システムのタイムゾーン設定を取得してpytz.timezoneに渡す方法は?
time.tzname
を使用してローカルタイムゾーン名を取得できますが、その名前はpytz.timezone
と互換性がありません。
実際、time.tzname
によって返される名前はあいまいです。このメソッドはシステムで('CST', 'CST')
を返しますが、「CST」は4つのタイムゾーンを示すことができます。
- 中央タイムゾーン(北米)-北米の中央タイムゾーンで観測
- 中国標準時
- 中原標準時-「中原標準時」という用語は現在台湾ではほとんど使用されていません
- オーストラリア中部標準時(ACST)
この問題を解決するための非常に簡単な方法:
import time
def localTzname():
offsetHour = time.timezone / 3600
return 'Etc/GMT%+d' % offsetHour
更新:@MartijnPietersは、「これはDST /サマータイムでは機能しません」と述べました。では、このバージョンはどうですか?
import time
def localTzname():
if time.daylight:
offsetHour = time.altzone / 3600
else:
offsetHour = time.timezone / 3600
return 'Etc/GMT%+d' % offsetHour
tzlocal
module は、ローカルタイムゾーンに対応するpytz tzinfoのオブジェクトを返します。
_import time
from datetime import datetime
import pytz # $ pip install pytz
from tzlocal import get_localzone # $ pip install tzlocal
# get local timezone
local_tz = get_localzone()
# test it
# utc_now, now = datetime.utcnow(), datetime.now()
ts = time.time()
utc_now, now = datetime.utcfromtimestamp(ts), datetime.fromtimestamp(ts)
local_now = utc_now.replace(tzinfo=pytz.utc).astimezone(local_tz) # utc -> local
assert local_now.replace(tzinfo=None) == now
_
現地時間が曖昧な夏時間への移行中でも機能します。
_local_tz
_は、ローカルタイムゾーンのutcオフセットがその時点で異なっていた場合でも、過去の日付でも機能します。この場合、dateutil.tz.tzlocal()
ベースのソリューションは失敗します。たとえば、ヨーロッパ/モスクワのタイムゾーン(2013年の例):
_>>> import os, time
>>> os.environ['TZ'] = 'Europe/Moscow'
>>> time.tzset()
>>> from datetime import datetime
>>> from dateutil.tz import tzlocal
>>> from tzlocal import get_localzone
>>> dateutil_tz = tzlocal()
>>> tzlocal_tz = get_localzone()
>>> datetime.fromtimestamp(0, dateutil_tz)
datetime.datetime(1970, 1, 1, 4, 0, tzinfo=tzlocal())
>>> datetime.fromtimestamp(0, tzlocal_tz)
datetime.datetime(1970, 1, 1, 3, 0, tzinfo=<DstTzInfo 'Europe/Moscow' MSK+3:00:00 STD>)
_
dateutilは、1970-01-01の正しいUTC + 3の代わりにwrongUTC + 4オフセットを返します。
2017年にこれにぶつかった人のためにdateutil.tz.tzlocal()
はまだ壊れています。モスクワでは現在のutfオフセットがUTC + 3であるため、上記の例は機能します(偶然、1970年からのutcオフセットに等しい)。エラーを示すために、UTCオフセットがUTC + 4である日付を選択できます。
_>>> import os, time
>>> os.environ['TZ'] = 'Europe/Moscow'
>>> time.tzset()
>>> from datetime import datetime
>>> from dateutil.tz import tzlocal
>>> from tzlocal import get_localzone
>>> dateutil_tz = tzlocal()
>>> tzlocal_tz = get_localzone()
>>> ts = datetime(2014, 6,1).timestamp() # get date in 2014 when gmtoff=14400 in Moscow
>>> datetime.fromtimestamp(ts, dateutil_tz)
datetime.datetime(2014, 5, 31, 23, 0, tzinfo=tzlocal())
>>> datetime.fromtimestamp(ts, tzlocal_tz)
datetime.datetime(2014, 6, 1, 0, 0, tzinfo=<DstTzInfo 'Europe/Moscow' MSK+4:00:00 STD>)
_
dateutilは、2014-06-01の正しいUTC + 4ではなく、wrongUTC + 3オフセットを返します。
python-dateutil
パッケージ から tzlocal
関数 を使用します。
from dateutil.tz import tzlocal
localtimezone = tzlocal()
内部的には、これはtime.timezone
およびtime.altzone
(time.daylight
に基づく切り替え)を使用するクラスですが、そこから適切なタイムゾーンオブジェクトを作成します。
pytz
タイムゾーンの代わりにこれを使用します。
代わりに、現在構成されているタイムゾーンをオペレーティングシステムから読み取ることもできますが、これはOSによって大きく異なります。 Mac OS Xでは、systemsetup -gettimezone
の出力を読み取る必要があります。
$ systemsetup -gettimezone
Time Zone: Europe/Copenhagen
DebianおよびUbuntuシステムでは、/etc/timezone
を読むことができます:
$ cat /etc/timezone
Europe/Oslo
RedHatおよび改良されたシステムでは、/etc/sysconfig/clock
から読み取る必要があります。
$ grep ZONE /etc/sysconfig/clock
ZONE="Europe/Oslo"
Python 3.6)なので、naive_datetime.astimezone()
を実行するだけで、naive_datetime
オブジェクトにシステムタイムゾーンが追加されます。
引数なしで(またはtz = Noneで)呼び出された場合、システムのローカルタイムゾーンがターゲットタイムゾーンとして想定されます。変換された日時インスタンスの.tzinfo属性は、OSから取得したゾーン名とオフセットを持つタイムゾーンのインスタンスに設定されます。
https://docs.python.org/3/library/datetime.html#datetime.datetime.astimezone
例:
>>> import datetime
>>> datetime.datetime.now().astimezone().isoformat(timespec='minutes')
'2018-10-02T13:09+03:00'
これがあなたに役立つかどうかはわかりませんが、あなたのより一般的な問題に答えると思います:
CST
のようなあいまいなタイムゾーンにある日付がある場合、 simple-date (python 3.2+のみ、申し訳ありませんが)検索を自動化でき、次のようなことができます特定の国を好む。
例えば:
>>> SimpleDate('2013-07-04 18:53 CST')
Traceback [...
simpledate.AmbiguousTimezone: 3 distinct timezones found: <DstTzInfo 'Australia/Broken_Hill' CST+9:30:00 STD>; <DstTzInfo 'America/Regina' LMT-1 day, 17:01:00 STD>; <DstTzInfo 'Asia/Harbin' LMT+8:27:00 STD> (timezones=('CST',), datetime=datetime.datetime(2013, 7, 4, 18, 53), is_dst=False, country=None, unsafe=False)
>>> SimpleDate('2013-07-04 18:53 CST', country='CN')
SimpleDate('2013-07-04 18:53 CST')
>>> SimpleDate('2013-07-04 18:53 CST', country='CN').utc
SimpleDate('2013-07-04 10:53 UTC', tz='UTC')
国を指定することにより、UTCへの変換を可能にするために可能な値の範囲を十分に小さくする方法に注意してください。
pyTZのタイムゾーンで検索を実行することで実装されます:
>>> SimpleDate('2013-07-04 18:53 CST', country='CN', debug=True)
...
PyTzFactory: Have country code CN
PyTzFactory: Country code CN has 5 timezones
PyTzFactory: Expanded country codes to 5 timezones
PyTzFactory: Expanding ('CST',)
PyTzFactory: Name lookup failed for CST
PyTzFactory: Found CST using Asia/Shanghai
PyTzFactory: Found CST using Asia/Harbin
PyTzFactory: Found CST using Asia/Chongqing
PyTzFactory: Found CST using Asia/Urumqi
PyTzFactory: Found CST using Asia/Kashgar
PyTzFactory: Expanded timezone to 5 timezones
PyTzFactory: New offset 8:00:00 for Asia/Shanghai
PyTzFactory: Known offset 8:00:00 for Asia/Harbin
PyTzFactory: Known offset 8:00:00 for Asia/Chongqing
PyTzFactory: Known offset 8:00:00 for Asia/Urumqi
PyTzFactory: Known offset 8:00:00 for Asia/Kashgar
PyTzFactory: Have 1 distinct timezone(s)
PyTzFactory: Found Asia/Shanghai
...
SimpleDate('2013-07-04 18:53 CST')
最後に、直接尋ねられた質問に答えるために、ここで別の答えで述べたように、tzlocalもラップします。したがって、タイムゾーンを指定しない場合は、期待どおりに自動的に実行されます。たとえば、私はチリに住んでいるので、
>>> SimpleDate()
SimpleDate('2013-07-04 19:21:25.757222 CLT', tz='America/Santiago')
>>> SimpleDate().tzinfo
<DstTzInfo 'America/Santiago' CLT-1 day, 20:00:00 STD>
ロケールのタイムゾーンを提供します(あいまいかどうか)。