676

私は何をする必要がありますか

タイムゾーンを認識しない datetime オブジェクトがあり、他のタイムゾーンを認識する datetime オブジェクトと比較できるようにするために、タイムゾーンを追加する必要があります。この1つのレガシーケースを認識しないタイムゾーンにアプリケーション全体を変換したくありません。

私が試したこと

まず、問題を示すために:

Python 2.6.1 (r261:67515, Jun 24 2010, 21:47:49) 
[GCC 4.2.1 (Apple Inc. build 5646)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import datetime
>>> import pytz
>>> unaware = datetime.datetime(2011,8,15,8,15,12,0)
>>> unaware
datetime.datetime(2011, 8, 15, 8, 15, 12)
>>> aware = datetime.datetime(2011,8,15,8,15,12,0,pytz.UTC)
>>> aware
datetime.datetime(2011, 8, 15, 8, 15, 12, tzinfo=<UTC>)
>>> aware == unaware
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can't compare offset-naive and offset-aware datetimes

まず、私は astimezone を試しました:

>>> unaware.astimezone(pytz.UTC)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: astimezone() cannot be applied to a naive datetime
>>>

実際に変換を行おうとしているので、これが失敗したことはそれほど驚くべきことではありません。置換はより良い選択のように思えました ( How do I get a value of datetime.today() in Python that is "timezone aware"?に従って):

>>> unaware.replace(tzinfo=pytz.UTC)
datetime.datetime(2011, 8, 15, 8, 15, 12, tzinfo=<UTC>)
>>> unaware == aware
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can't compare offset-naive and offset-aware datetimes
>>> 

しかし、ご覧のとおり、replace は tzinfo を設定しているように見えますが、オブジェクトを認識させていません。解析する前に入力文字列を改ざんしてタイムゾーンを取得する準備をしています (解析に dateutil を使用していますが、それが重要な場合)。

また、Python 2.6 と Python 2.7 の両方でこれを試しましたが、同じ結果が得られました。

環境

いくつかのデータ ファイルのパーサーを作成しています。日付文字列にタイムゾーン インジケーターがない場合、サポートする必要がある古い形式があります。データ ソースは既に修正済みですが、従来のデータ形式をサポートする必要があります。さまざまなビジネス BS の理由から、レガシー データの 1 回限りの変換はオプションではありません。一般に、デフォルトのタイムゾーンをハードコーディングするという考えは好きではありませんが、この場合はそれが最良の選択肢のようです。問題のすべてのレガシー データが UTC であることはかなりの自信を持って知っているので、この場合、それをデフォルトにするリスクを受け入れる準備ができています。

4

15 に答える 15

756

一般に、ナイーブな日時をタイムゾーン対応にするには、localize メソッドを使用します。

import datetime
import pytz

unaware = datetime.datetime(2011, 8, 15, 8, 15, 12, 0)
aware = datetime.datetime(2011, 8, 15, 8, 15, 12, 0, pytz.UTC)

now_aware = pytz.utc.localize(unaware)
assert aware == now_aware

localizeUTC タイムゾーンの場合、処理する夏時間の計算がないため、実際には使用する必要はありません。

now_aware = unaware.replace(tzinfo=pytz.UTC)

動作します。(.replace新しい日時を返します。変更しませんunaware。)

于 2011-08-15T13:03:52.747 に答える
288

これらの例はすべて外部モジュールを使用していますが、この SO answerにも示されているように、datetime モジュールだけを使用して同じ結果を得ることができます。

from datetime import datetime, timezone

dt = datetime.now()
dt = dt.replace(tzinfo=timezone.utc)

print(dt.isoformat())
# '2017-01-12T22:11:31+00:00'

依存関係が少なく、pytz の問題はありません。

注: これを python3 および python2 で使用する場合は、タイムゾーンのインポートにも使用できます (UTC 用にハードコードされています)。

try:
    from datetime import timezone
    utc = timezone.utc
except ImportError:
    #Hi there python2 user
    class UTC(tzinfo):
        def utcoffset(self, dt):
            return timedelta(0)
        def tzname(self, dt):
            return "UTC"
        def dst(self, dt):
            return timedelta(0)
    utc = UTC()
于 2017-01-12T22:30:23.367 に答える
48

Django で次のステートメントを使用して、非認識時間を認識に変換します。

from django.utils import timezone

dt_aware = timezone.make_aware(dt_unaware, timezone.get_current_timezone())
于 2015-01-27T15:21:38.703 に答える
0

タイムゾーンの変更

import pytz
from datetime import datetime

other_tz = pytz.timezone('Europe/Madrid')

# From random aware datetime...
aware_datetime = datetime.utcnow().astimezone(other_tz)
>> 2020-05-21 08:28:26.984948+02:00

# 1. Change aware datetime to UTC and remove tzinfo to obtain an unaware datetime
unaware_datetime = aware_datetime.astimezone(pytz.UTC).replace(tzinfo=None)
>> 2020-05-21 06:28:26.984948

# 2. Set tzinfo to UTC directly on an unaware datetime to obtain an utc aware datetime
aware_datetime_utc = unaware_datetime.replace(tzinfo=pytz.UTC)
>> 2020-05-21 06:28:26.984948+00:00

# 3. Convert the aware utc datetime into another timezone
reconverted_aware_datetime = aware_datetime_utc.astimezone(other_tz)
>> 2020-05-21 08:28:26.984948+02:00

# Initial Aware Datetime and Reconverted Aware Datetime are equal
print(aware_datetime1 == aware_datetime2)
>> True
于 2020-05-21T08:32:46.873 に答える
0

unutbuの回答の形式で。より直感的な構文で、このようなことを処理するユーティリティ モジュールを作成しました。pipでインストールできます。

import datetime
import saturn

unaware = datetime.datetime(2011, 8, 15, 8, 15, 12, 0)
now_aware = saturn.fix_naive(unaware)

now_aware_madrid = saturn.fix_naive(unaware, 'Europe/Madrid')
于 2016-09-25T23:31:51.543 に答える