Мы можем использовать time.tzname
имя локального часового пояса, но это имя несовместимо с pytz.timezone
.
Фактически, имя, возвращаемое time.tzname
, неоднозначно. Этот метод возвращает ('CST', 'CST')
в моей системе, но "CST" может указывать четыре часовых пояса:
- Центральный часовой пояс (Северная Америка) - наблюдается в Центральном часовом поясе Северной Америки.
- Стандартное время в Китае
- Стандартное время Chungyuan - термин "стандартное время Chungyuan" теперь редко используется на Тайване.
- Центральное стандартное время Австралии (ACST)
Ответ 1
Очень простой способ решить этот вопрос:
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
Ответ 2
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 offset для локального часового пояса в то время было другим. Решение на основе 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 возвращает неправильный UTC + 4 смещение вместо правильного UTC + 3 в 1970-01-01.
Для тех, кто сталкивается с этим в 2017 году, dateutil.tz.tzlocal()
все еще сломан. Вышеприведенный пример работает сейчас, потому что текущее смещение utf - это UTC + 3 в Москве (что случайно соответствует смещению utc с 1970 года). Чтобы продемонстрировать ошибку, мы можем выбрать дату, когда utc offset - 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 возвращает неправильный UTC + 3 вместо правильного UTC + 4 на 2014-06-01.
Ответ 3
Используйте tzlocal
функцию из пакета python-dateutil
:
from dateutil.tz import tzlocal
localtimezone = tzlocal()
Внутри это класс, который использует time.timezone
и time.altzone
(переключение на основе time.daylight
), но создает из него подходящий объект часового пояса.
Вы используете это вместо часового пояса pytz
.
Альтернативой является чтение текущего настроенного часового пояса из операционной системы, но это сильно отличается от ОС к ОС. В 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"
Ответ 4
Я не знаю, полезно ли это для вас или нет, но я думаю, что он отвечает на вашу более общую проблему:
если у вас есть дата, которая находится в неоднозначном часовом поясе, например 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>
дает мой часовой пояс локали (неоднозначный или нет).