python и TZ

Phoenix

$10:03 steel ...lib/python2.7(0/1)$ zdump -v Europe/Moscow | tail
Europe/Moscow Sat Oct 24 22:59:59 2009 UTC = Sun Oct 25 02:59:59 2009 MSD isdst=1 gmtoff=14400
Europe/Moscow Sat Oct 24 23:00:00 2009 UTC = Sun Oct 25 02:00:00 2009 MSK isdst=0 gmtoff=10800
Europe/Moscow Sat Mar 27 22:59:59 2010 UTC = Sun Mar 28 01:59:59 2010 MSK isdst=0 gmtoff=10800
Europe/Moscow Sat Mar 27 23:00:00 2010 UTC = Sun Mar 28 03:00:00 2010 MSD isdst=1 gmtoff=14400
Europe/Moscow Sat Oct 30 22:59:59 2010 UTC = Sun Oct 31 02:59:59 2010 MSD isdst=1 gmtoff=14400
Europe/Moscow Sat Oct 30 23:00:00 2010 UTC = Sun Oct 31 02:00:00 2010 MSK isdst=0 gmtoff=10800
Europe/Moscow Sat Mar 26 22:59:59 2011 UTC = Sun Mar 27 01:59:59 2011 MSK isdst=0 gmtoff=10800
Europe/Moscow Sat Mar 26 23:00:00 2011 UTC = Sun Mar 27 03:00:00 2011 MSK isdst=0 gmtoff=14400
Europe/Moscow Fri Jan 1 03:00:00 2500 UTC = Fri Jan 1 03:00:00 2500 MSK isdst=0 gmtoff=14400
Europe/Moscow Fri Jan 1 03:00:00 2500 UTC = Fri Jan 1 03:00:00 2500 MSK isdst=0 gmtoff=14400
$10:03 steel ...lib/python2.7(0/1)$ python
Python 2.7.1 (r271:86832, Mar 30 2011, 22:08:41)
[GCC 4.2.1 20070719 [FreeBSD]] on freebsd8
Type "help", "copyright", "credits" or "license" for more information.
>>> import os, time
>>> os.environ['TZ'] = 'Europe/Moscow'
>>> time.tzset
>>> time.timezone
-10800
>>>

В общем django устанавливает так же временную зону, поэтому в ней тоже не работает.

artimon

Используй time.altzone и напиши об этом разработчикам Django
$ python
Python 2.6.5 (r265:79063, Apr 16 2010, 13:57:41)
[GCC 4.4.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import time
>>> time.tzname
('MSK', 'MSK')
>>> time.timezone
-10800
>>> time.altzone
-14400

Phoenix

У них так http://code.djangoproject.com/browser/django/branches/relea...
 
40	    def utcoffset(self, dt):
41 if self._isdst(dt):
42 return timedelta(seconds=-time.altzone)
43 else:
44 return timedelta(seconds=-time.timezone)
45
46 def dst(self, dt):
47 if self._isdst(dt):
48 return timedelta(seconds=-time.altzone) - timedelta(seconds=-time.timezone)
49 else:
50 return timedelta(0)


59 def _isdst(self, dt):
60 tt = (dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second, dt.weekday 0, -1)
61 try:
62 stamp = time.mktime(tt)
63 except (OverflowError, ValueError):
64 # 32 bit systems can't handle dates after Jan 2038, and certain
65 # systems can't handle dates before ~1901-12-01:
66 #
67 # >>> time.mktime1900, 1, 13, 0, 0, 0, 0, 0, 0
68 # OverflowError: mktime argument out of range
69 # >>> time.mktime1850, 1, 13, 0, 0, 0, 0, 0, 0
70 # ValueError: year out of range
71 #
72 # In this case, we fake the date, because we only care about the
73 # DST flag.
74 tt = (2037 + tt[1:]
75 stamp = time.mktime(tt)
76 tt = time.localtime(stamp)
77 return tt.tm_isdst > 0

Перепутали что ли? Они используют функцию dst для опредления, есть ли сохранение времени.
Вроде как логично. В доках сказано, что altzone только для тех, у кого время на дневное переводится.
 
The offset of the local DST timezone, in seconds west of UTC, if one is defined. This is negative if the local DST timezone is east of UTC (as in Western Europe, including the UK). Only use this if daylight is nonzero.

Почему для MSK различаются altzone и timezone?

artimon

Я в Django не силён, но на вид вроде правильно.
> Почему для MSK различаются altzone и timezone?
Потому что по tzdata у нас сейчас летнее время.

artimon

Разобрался с удалённым постом?
Поделись, мне тоже интересно.

Phoenix

Да фиг его знает.
Я им вот такое написал. http://code.djangoproject.com/ticket/16899
Я всё равно не понимаю.
time.daylight, time.altzone, time.timezone не зависят от текущего времени, поэтому, видимо, для определения нужного смещения нужно применять магию с tm_isdst. Там есть свои фичи, типа одному локальному времени может соответствовать два UTC (одно с dst, другое без dst но это не важно.
Будем считать, что в году есть 2 часа неблагоприятных для работы.
дальше вроде как всё идёт к тому, что баг в самом time питона.
Т.к. единственная логика, которая у меня не вызывает отторжения такая:
есть timezone - для обычного, altzone - для альтернативного
если tm_isdst - 0, то применяем обычное, если 1, то альтернативное.
Тогда получается, что timezone возвращать 14400, о чём я в начале и написал. И что ожидают от time django-писатели.

Phoenix

Теперь и то, что я сказал вызывает непринятие.
Как же узнать смещение прошлой зимой? только по файлу зоны.
Двумя значениями не обойтись. Т.е. нужен какой-то механизм не просто узнавать зимнее/летнее время по времени, а, использую магию файлов зон определять ещё и смещение.
Т.е. алгоритм в django предполагает, что зона не меняется. Летнее смещение и зимнее смещение остаётся одинаковым.

Phoenix

моё решение такое

>>> pp = time.mktime2011, 1, 13, 0, 0, 0, 0, 0, -1
>>> datetime.utcfromtimestamp(pp) - datetime.fromtimestamp(pp)
datetime.timedelta(0, -10800)
>>> p2 = time.mktime2011, 7, 13, 0, 0, 0, 0, 0, -1
>>> datetime.utcfromtimestamp(p2) - datetime.fromtimestamp(p2)
datetime.timedelta(0, -14400)
>>> p3 = time.mktime2011, 9, 28, 0, 0, 0, 0, 0, -1
>>> datetime.utcfromtimestamp(p3) - datetime.fromtimestamp(p3)
datetime.timedelta(0, -14400)

artimon

Да уж, что то в питоне намудрили

Phoenix

похоже на то же самое.
datetime.utcfromtimestamp(pp) - datetime.fromtimestamp(pp) вроде от этого бага не страдает.
По сути у всех этих (что по ссылке, что в джанго) был хак, который использовал инвариантность часовых поясов.
Пока timezone и altzone сохранялись - всё работало.

Phoenix

а на винде всё ок :grin:
>>> time.timezone
-14400
>>> time.altzone
-18000
>>> time.daylight
0
>>>

Phoenix

чувак ответил, что мы сделали так, как было в доке по питону и что это у них там косяки
http://bugs.python.org/issue1647654
http://bugs.python.org/issue9527
Оставить комментарий
Имя или ник:
Комментарий: