web-dev-qa-db-ja.com

Pythonローカルタイムゾーンを使用して正しいタイムゾーンオフセットを取得する

まず、タイムゾーンがCET/CESTであると言うことから始めましょう。 CESTからCET(GMT + 2であるDSTからGMT + 1である通常の状態に戻る)に変わる正確な瞬間は、常に10月の最終日曜日の午前3時です。 2010年、これは10月31日午前3時でした。

次のことに注意してください。

>>> import datetime
>>> import pytz.reference
>>> local_tnz = pytz.reference.LocalTimezone()
>>> local_tnz.utcoffset(datetime.datetime(2010, 10, 31, 2, 12, 30))
datetime.timedelta(0, 3600)

上記で説明したように、これは間違っています。

>>> local_tnz.utcoffset(datetime.datetime(2010, 10, 30, 2, 12, 30))
datetime.timedelta(0, 7200)
>>> local_tnz.utcoffset(datetime.datetime(2010, 10, 31, 2, 12, 30))
datetime.timedelta(0, 7200)

今、それは突然正しいです:/

これについていくつかの質問があることは知っていますが、与えられた解決策は常に「ローカライズを使用する」ことですが、ここでの私の問題は、LocalTimezoneがそのメソッドを提供しないことです。

実際、ミリ秒単位のタイムスタンプがいくつかあり、その中にローカルタイムゾーン(私のものだけでなく、プログラムを使用するすべての人)のutcoffsetが必要です。これらの1つは、1288483950000または2010年10月31日02:12:30 GMT + 0200(CEST)のタイムゾーンです。

現在、datetimeオブジェクトを取得するために以下を実行しています。

datetime.datetime.fromtimestamp(int(int(millis)/1E3)) 

これにより、utcoffsetを数分で取得できます。

-int(local_tnz.utcoffset(date).total_seconds()/60)

残念ながら、これは多くの場合間違っています:(。

何か案は?

注:私はpython3.2.4を使用していますが、この場合は問題ではありません。

編集:

@JamesHoldernessのおかげで解決策を見つけました。

def datetimeFromMillis(millis):
    return pytz.utc.localize(datetime.datetime.utcfromtimestamp(int(int(millis)/1E3)))

def getTimezoneOffset(date):
    return -int(date.astimezone(local_tz).utcoffset().total_seconds()/60)

Local_tzがtzlocalモジュールのtzlocal.get_localzone()に等しい場合。

18

Wikipedia によると、夏時間への移行と夏時間からの移行はUTC 01:00に発生します。

  • UTC 00:12では、まだ中央ヨーロッパ夏時間(つまりUTC + 02:00)であるため、現地時間は02:12です。

  • UTCの01:12に標準の中央ヨーロッパ時間(UTC + 01:00)に戻るため、現地時間は再び02:12になります。

夏時間から標準時間に戻すと、現地時間は02:59から02:00に戻り、時間が繰り返されます。したがって、UTCオフセット02:12(現地時間)を要求する場合、答えは+01:00または+02:00のいずれかである可能性があります。これは、話している02:12のバージョンによって異なります。

Pytzライブラリをさらに調査すると、pytz.referenceの実装を使用してはならないという問題があるかもしれませんが、これらの曖昧さをうまく処理できない可能性があります。ソースコードのコメントから引用:

Python docs。からのtzinfo実装を参照してください。1987〜2006年の間のみ正しいので、テストに使用します。これらを実際のコードに使用しないでください。

pytzで曖昧な時間を扱う

あなたがすべきことは、適切なタイムゾーンのtimezoneオブジェクトを構築することです:

import pytz
cet = pytz.timezone('CET')

次に、utcoffsetメソッドを使用して、そのタイムゾーンの日付/時刻のUTCオフセットを計算できます。

dt = datetime.datetime(2010, 10, 31, 2, 12, 30)
offset = cet.utcoffset(dt)

上記の例では、2つのバージョンの02:12:30のどちらを意図しているかわからないため、AmbiguousTimeError例外がスローされることに注意してください。幸いなことに、pytzでは、is_dstパラメーターを設定することにより、dstバージョンと標準バージョンのどちらを使用するかを指定できます。例えば:

offset = cet.utcoffset(dt, is_dst = True)

時間が曖昧でなくても、utcoffsetへのすべての呼び出しでこのパラメーターを設定しても害はないことに注意してください。文書によると、DST移行のあいまいな期間にのみ使用され、そのあいまいさを解決します。

タイムスタンプの扱い方

タイムスタンプの処理に関しては、可能な限りUTC値として保存するのが最善です。そうしないと、貴重な情報を破棄してしまう可能性があります。したがって、最初にdatetime.utcfromtimestampメソッドを使用してUTC日時に変換します。

dt = datetime.datetime.utcfromtimestamp(1288483950)

次に、pytzを使用して時刻をUTCとしてローカライズします。これにより、タイムゾーンがdatetimeオブジェクトに付加されます。

dt = pytz.utc.localize(dt)

最後に、そのUTC日時をローカルタイムゾーンに変換し、次のようにタイムゾーンオフセットを取得できます。

offset = dt.astimezone(cet).utcoffset()

この計算セットは、両方のタイムスタンプがCETタイムゾーンの02:12:30で表されている場合でも、1288483950と1288487550の両方に対して正しいオフセットを生成することに注意してください。

ローカルタイムゾーンの決定

固定のタイムゾーンではなく、コンピューターのローカルタイムゾーンを使用する必要がある場合、pytzから直接使用することはできません。また、time.tznameからのタイムゾーン名を使用してpytz.timezoneオブジェクトを作成することもできません。 tは常にpytzによって認識されます。

解決策は、 tzlocalモジュール を使用することです。その唯一の目的は、この欠落した機能をpytzで提供することです。次のように使用します。

import tzlocal
local_tz = tzlocal.get_localzone()

get_localzone()関数はpytz.timezoneオブジェクトを返すため、すべての場所でその値を使用できるはずです上記の例ではcet変数を使用しました。

26

タイムスタンプをミリ秒単位で指定すると、stdlibのみを使用してローカルタイムゾーンのutcオフセットを取得できます。

_#!/usr/bin/env python
from datetime import datetime

millis = 1288483950000
ts = millis * 1e-3
# local time == (utc time + utc offset)
utc_offset = datetime.fromtimestamp(ts) - datetime.utcfromtimestamp(ts)
_

うるう秒前後の時間を無視すると、あいまいさや存在しない時間はありません。

OSが過去のタイムゾーンdbを維持している場合、他の理由でDSTとutcオフセットの変更をサポートします。たとえば、Ubuntuでは過去/現在の日付で動作するはずですが、異なるutcオフセットを使用した過去の日付ではWindowsで破損する可能性があります。

* nixおよびWin32システムで動作する tzlocal モジュールを使用した場合も同じです。

_#!/usr/bin/env python
from datetime import datetime
from tzlocal import get_localzone # pip install tzlocal

millis = 1288483950000
ts = millis * 1e-3
local_dt = datetime.fromtimestamp(ts, get_localzone())
utc_offset = local_dt.utcoffset()
_

参照してください python utc datetimeをpython標準ライブラリのみを使用してローカルdatetimeに変換する方法?

Utcオフセットを数分で取得するには(Python 3.2以降):

_from datetime import timedelta

minutes = utc_offset / timedelta(minutes=1)
_

pytz.reference.LocalTimezone()を使用しないでください 。これはテスト専用です

9
jfs