Zeitzonen und Sommerzeit

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
betterworld
User
Beiträge: 3
Registriert: Freitag 31. Juli 2015, 07:10

Hallo allerseits,

ich verzweifle momentan an einer Aufgabe, die eigentlich ziemlich einfach und auch alltäglich sein sollte: Timestamps in Strings umwandeln und wieder zurück unter korrekter Behandlung von Zeitzonen und Sommerzeit.

Offenbar funktioniert das in der sonst sehr umfangreichen Standardbibliothek nur unter Hinzunahme von "dateutil". Aber auch dann kommt nicht wirklich das heraus, was man erwartet. Folgende Testergebnisse bei mir (lokale Zeitzone ist CET):

Code: Alles auswählen

import datetime, dateutil.tz, dateutil.parser

datetime.datetime.fromtimestamp(1445733000, dateutil.tz.tzlocal()).strftime('%H:%M %Z')   # '02:30 CET'
datetime.datetime.fromtimestamp(1445736600, dateutil.tz.tzlocal()).strftime('%H:%M %Z')   # '02:30 CET'
Wie kann denn das beides dasselbe ergeben? Da hätte ich jetzt erwartet, dass die Zeitzone einmal mit "CET" und einmal mit "CEST" rauskommt. (Anm.: Die Timestamps liegen eine Stunde auseinander und das ist genau die Stunde, wo dieses Jahr die Winterzeit anfängt.)

Anders herum genau dasselbe:

Code: Alles auswählen

dateutil.parser.parse('2015-10-25 02:30:00 CET')
dateutil.parser.parse('2015-10-25 02:30:00 CEST')
... ergibt auch beides mal dasselbe.

Mit dem einfacheren Modul "time" funktioniert zwar die Sommerzeit halbwegs, aber dafür macht es offenbar alles nur in der lokalen Zeitzone:

Code: Alles auswählen

time.mktime(time.strptime("2015-10-25 02:30:00 CET", "%Y-%m-%d %H:%M:%S %Z"))   # 1445736600.0
time.mktime(time.strptime("2015-10-25 02:30:00 CEST", "%Y-%m-%d %H:%M:%S %Z"))   # 1445733000.0

# soweit war das richtig, das war schon mal besser als mit datetime/dateutil.  Aber nun:

time.mktime(time.strptime("2015-10-25 02:30:00 UTC", "%Y-%m-%d %H:%M:%S %Z"))  # 1445736600.0 -> falsch.
Zum Vergleich mal mit GNU date in der Kommondozeile. Das macht imho alles richtig:

Code: Alles auswählen

$ date +%s -d '2015-10-25 02:30:00 UTC'
1445740200
$ date +%s -d '2015-10-25 02:30:00 CET'
1445736600
$ date +%s -d '2015-10-25 02:30:00 CEST'
1445733000
Wenn jemand einen Tipp hat, wie man diese scheinbar sehr simple Aufgabe in Python umsetzen kann, wäre ich dankbar :)
Gegooglet habe ich, da bin ich bisher nur auf dateutil gestoßen, aber, wie man sieht, hilft das auch nicht.
BlackJack

@betterworld: Das übliche (externe) Modul für ”Zeitzonenkram” ist `pytz`:

Code: Alles auswählen

In [40]: A = datetime.datetime.fromtimestamp(1445733000, pytz.UTC)

In [41]: B = datetime.datetime.fromtimestamp(1445736600, pytz.UTC)

In [42]: tz = pytz.timezone('Europe/Berlin')

In [43]: format(tz.normalize(A.astimezone(tz)), '%H:%M %Z')
Out[43]: '02:30 CEST'

In [44]: format(tz.normalize(B.astimezone(tz)), '%H:%M %Z')
Out[44]: '02:30 CET'
Edit: Beim Parsen hast Du mit den 3- bis 4-buchstabigen kürzeln für Zeitzonen das Problem das die nicht eindeutig sein müssen, man also nicht zwingend so einem Kürzel *einen* Zeitversatz zuordnen kann. 'EST' gibt es beispielsweise sowohl in Nordamerika als auch in Australien als Abkürzung und es steht natürlich in beiden Fällen nicht für den gleichen relativen Versatz zu UTC.
betterworld
User
Beiträge: 3
Registriert: Freitag 31. Juli 2015, 07:10

Hi BlackJack,
danke für den Tipp. pytz hatte ich wohl beim Googlen übersehen.

Aber vielleicht hast Du recht, dass das mit den Kürzeln eine schlechte Idee ist. Vielleicht stelle ich doch auf GMT-Offsets um, denn dafür braucht man auch keine Tabellen. Ich habe dann noch gefunden, dass es ab Python 3.2 das Modul datetime.timezone gibt, womit ich mir die String-Um/Rückwandlung mit den Offsets wohl irgendwie hinfriemeln könnte.
Antworten