web-dev-qa-db-ja.com

pytzローカライズvs日時置換

Pytzの.localize()関数でいくつかの奇妙な問題が発生しています。時々、ローカライズされた日時を調整しません:

.localize動作:

>>> tz
<DstTzInfo 'Africa/Abidjan' LMT-1 day, 23:44:00 STD> 
>>> d
datetime.datetime(2009, 9, 2, 14, 45, 42, 91421)

>>> tz.localize(d)
datetime.datetime(2009, 9, 2, 14, 45, 42, 91421, 
                  tzinfo=<DstTzInfo 'Africa/Abidjan' GMT0:00:00 STD>)
>>> tz.normalize(tz.localize(d))
datetime.datetime(2009, 9, 2, 14, 45, 42, 91421,
                  tzinfo=<DstTzInfo 'Africa/Abidjan' GMT0:00:00 STD>)

ご覧のとおり、ローカライズ/正規化操作の結果として時間は変更されていません。ただし、.replaceを使用する場合:

>>> d.replace(tzinfo=tz)
datetime.datetime(2009, 9, 2, 14, 45, 42, 91421, 
                  tzinfo=<DstTzInfo 'Africa/Abidjan' LMT-1 day, 23:44:00 STD>)
>>> tz.normalize(d.replace(tzinfo=tz))
datetime.datetime(2009, 9, 2, 15, 1, 42, 91421,
                  tzinfo=<DstTzInfo 'Africa/Abidjan' GMT0:00:00 STD>)

これは日時を調整するようです。

質問は-どちらが正しいのですか、なぜ他の人が間違っているのですか?

43
Art

localizeは、渡された単純な日時が「正しい」(タイムゾーンを知らない場合を除いて!).

ローカライズされた方法で日付時刻のI/Oを実行する必要がある場合(replaceがDSTなどを処理します)、normalizeを使用して(そして推奨)...

36
Alex Martelli

localizeは、初期の固定日時値を持つ日時対応オブジェクトを作成するために使用する正しい関数です。結果の日時対応オブジェクトには、元の日時値が含まれます。私の見解では非常に一般的な使用パターンであり、おそらくpytzでより適切に文書化できるものです。

replace(tzinfo = ...)は残念ながら名前が付けられています。これは、動作がランダムな関数です。自分の苦痛を味わわない限り、タイムゾーンを設定するためにこの関数を使用しないことをお勧めします。私はすでにこの機能を使うのに十分苦しんでいます。

11
paolov

私はこれに少し遅れていることに気づきました...しかし、これは私がうまくいくことがわかったものです。アレックスが述べたようにUTCで働く:

tz = pytz.timezone('Africa/Abidjan')
now = datetime.datetime.utcnow()

次にローカライズするには:

tzoffset = tz.utcoffset(now)
mynow = now+tzoffset

そして、この方法はDSTを完全に処理します

7
derks

このDstTzInfoクラスは、特定の時点でUTCからのオフセットが変化するタイムゾーンに使用されます。たとえば(おそらくご存じのように)、多くの場所は夏の初めに「夏時間」に移行し、夏の終わりに「標準時間」に戻ります。各DstTzInfoインスタンスはこれらのタイムゾーンの1つのみを表しますが、「localize」および「normalize」メソッドは正しいインスタンスを取得するのに役立ちます。

アビジャンの場合、(pytzによると)移行は1回しかありませんでした。1912年のことです。

>>> tz = pytz.timezone('Africa/Abidjan')
>>> tz._utc_transition_times
[datetime.datetime(1, 1, 1, 0, 0), datetime.datetime(1912, 1, 1, 0, 16, 8)]

Pytzから取得するtzオブジェクトは、1912年より前のタイムゾーンを表します。

>>> tz
<DstTzInfo 'Africa/Abidjan' LMT-1 day, 23:44:00 STD>

次に、2つの例を調べて、tz.localize(d)を呼び出すときに次のことを実行することを確認します[〜#〜] not [〜#〜]この1912年以前のタイムゾーンを単純な日時に追加しますオブジェクト。指定したdatetimeオブジェクトが現地時間を表すと想定していますその現地時間の正しいタイムゾーンで、これは1912年以降のタイムゾーンです。

ただし、d.replace(tzinfo = tz)を使用する2番目の例では、datetimeオブジェクトを使用して、1912より前のタイムゾーンの時刻を表します。これはおそらくあなたが意図したものではありません。次に、dt.normalizeを呼び出すと、これは、その日時値(1912以降のタイムゾーン)に適したタイムゾーンに変換されます。

4
lplatypus