17

私は現在、単純な Python 日時を返すカレンダー システムのバックエンドに取り組んでいます。フロントエンドが機能する方法は、ユーザーがさまざまなカレンダー イベントを作成し、フロントエンドが作成したイベントのナイーブ バージョンを返すことです (たとえば、ユーザーが 2020 年 10 月 5 日の午後 3:00 から午後 4:00 までを選択した場合、フロントエンドは次を返します)。datetime.datetime(2020, 10, 5, 15, 0, 0)始まりdatetime.datetime(2011, 10, 5, 16, 0, 0)として、そして終わりとして。

私がする必要があるのは、単純な日時を取得し、データベースに格納するために UTC に変換することです。システムの各ユーザーはすでにタイムゾーン設定を指定しているため、単純な datetime はタイムゾーン設定と同じタイムゾーンであると見なされます。ユーザーがタイムゾーンを変更した場合でも、既存のイベントがスケジュールした正しい時刻にレンダリングされるように、日時は UTC を基準にして格納する必要があることは明らかです。

フロントエンドは私の管理外にあるため、受信しているデータを変更することはできません。データベースの設計も私の手に負えないので、どのデータをどのように保存するかを変更することはできません。

これまでに私が取ったおおよそのアプローチは次のとおりです。

import pytz
def convert_to_UTC(naive_datetime, user_tz_preference):
    user_datetime = naive_datetime.replace(tzinfo=user_tz_preference)
    utc_datetime = user_datetime.astimezone(pytz.utc)

私が遭遇した問題は、夏時間に関連しています。

>>> from datetime import datetime
>>> import pytz
>>> user_tz_preference = pytz.timezone('US/Pacific')
>>> naive_datetime = datetime(2011, 10, 26, 12, 0, 0)
>>> user_datetime = naive_datetime.replace(tzinfo=user_tz_preference)
>>> user_datetime
datetime.datetime(2011, 10, 26, 12, 0, tzinfo=<DstTzInfo 'US/Pacific' PST-1 day, 16:00:00 STD>)
>>> received_utc = user_datetime.astimezone(pytz.utc)
>>> received_utc
datetime.datetime(2011, 10, 26, 20, 0, tzinfo=<UTC>)
>>> expected_utc = datetime(2011, 10, 26, 19, 0, tzinfo=pytz.utc)
>>> expected_utc == received_utc
False

「replace」を使用すると、日付に関係なく、タイムゾーンが PDT ではなく PST に設定されることに注意してください。これにより、予想される 7 時間の DST オフセットではなく 8 時間の UTC オフセットが与えられるため、時間が正しく保存されなくなります。

ナイーブな日時を正しい PDT (または他のタイムゾーン相対 DST) tzinfo に変換するためにどのようなオプションがありますか?

(また、すべてのユーザーが DST を観察するタイムゾーンに住んでいるわけではないことに注意してください。または、異なる時間に切り替わるタイムゾーンに住んでいる可能性があるため、保存する前にタイムデルタ補正のような解決策を実行するには、タイムゾーンは DST をサポートし、どの日付に切り替わるか)。

4

2 に答える 2

23

Pytzのlocalize関数はこれを行うことができます:http://pytz.sourceforge.net/#localized-times-and-date-arithmetic

from datetime import datetime
import pytz    

tz = pytz.timezone('US/Pacific')
naive_dt = datetime(2020, 10, 5, 15, 0, 0) 
utc_dt = tz.localize(naive_dt, is_dst=None).astimezone(pytz.utc)
# -> 2020-10-05 22:00:00+00:00
于 2011-11-02T20:21:25.123 に答える