2010-04-27 6 views
36

Я хочу сравнить временные метки UTC из файла журнала с локальными метками времени. При создании локального datetime объекта, я использую нечто вроде:Python: Рисунок локального часового пояса

>>> local_time=datetime.datetime(2010, 4, 27, 12, 0, 0, 0, 
           tzinfo=pytz.timezone('Israel')) 

Я хочу найти автоматический инструмент, который заменит tzinfo=pytz.timezone('Israel') с текущей локальной временной зоной.

Любые идеи?

+0

Вашей проблемы сомнителен, чтобы начать с. В зависимости от того, что вы делаете, есть хорошие шансы на создание условия гонки вблизи перехода на летнее время (или в любую другую ситуацию, когда меняется местный часовой пояс). – Kevin

ответ

26

Попробуйте dateutil, у которого есть тип tzlocal, который делает то, что вам нужно.

+9

Это не очень стандартный пакет ... есть ли еще канонические решения? – gatoatigrado

+2

'dateutil' терпит неудачу в течение некоторого времени с датами в прошлом. И для случаев, когда это действительно работает, вы можете использовать [чистое решение stdlib] (http://stackoverflow.com/a/17363006/4279) – jfs

+0

@gatoatigrado: см. [Как преобразовать дату и время python utc в локальное datetime, используя только стандартная библиотека python?] (http://stackoverflow.com/a/13287083/4279) – jfs

1

Для простых вещей, следующий tzinfo реализации может быть использована, которая запрашивает ОС для часовых поясов смещений:

import datetime 
import time 

class LocalTZ(datetime.tzinfo): 
    _unixEpochOrdinal = datetime.datetime.utcfromtimestamp(0).toordinal() 

    def dst(self, dt): 
     return datetime.timedelta(0) 

    def utcoffset(self, dt): 
     t = (dt.toordinal() - self._unixEpochOrdinal)*86400 + dt.hour*3600 + dt.minute*60 + dt.second + time.timezone 
     utc = datetime.datetime(*time.gmtime(t)[:6]) 
     local = datetime.datetime(*time.localtime(t)[:6]) 
     return local - utc 


print datetime.datetime.now(LocalTZ()) 
print datetime.datetime(2010, 4, 27, 12, 0, 0, tzinfo=LocalTZ()) 

# If you're in the EU, the following datetimes are right on the DST change. 
print datetime.datetime(2013, 3, 31, 0, 59, 59, tzinfo=LocalTZ()) 
print datetime.datetime(2013, 3, 31, 1, 0, 0, tzinfo=LocalTZ()) 
print datetime.datetime(2013, 3, 31, 1, 59, 59, tzinfo=LocalTZ()) 

# The following datetime is invalid, as the clock moves directly from 
# 01:59:59 standard time to 03:00:00 daylight savings time. 
print datetime.datetime(2013, 3, 31, 2, 0, 0, tzinfo=LocalTZ()) 

print datetime.datetime(2013, 10, 27, 0, 59, 59, tzinfo=LocalTZ()) 
print datetime.datetime(2013, 10, 27, 1, 0, 0, tzinfo=LocalTZ()) 
print datetime.datetime(2013, 10, 27, 1, 59, 59, tzinfo=LocalTZ()) 

# The following datetime is ambigous, as 02:00 can be either DST or standard 
# time. (It is interpreted as standard time.) 
print datetime.datetime(2013, 10, 27, 2, 0, 0, tzinfo=LocalTZ()) 
+0

(1) он не может работать, если модуль 'time' не имеет доступа к базе данных tz на данной платформе (примечание:' pytz' в вопросе предоставляет такой доступ переносимым образом) (2) 't' formula is неверно, если смещение utc, соответствующее 'dt', не является' -time.timezone', и поэтому даже если модуль 'time' знает правильное' localtime (t) '- ваш код может спросить неправильное значение (рассмотрим время вокруг DST). – jfs

2

Избежания нестандартного модуля (кажется недостающим метод модуля даты и времени):

from datetime import datetime 
utcOffset_min = int(round((datetime.now() - datetime.utcnow()).total_seconds()))/60 # round for taking time twice 
utcOffset_h = utcOffset_min/60 
assert(utcOffset_min == utcOffset_h * 60) # we do not handle 1/2 h timezone offsets 

print 'Local time offset is %i h to UTC.' % (utcOffset_h) 
+2

Если в прошлом вам не нравились смещения DST или utc (как показывает ваше решение); вы можете просто использовать '-time.timezone'. – jfs

2

на основании ответа Thoku в выше, вот ответ, который решает часовой пояс до ближайшего получаса (что актуально для некоторых часовых поясов, например, Южная Австралия):

from datetime import datetime 
round((round((datetime.now()-datetime.utcnow()).total_seconds())/1800)/2) 
+0

Версия Python 3: 'round ((round ((datetime.datetime.now() - datetime.datetime.utcnow()).total_seconds())/1800)/2) ' – Dmitry

+0

(1) неверно, если локальное смещение utc отличается в прошлом (оно во многих часовых поясах) (2)' round() 'может вызвать неправильное смещение utc здесь (для некоторых часовых поясов), и это не нужно. Чтобы узнать, как получить точное смещение utc, см. [Получение смещения UTC для компьютера в Python] (http://stackoverflow.com/q/3168096/4279) – jfs

22

сравнить временные метки UTC из файла журнала с местными временными метками.

Это hard to find out Olson TZ name for a local timezone портативным способом. К счастью, вам не нужно его выполнять.

tzlocal module возвращает часовой пояс pytz, соответствующий временной зоне:

from datetime import datetime 

import pytz # $ pip install pytz 
from tzlocal import get_localzone # $ pip install tzlocal 

tz = get_localzone() 
local_dt = tz.localize(datetime(2010, 4, 27, 12, 0, 0, 0), is_dst=None) 
utc_dt = local_dt.astimezone(pytz.utc) #NOTE: utc.normalize() is unnecessary here 

В отличие от других решений, представленных до сих пор выше код позволяет избежать следующих проблем:

  • local time can be ambiguous т.е. точное сравнение может быть невозможно для некоторых местных времен
  • Учет офсетной программы может отличаться для того же локального часового пояса для дат в прошлом. Некоторые библиотеки, которые поддерживают часовой пояс-зависимые объекты даты-времени (например, dateutil) не принимать это во внимание

Примечание: чтобы получить часовой пояс-Aware объект DATETIME от наивного объекта даты и времени, вы должны использовать *:

local_dt = tz.localize(datetime(2010, 4, 27, 12, 0, 0, 0), is_dst=None) 

вместо:

#XXX fails for some timezones 
local_dt = datetime(2010, 4, 27, 12, 0, 0, 0, tzinfo=tz) 

*is_dst=None вынуждает исключительные возможности если заданное местное время неоднозначно или вообще не существует.

Если вы уверены, что все локальные временные метки используют один и тот же (тока) для смещения UTC местного часового пояса, то можно выполнить сравнение с использованием только STDLIB:

# convert a naive datetime object that represents time in local timezone to epoch time 
timestamp1 = (datetime(2010, 4, 27, 12, 0, 0, 0) - datetime.fromtimestamp(0)).total_seconds() 

# convert a naive datetime object that represents time in UTC to epoch time 
timestamp2 = (datetime(2010, 4, 27, 9, 0) - datetime.utcfromtimestamp(0)).total_seconds() 

timestamp1 и timestamp2 можно сравнить непосредственно.

Примечание:

  • timestamp1 формула работает только тогда, когда UTC смещения в эпохе (datetime.fromtimestamp(0)) такое же, как и сейчас
  • fromtimestamp() создает наивный объект DATETIME в текущей локальной временной зоне
  • utcfromtimestamp() создает наивный объект datetime в UTC.
+0

Только то, что мне нужно! – nagylzs

10

Я спрашивал то же самое себя, и я нашел ответ в 1:

посмотрите на раздел 8.1.7: формат «% г» (в нижнем регистре, то Z заглавных возвращает также часовой пояс, но не в 4-значном формате, но в виде сокращений временных зон, как в [3]) strftime возвращает форму «+/- 4DIGIT», которая является стандартной в заголовках электронной почты (см. раздел 3.3 RFC 2822 , см. [2], в котором устаревают другие способы указания часового пояса для заголовков электронной почты).

Итак, если вы хотите, чтобы ваш часовой пояс в этом формате, используйте:

time.strftime("%z") 

[1] http://docs.python.org/2/library/datetime.html

[2] http://tools.ietf.org/html/rfc2822#section-3.3

[3] Timezone аббревиатуры: http://en.wikipedia.org/wiki/List_of_time_zone_abbreviations, только для Справка.

+2

вопрос о поиске объекта 'tzinfo', соответствующего локальному часовому поясу, а не текущему смещению utc в виде строки. [ 'Time.timezone',' .altzone'] (http://stackoverflow.com/questions/13218506/how-to-get-system-timezone-setting-and-pass-it-to-pytz-timezone#comment25200533_13218990) дает вам текущее смещение utc. Смещение или сокращения временной зоны неоднозначны. Не так легко получить местный часовой пояс, который вы можете использовать для дат в далеком прошлом, настоящем и ближайшем будущем. Посмотрите на исходный код модуля '' tzlocal' '(https://github.com/regebro/tzlocal), чтобы увидеть пример того, как это можно сделать. – jfs

+0

Простой и эффективный –

2

Вот способ, чтобы получить локальный часовой пояс, используя только стандартную библиотеку, (работает только в среде * NIX):

>>> '/'.join(os.path.realpath('/etc/localtime').split('/')[-2:]) 
'Australia/Sydney' 

Вы можете использовать это, чтобы создать pytz часовой пояс:

>>> import pytz 
>>> my_tz_name = '/'.join(os.path.realpath('/etc/localtime').split('/')[-2:]) 
>>> my_tz = pytz.timezone(my_tz_name) 
>>> my_tz 
<DstTzInfo 'Australia/Sydney' LMT+10:05:00 STD> 

... которые вы можете применить к datetime:

>>> import datetime 
>>> now = datetime.datetime.now() 
>>> now 
datetime.datetime(2014, 9, 3, 9, 23, 24, 139059) 

>>> now.replace(tzinfo=my_tz) 
>>> now 
datetime.datetime(2014, 9, 3, 9, 23, 24, 139059, tzinfo=<DstTzInfo 'Australia/Sydney' LMT+10:05:00 STD>) 
+0

, чтобы избежать изобретательства квадратных колес, [смотрите исходный код 'tzlocal'] (https://github.com/regebro/tzlocal) – jfs

+0

этот временной интервал нарушает среду с переопределением переменной TZ. – Karsten

3

сначала получить pytz и tzlocal модули

пункт установить pytz tzlocal

затем

from tzlocal import get_localzone 
local = get_localzone() 

, то вы можете сделать что-то вроде

from datetime import datetime 
print(datetime.now(local)) 
-1
tzlocal

из dateutil.

Приводится пример кода. Последняя строка подходит для использования в именах файлов.

>>> from datetime import datetime 
>>> from dateutil.tz import tzlocal 
>>> str(datetime.now(tzlocal())) 
'2015-04-01 11:19:47.980883-07:00' 
>>> str(datetime.now(tzlocal())).replace(' ','-').replace(':','').replace('.','-') 
'2015-04-01-111947-981879-0700' 
>>> 
0

Во-первых, отметим, что вопрос представляет собой неправильный инициализацию осознаваемому объект даты и времени:

>>> local_time=datetime.datetime(2010, 4, 27, 12, 0, 0, 0, 
...         tzinfo=pytz.timezone('Israel')) 

создает недопустимый экземпляр. Можно видеть эту проблему путем вычисления UTC смещения результирующего объекта: (. Обратите внимание на результат, который нечетная часть часа)

>>> print(local_time.utcoffset()) 
2:21:00 

инициализировать известен DateTime надлежащим образом с помощью pytz следует использовать метод localize() следующим образом:

>>> local_time=pytz.timezone('Israel').localize(datetime.datetime(2010, 4, 27, 12)) 
>>> print(local_time.utcoffset()) 
3:00:00 

Теперь, если вам требуется локальный часовой пояс pytz как новый tzinfo, вы должны использовать tzlocal пакет как другие объяснили, но если все, что вам нужно, это случай с правильным местный часовой пояс и аббревиатура Тион затем tarting с Python 3.3, вы можете вызвать метод astimezone() без аргументов, чтобы преобразовать осведомленный datetime экземпляр в местный часовой пояс:

>>> local_time.astimezone().strftime('%Y-%m-%d %H:%M %Z %z') 
'2010-04-27 05:00 EDT -0400' 
+0

(1) не передают часовой пояс 'pytz' непосредственно в' datetime() 'constructor - если вы знаете, что не должны этого делать; зачем это делать? (2) Если у вас установлен «pytz»; почему вы используете не-портативный 'astimezone()', который может не иметь доступа к базе данных tz на данной платформе? Вы можете получить чистый модуль Python ['tzlocal', который может найти объект' pytz' tzinfo для локального часового пояса для Windows и Unix ('/ etc/localtime' или'/usr/local/etc/localtime') вместо.] (Http : //stackoverflow.com/a/17363006/4279) – jfs

+0

(1), потому что именно так ОП представил свой вопрос; (2) astimezone() такой же портативный, как и он, и его можно использовать без необходимости установки дополнительного пакета. –

+0

(1) вопрос может содержать сломанный код; ответ не должен (без веской причины и четкого указания в самом блоке кода, [пример] (http://stackoverflow.com/questions/3277503/python-read-file-line-by-line-into-array# comment35813598_3277503)). (2) код уже использует pytz. Правильный ответ должен использовать базу данных tz. – jfs

19

В Python 3.x, локальная временная зона может можно понять, как это:

import datetime 
LOCAL_TIMEZONE = datetime.datetime.now(datetime.timezone.utc).astimezone().tzinfo 

Это сложное использование datetime «s code.

+0

Это хорошо – orkenstein

2

на основе J. F. Sebastian's answer, вы можете сделать это с помощью стандартной библиотеки:

import time, datetime 
local_timezone = datetime.timezone(datetime.timedelta(seconds=-time.timezone)) 

Испытан в 3.4, должен работать на 3.4+

+0

Я думаю, что это может привести к неправильным результатам, когда действует летнее время. –

Смежные вопросы