めちゃくちゃ初歩的なミスを犯すところだったので戒めにメモしておきます。。。
背景
Twitter APIを用いて構築しているTwitterクローラで、デフォルト設定である1週間単位でツイートデータを収集していたが、1週間丸ごと取りに行くとデータ量的にクロールにかかる時間が長くなってしまう為、クロールしてくる期間を変更したい。
しかし、Standard Search APIには取得開始日時から特定の日時までのデータに絞るパラメータが存在していない為、APIの返り値から日付情報を抽出して比較する必要がある。
(厳密には、since_idはあるけど仕様が謎で使いづらい・・・)
問題
以下のように、django.utils.timezone
を用いてJSTで対象期間を定義し、APIの返り値をJSTに変換して比較しようとしていた。
import datetime
from django.utils import timezone
target_datetime = timezone.localtime(timezone.now()) - datetime.timedelta(days=4)
created_at = "Thu Oct 03 15:28:43 +0000 2019" #APIから抽出した日付文字列
created_at_datetime = timezone.make_aware(datetime.datetime.strptime(created_at, '%a %b %d %H:%M:%S +0000 %Y'), timezone.get_default_timezone())
if created_at_datetime > target_datetime:
以下省略
しかし、このやり方だと以下のように「UTC」の日時が「JST」に変換されないまま、「JST」のタイムゾーン情報だけが付与された形になっていた。
>>> created_at = "Thu Oct 03 15:28:43 +0000 2019"
>>> created_at_datetime = timezone.make_aware(datetime.datetime.strptime(created_at, '%a %b %d %H:%M:%S +0000 %Y'), timezone.get_default_timezone())
datetime.datetime(2019, 10, 3, 15, 28, 43, tzinfo=<DstTzInfo 'Asia/Tokyo' JST+9:00:00 STD>)
解決方法
UTC文字列をJSTのdatetimeに変換するには以下の手順を踏む必要がある。
>>> created_at = "Thu Oct 03 15:28:43 +0000 2019"
>>> created_at_datetime_utc = datetime.datetime.strptime(created_at, '%a %b %d %H:%M:%S %z %Y')
>>> timezone.localtime(created_at_datetime_utc)
datetime.datetime(2019, 10, 4, 0, 28, 43, tzinfo=<DstTzInfo 'Asia/Tokyo' JST+9:00:00 STD>)
なお、datetime同士の比較を行うだけの目的であればわざわざ変換しなくてもよしなに計算してくれる模様。
>>> created_at_datetime
datetime.datetime(2019, 9, 29, 20, 32, 44, tzinfo=datetime.timezone.utc)
>>> target_datetime
datetime.datetime(2019, 9, 29, 20, 32, 44, tzinfo=<DstTzInfo 'Asia/Tokyo' JST+9:00:00 STD>)
>>> created_at_datetime > target_datetime
True
>>> created_at_datetime
datetime.datetime(2019, 9, 29, 12, 32, 44, tzinfo=datetime.timezone.utc)
>>> target_datetime
datetime.datetime(2019, 9, 29, 20, 32, 44, tzinfo=<DstTzInfo 'Asia/Tokyo' JST+9:00:00 STD>)
>>> created_at_datetime > target_datetime
True
>>> created_at_datetime
datetime.datetime(2019, 9, 29, 10, 32, 44, tzinfo=datetime.timezone.utc)
>>> target_datetime
datetime.datetime(2019, 9, 29, 20, 32, 44, tzinfo=<DstTzInfo 'Asia/Tokyo' JST+9:00:00 STD>)
>>> created_at_datetime > target_datetime
False