64

私が今思いつくことができる最高のものは、この怪物です:

>>> datetime.utcnow() \
...   .replace(tzinfo=pytz.UTC) \
...   .astimezone(pytz.timezone("Australia/Melbourne")) \
...   .replace(hour=0,minute=0,second=0,microsecond=0) \
...   .astimezone(pytz.UTC) \
...   .replace(tzinfo=None)
datetime.datetime(2008, 12, 16, 13, 0)

つまり、英語では、現在の時刻 (UTC) を取得し、それを他のタイムゾーンに変換し、時刻を午前 0 時に設定してから、UTC に戻します。

ユーザーのタイムゾーンではなくサーバーのタイムゾーンを使用するため、 now() または localtime() を使用しているだけではありません。

私は何かが欠けていると感じずにはいられません。何かアイデアはありますか?

4

6 に答える 6

100

次のようにすれば、いくつかのメソッド呼び出しを削減できると思います。

>>> from datetime import datetime
>>> datetime.now(pytz.timezone("Australia/Melbourne")) \
            .replace(hour=0, minute=0, second=0, microsecond=0) \
            .astimezone(pytz.utc)

しかし...コードには美学よりも大きな問題があります。夏時間への切り替えまたは夏時間からの切り替えの日に間違った結果が得られます。

これは、datetime コンストラクターもreplace()DST の変更も考慮していないためです。

例えば:

>>> now = datetime(2012, 4, 1, 5, 0, 0, 0, tzinfo=pytz.timezone("Australia/Melbourne"))
>>> print now
2012-04-01 05:00:00+10:00
>>> print now.replace(hour=0)
2012-04-01 00:00:00+10:00 # wrong! midnight was at 2012-04-01 00:00:00+11:00
>>> print datetime(2012, 3, 1, 0, 0, 0, 0, tzinfo=tz)
2012-03-01 00:00:00+10:00 # wrong again!

ただし、tz.localize()状態のドキュメント:

日時コンストラクターに tzinfo 引数を渡すのではなく、このメソッドを使用してローカルタイムを構築する必要があります。

したがって、問題は次のように解決されます。

>>> import pytz
>>> from datetime import datetime, date, time

>>> tz = pytz.timezone("Australia/Melbourne")
>>> the_date = date(2012, 4, 1) # use date.today() here

>>> midnight_without_tzinfo = datetime.combine(the_date, time())
>>> print midnight_without_tzinfo
2012-04-01 00:00:00

>>> midnight_with_tzinfo = tz.localize(midnight_without_tzinfo)
>>> print midnight_with_tzinfo
2012-04-01 00:00:00+11:00

>>> print midnight_with_tzinfo.astimezone(pytz.utc)
2012-03-31 13:00:00+00:00

ただし、1582 年より前の日付の保証はありません。

于 2008-12-19T18:29:13.297 に答える
32

2012 年 4 月 1 日など、夏時間 (DST) からの移行日に@hop の回答tz.localize()が間違っています。修正するには、次のコマンドを使用できます。

tz = pytz.timezone("Australia/Melbourne")
today = datetime.now(tz).date()
midnight = tz.localize(datetime.combine(today, time(0, 0)), is_dst=None)
utc_dt = midnight.astimezone(pytz.utc)        

コメントと同じ:

#!/usr/bin/env python
from datetime import datetime, time
import pytz # pip instal pytz

tz = pytz.timezone("Australia/Melbourne") # choose timezone

# 1. get correct date for the midnight using given timezone.
today = datetime.now(tz).date()

# 2. get midnight in the correct timezone (taking into account DST)
#NOTE: tzinfo=None and tz.localize()
# assert that there is no dst transition at midnight (`is_dst=None`)
midnight = tz.localize(datetime.combine(today, time(0, 0)), is_dst=None)

# 3. convert to UTC (no need to call `utc.normalize()` due to UTC has no 
#    DST transitions)
fmt = '%Y-%m-%d %H:%M:%S %Z%z'
print midnight.astimezone(pytz.utc).strftime(fmt)
于 2012-06-27T23:57:46.290 に答える