2016-05-05 8 views
1

Ich möchte berechnen, wie viele Stunden es in einem Datumsintervall gibt: zum Beispiel "2014.03.29-30" sollte 47 geben, wegen der Sommerzeit.Unterschied von zwei Timedelta-Objekten, mit Zeitzonen

Meine Methode macht zwei Datetime-Objekte, im Beispiel die folgende:

datetime.datetime(2014, 3, 29, 0, 0, tzinfo=<DstTzInfo 'Europe/Budapest' LMT+1:16:00 STD>) 
datetime.datetime(2014, 3, 30, 23, 59, tzinfo=<DstTzInfo 'Europe/Budapest' LMT+1:16:00 STD>) 
return (date2-date1) + timedelta(minutes=1) 

es jedoch „2 Tage, 0:00:00“ gibt, die nicht korrekt ist. Wie könnte ich ein Timedelta-Objekt erstellen, das Zeitzonen und dst berücksichtigt? Auch wenn es eine einfachere Lösung für das ganze Problem gibt, bin ich offen dafür.

Vielen Dank!

Antwort

2

Vor dem 1901-12-13 20:45:52 UTC war die Zeitzone 'Europe/Budapest' LMT + 1: 16: 00 STD. Derzeit, ab 2016-05-05, ist die 'Europe/Budapest' Zeitzone CET + 2: 00: 00 DST.

Wenn Sie pytz die localize method, dann pytz wird die Zeitzone (UTCOFFSET und dstOffset) wählt für 'Europe/Budapest', die für die gegebene naive Datumzeit geeignet ist:

import datetime as DT 
import pytz 

tzone = pytz.timezone('Europe/Budapest') 
date1 = tzone.localize(DT.datetime(2014, 3, 29, 0, 0), is_dst=None) 
# datetime.datetime(2014, 3, 29, 0, 0, tzinfo=<DstTzInfo 'Europe/Budapest' CET+1:00:00 STD>) 

Im Gegensatz dazu, wenn Sie liefern tzinfo=tzone direkt an datetime.datetime, wie in:

wrong_date1 = datetime.datetime(2014, 3, 29, 0, 0, tzinfo=tzone) 
# datetime.datetime(2014, 3, 29, 0, 0, tzinfo=<DstTzInfo 'Europe/Budapest' LMT+1:16:00 STD>) 

dann wählt der datetime.datetimefalsch die erste Zeitzone zugeordnet mit 'Europe/Budapest'unabhängig davon, ob das war die Zeitzone in Kraft am 2014-3-29.

Wenn daher pytz arbeiten, verwenden Sie immer tzone.localize naive Datetimes Zeitzone-bewusst zu machen: (. Oder eine Zeitzone, die im Laufe ihrer Geschichte alle Tage gleich ist)

import datetime as DT 
import pytz 
tzone = pytz.timezone('Europe/Budapest') 
date1 = tzone.localize(DT.datetime(2014, 3, 29, 0, 0), is_dst=None) 
date2 = tzone.localize(DT.datetime(2014, 3, 30, 23, 59), is_dst=None) 
print(((date2-date1) + DT.timedelta(minutes=1)).total_seconds()/3600.) 
# 47.0 

Do not use tzinfo=tzone es sei denn, tzone ist pytz.utc


Woher kam das Datum 1901-12-13 20:45:52 UTC?

Sie bei einer UTC-Übergangszeiten des pytz Zeitzone peek (und Informationen verbunden Übergang) seine tzone._utc_transition_times und tzone._transition_info private Attribute verwenden:

In [43]: [(utcdate, utcoffset, dstoffset, tzabbrev) for utcdate, (utcoffset, dstoffset, tzabbrev) in zip(tzone._utc_transition_times, tzone._transition_info)][:2] 
Out[43]: 
[(datetime.datetime(1, 1, 1, 0, 0), 
    datetime.timedelta(0, 4560), 
    datetime.timedelta(0), 
    'LMT'), 
(datetime.datetime(1901, 12, 13, 20, 45, 52), 
    datetime.timedelta(0, 3600), 
    datetime.timedelta(0), 
    'CET')] 

Dies, dass ab dem Zeitpunkt 1-1-1 UTC zu 1901-12-13 20:45:52 UTC zeigt war die Zeitzone Abkürzung LMT und die Utcoffset war 4560 Sekunden, was 1 Stunde und 16 Minuten entspricht:

In [47]: print(DT.timedelta(0, 4560)) 
1:16:00 

Daher die erste t Imezone, die mit 'Europe/Budapest' assoziiert ist, ist .

+0

Vielen Dank! Eine letzte Sache: Was macht der 'is_dst = None' Teil? Ich habe es versehentlich übersprungen, aber es funktioniert auch so, wie es sollte. – Rolf

+2

'is_dst = None' sagt' tzone.localize', um einen 'AmbiguousTimeError' für mehrdeutige Zeiten zu erzeugen, wenn die Sommerzeit endet -" falling back "bewirkt, dass die gleiche naive Zeit zweimal auftritt.Ansonsten tut es was angemessen ist. Es wird aus "großer Vorsicht" als allgemeine Gewohnheit verwendet, obwohl es hier keine Wirkung hat. Standardmäßig ist 'is_dst = False', was bedeutet, dass 'tzone.localize' mehrdeutige Zeiten auflöst, indem * angenommen wird, dass sich die naive Datetime auf die Datetime bezieht, wenn die Sommerzeit nicht in Kraft ist. – unutbu

+0

Ich verstehe, danke. – Rolf