2014-10-20 15 views
5

Ho trovato alcune cose strane. Ecco alcuni esempi.Django timezone.make_aware ha generato AmbiguousTimeError per il 26/10/2014 26:45:00

from django.utils import timezone 
value = u'2014-10-26 01:45:00' 
#I know that a variable has 'Europe/Moscow' timezone. Let's tell Django about it. 
TZ = timezone.pytz.timezone('Europe/Moscow') 
d = timezone.datetime.strptime(value,'%Y-%m-%d %H:%M:%S') 
print timezone.make_aware(d,TZ) 
#raised AmbiguousTimeError: 2014-10-26 01:45:00 

E poi inizia il divertimento

print timezone.make_aware(d+timezone.timedelta(minutes=15),TZ) 
#out: 2014-10-26 02:00:00+03:00 
print timezone.make_aware(d+timezone.timedelta(minutes=14),TZ) 
#raised AmbiguousTimeError 
print timezone.make_aware(d-timezone.timedelta(minutes=46),TZ) 
#out: 2014-10-26 00:59:00+04:00 
print timezone.make_aware(d-timezone.timedelta(minutes=45),TZ) 
#raised AmbiguousTimeError  

Così AmbiguousTimeError sollevato tra 2014/10/26 00:59:00 e 2014-10-26 02:00:00

PERCHE '? E come lo risolvono?

risposta

3

timezon.make_aware(d, TZ) equivale a TZ.localize(d, is_dst=None) che genera un errore per i tempi ambigui: 2014-10-26 01:45:00 accade due volte in Europa/Mosca fuso orario:

# Europe/Moscow    UTC       timestamp 
2014-10-26 00:45:00 MSK+0400; 2014-10-25 20:45:00 UTC+0000; 1414269900 
2014-10-26 01:00:00 MSK+0400; 2014-10-25 21:00:00 UTC+0000; 1414270800 
2014-10-26 01:15:00 MSK+0400; 2014-10-25 21:15:00 UTC+0000; 1414271700 
2014-10-26 01:30:00 MSK+0400; 2014-10-25 21:30:00 UTC+0000; 1414272600 
2014-10-26 01:45:00 MSK+0400; 2014-10-25 21:45:00 UTC+0000; 1414273500 
2014-10-26 01:15:00 MSK+0300; 2014-10-25 22:15:00 UTC+0000; 1414275300 
2014-10-26 01:30:00 MSK+0300; 2014-10-25 22:30:00 UTC+0000; 1414276200 
2014-10-26 01:45:00 MSK+0300; 2014-10-25 22:45:00 UTC+0000; 1414277100 
2014-10-26 02:00:00 MSK+0300; 2014-10-25 23:00:00 UTC+0000; 1414278000 

Avviso: l'offset UTC viene modificato +0400-+0300 alle 2 di notte (Федеральный закон от 21 июля 2014 г. N 248-ФЗ).

Per evitare l'eccezione, è possibile chiamare TZ.localize(d) (nota: no is_dst=None) che funziona bene per i tempi non ambigui esistenti ma potrebbe non riuscire (restituire la risposta errata) per i periodi non esistenti o ambigui.

Se è stato risolto pytz Bug #1378150: Enhance support for end-of-DST-like ambiguous time, è possibile utilizzare TZ.localize(d, is_dst=True), TZ.localize(d, is_dst=False) per ottenere il tempo prima e dopo la transizione in modo corrispondente.

Se il bug non è fisso si potrebbe usare la mia risposta da Parsing of Ordered Timestamps in Local Time (to UTC) While Observing Daylight Saving Time per ottenere il tempo dopo la transizione:

# `naive` is a naive datetime object in local (Europe/Moscow) time 
if tz.localize(naive, is_dst=False) == tz.localize(naive, is_dst=True): 
    # Example: 2014/10/26 in Europe/Moscow timezone 
    # ambiguous time but is_dst=False/True yield the same result 
    # i.e., tz.localize() can't help, find UTC time manually 
    #NOTE: assume there is no other changes to UTC offset today (local.day) 
    new_offset = tz.localize(naive + timedelta(1), is_dst=None).utcoffset() 
    assert tz.localize(naive).utcoffset() != new_offset 
    utc = (naive - new_offset).replace(tzinfo=pytz.utc) 
    local = utc.astimezone(tz) 
1

A causa dell'ora legale.

Alle 2:00 del 26 ottobre, i moscoviti torneranno indietro di un'ora. Ciò significa che vedranno, per esempio, 1:30 due volte in quel giorno. Quindi i tempi tra l'1: 00 e le 2:00 sono ambigui e Python/pytz lo sta dicendo.

Il modo in cui gestirai sarà specifico dell'applicazione. Devi decidere di quale delle 1:30 di cui stai parlando (cioè di quale ora UTC stai parlando).

(A quanto pare questa è l'ultimo anno che la maggior parte dei russi si occuperà con il DST Vedere this article per alcuni retroscena interessanti..)

+0

non è l'ora legale. Europa/Mosca ha UTC + 0400 compensato per tutto l'anno. L'offset è cambiato (da un ordine governativo specifico) a UTC + 0300 al 26 ottobre 2014. Sebbene l'effetto sia lo stesso della transizione di fine dell'ora legale ("fall back") ad esempio, vedere [Bug # 1378150 "Migliorare il supporto per end-of-DST-like ambiguous time ... "' pytz' bug] (https://bugs.launchpad.net/pytz/+bug/1378150) - significa che anche esplicativo 'TZ.localize (ingenuo, is_dst = True) '(o' is_dst = False') non darà il tempo desiderato fino a quando il bug non verrà risolto. – jfs