Ruby - ツイートIDからタイムスタンプ等の取得!
Updated:
Twitter のツイートIDは snowflake というツールを使って算出されています。
このツールのアルゴリズムを理解すれば、ツイートIDからツイートした日時が取得できます。
以下、そのアルゴリズムについての簡単な説明と、ツイート日時を算出する Ruby スクリプトの紹介です。
0. 前提条件
- Ruby 2.3.3-p222 での作業を想定。
- ツイートIDだけでなく、アカウントID(ユーザが変更可能な英数字の screen_name ではなく、ユーザが変更不可能な数字のみの羅列)も同様に取得できる模様。(但し、最近の18桁(64bit)のIDのみ)
1. ツイートIDについて
snowflake によると、ツイートIDは 63bit(long値 - 1bit)で表現されていて、以下のような構造になっている。
Tweet ID | Machine ID | Sequence |
---|---|---|
41 bit | 10 bit | 12 bit |
さらに、 timestamp の値は 1288834974657(ミリ秒)減算した値となっている。
2. Ruby スクリプトの作成
以下のように Ruby スクリプトを作成してみた。
各項目の値を取得するためにマスク処理を行っているが、タイムスタンプのみであれば、右シフトを行うだけでよい。(スクリプト内のコメント参照)
File: analyze_tweetid.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#! /usr/local/bin/ruby
# coding: utf-8
#=ツイートID解析
# : コマンドライン引数にツイートIDを渡して実行するとツイート日時等を算出する。
#
# date name version
# 2017.01.07 Masaru Koizumi 1.00 新規作成
#
# Copyright(C) 2017 mk-mode.com All Rights Reserved.
#---------------------------------------------------------------------------------
# 引数 : ツイートID(半角数字)
#---------------------------------------------------------------------------------
#++
class AnalyzeTweetid
TW_EPOCH = 1288834974657 # 単位:ミリ秒
MASK_T = "111111111111111111111111111111111111111110000000000000000000000"
MASK_M = "000000000000000000000000000000000000000001111111111000000000000"
MASK_S = "000000000000000000000000000000000000000000000000000111111111111"
def initialize(tweet_id)
@tweet_id = tweet_id.to_i
end
def exec
begin
# 各値のバイナリ文字列
timestamp_b = (@tweet_id & MASK_T.to_i(2)).to_s(2)
machine_id_b = (@tweet_id & MASK_M.to_i(2)).to_s(2)
sequence_b = (@tweet_id & MASK_S.to_i(2)).to_s(2)
# 各値の抽出&数値化
timestamp = ("%063d" % timestamp_b.to_i )[ 0,41].to_i(2)
machine_id = ("%063d" % machine_id_b.to_i)[41,10].to_i(2)
sequence = ("%063d" % sequence_b.to_i )[51,12].to_i(2)
# timestamp の算出
timestamp = Time.at((timestamp + TW_EPOCH) / 1000.0)
# 結果出力
puts " TWEET-ID: #{@tweet_id}"
puts "TIMESTAMP: #{timestamp.strftime("%Y-%m-%d %H:%M:%S.%L %Z")}"
puts " (MACHINE-ID: #{machine_id}, SEQUENCE: #{sequence})"
# timestamp のみなら、マスク処理をしなくとも、以下で充分
# timestamp = Time.at(((@tweet_id >> 22) + TW_EPOCH) / 1000.0)
# puts " TWEET-ID: #{@tweet_id}"
# puts "TIMESTAMP: #{timestamp.strftime("%Y-%m-%d %H:%M:%S.%L %Z")}"
rescue => e
$stderr.puts "[ERROR][#{self.class.name}.#{__method__}] #{e}"
e.backtrace.each { |tr| $stderr.puts "\t#{tr}"}
exit 1
end
end
end
if __FILE__ == $0
exit 0 unless tweet_id = ARGV.shift
AnalyzeTweetid.new(tweet_id).exec
end
3. Ruby スクリプトの実行
ツイートIDをコマンドライン引数に指定して実行する。
$ ./analyze_tweetid.rb 817350207100719104
TWEET-ID: 817350207100719104
TIMESTAMP: 2017-01-06 21:40:49.661 JST
(MACHINE-ID: 329, SEQUENCE: 0)
1000分の1秒単位で正確にツイート日時が取得できている。
参考サイト
※実際には、紹介されている Scala のコードを参考にしている。
単純にツイート日時を取得したいだけなら、 Twitter API を利用しなくてもよいので大変お手軽です。
以上。
Comments