2008-12-17 11 views
32

Das Beste, was ich kann kommen, um mit jetzt ist diese Ungeheuerlichkeit:Wie bekomme ich die UTC-Zeit von "Mitternacht" für eine bestimmte Zeitzone?

>>> datetime.utcnow() \ 
... .replace(tzinfo=pytz.UTC) \ 
... .astimezone(pytz.timezone("Australia/Melbourne")) \ 
... .replace(hour=0,minute=0,second=0,microsecond=0) \ 
... .astimezone(pytz.UTC) \ 
... .replace(tzinfo=None) 
datetime.datetime(2008, 12, 16, 13, 0) 

Ie, in Englisch, die aktuelle Zeit erhalten (in UTC), wandelt es in einer anderen Zeitzone eingestellt, die Zeit bis Mitternacht dann zurück in UTC konvertieren.

Ich benutze nicht nur jetzt() oder localtime() als würde die Zeitzone des Servers, nicht die Zeitzone des Benutzers verwenden.

Ich kann nicht helfen zu fühlen, dass ich etwas vermisse, irgendwelche Ideen?

Antwort

46

Ich denke, man kann ruft ein paar Methode abrasieren, wenn Sie es tun, wie folgt:

>>> from datetime import datetime 
>>> datetime.now(pytz.timezone("Australia/Melbourne")) \ 
      .replace(hour=0, minute=0, second=0, microsecond=0) \ 
      .astimezone(pytz.utc) 

ABER ... es gibt ein größeres Problem als Ästhetik in Ihrem Code: es wird das falsche Ergebnis am Tag geben der Umstellung auf oder von der Sommerzeit.

Der Grund dafür ist, dass weder die Datetime-Konstruktoren noch replace() DST-Änderungen berücksichtigen.

Zum Beispiel:

>>> now = datetime(2012, 4, 1, 5, 0, 0, 0, tzinfo=pytz.timezone("Australia/Melbourne")) 
>>> print now 
2012-04-01 05:00:00+10:00 
>>> print now.replace(hour=0) 
2012-04-01 00:00:00+10:00 # wrong! midnight was at 2012-04-01 00:00:00+11:00 
>>> print datetime(2012, 3, 1, 0, 0, 0, 0, tzinfo=tz) 
2012-03-01 00:00:00+10:00 # wrong again! 

jedoch die Dokumentation für tz.localize() Zustände:

Diese Methode verwendet werden soll Localtimes zu konstruieren, sondern als ein Tzinfo Argument in ein Datetime-Konstruktor übergeben.

So wird Ihr Problem wie so gelöst:

>>> import pytz 
>>> from datetime import datetime, date, time 

>>> tz = pytz.timezone("Australia/Melbourne") 
>>> the_date = date(2012, 4, 1) # use date.today() here 

>>> midnight_without_tzinfo = datetime.combine(the_date, time()) 
>>> print midnight_without_tzinfo 
2012-04-01 00:00:00 

>>> midnight_with_tzinfo = tz.localize(midnight_without_tzinfo) 
>>> print midnight_with_tzinfo 
2012-04-01 00:00:00+11:00 

>>> print midnight_with_tzinfo.astimezone(pytz.utc) 
2012-03-31 13:00:00+00:00 

keine Garantien für Termine vor 1582, though.

+2

nicht vergessen Millisekunde – joeforker

+0

es scheint es ignoriert DST. Irgendwo könnte '.localize() /. Normalize()' notwendig sein. – jfs

+0

@ J.F.Sebastian: interessant! bist du sicher? Hast du ein Beispiel? es ist durchaus möglich. – hop

0

Wenn Sie die TZ-Umgebungsvariable festlegen, ändert sich die Zeitzone, in der die Python-Datums- und Zeitfunktionen arbeiten.

>>> time.gmtime() 
(2008, 12, 17, 1, 16, 46, 2, 352, 0) 
>>> time.localtime() 
(2008, 12, 16, 20, 16, 47, 1, 351, 0) 
>>> os.environ['TZ']='Australia/Melbourne' 
>>> time.localtime() 
(2008, 12, 17, 12, 16, 53, 2, 352, 1) 
+0

Abgesehen davon, dass ich nicht die TZ-Variable verwenden möchte, um das zu steuern, sagt mir das nicht, wie ich Mitternacht finde, sondern nur die aktuelle Zeit. – Tom

0

Jede Zeitzone hat eine Nummer, z. B. US/Central = -6. Dies ist definiert als der Offset in Stunden von UTC. Da 0000 Mitternacht ist, können Sie diesen Offset einfach verwenden, um die Zeit in einer beliebigen Zeitzone zu finden, wenn es Mitternacht UTC ist. Um das zugreifen, glaube ich kann Ihnen

 time.timezone

Nach The Python Docs verwenden, gibt time.timezone tatsächlich den negativen Wert dieser Zahl:

time.timezone

Der Offset die lokale (nicht-DST) Zeitzone, in Sekunden westlich von UTC (negativ in den meisten westeuropäischen Ländern, positiv in den USA, null in Großbritannien).

Also würde man einfach die Zahl für die Zeit in Stunden zu verwenden, wenn es positiv ist (dh, wenn es Mitternacht ist in Chicago (die einen 6 Zeitzone-Wert) hat, dann ist es 6000 = 06.00 UTC) .

Wenn die Zahl negativ ist, subtrahieren Sie von 24. Zum Beispiel würde Berlin -1 ergeben, also 24 - 1 => 2300 = 11pm.

+0

Ich denke, Sie sind auf dem richtigen Weg, aber woher wissen Sie, mit welchem ​​Datum beginnen? vor ein paar Stunden war es der 17. hier in Melbourne, während es noch der 16. in UTC war. – Tom

+0

Die Frage bezieht sich auf lokale Mitternacht. Die Tagesbeziehung wird durch den UTC-Offset für die Zeitzone - um Mitternacht vor Ort - festgelegt. –

+0

hinzufügen/subtrahieren tz Differenzen von Hand könnte Probleme haben, um den Schalter von und zu DST – hop

22

@hop's answer ist falsch am Tag des Übergangs von der Sommerzeit (DST) zB 1. April 2012. Um es zu beheben tz.localize() verwendet werden könnte:

tz = pytz.timezone("Australia/Melbourne") 
today = datetime.now(tz).date() 
midnight = tz.localize(datetime.combine(today, time(0, 0)), is_dst=None) 
utc_dt = midnight.astimezone(pytz.utc)   

Das gleiche mit Kommentaren:

#!/usr/bin/env python 
from datetime import datetime, time 
import pytz # pip instal pytz 

tz = pytz.timezone("Australia/Melbourne") # choose timezone 

# 1. get correct date for the midnight using given timezone. 
today = datetime.now(tz).date() 

# 2. get midnight in the correct timezone (taking into account DST) 
#NOTE: tzinfo=None and tz.localize() 
# assert that there is no dst transition at midnight (`is_dst=None`) 
midnight = tz.localize(datetime.combine(today, time(0, 0)), is_dst=None) 

# 3. convert to UTC (no need to call `utc.normalize()` due to UTC has no 
# DST transitions) 
fmt = '%Y-%m-%d %H:%M:%S %Z%z' 
print midnight.astimezone(pytz.utc).strftime(fmt) 
+0

Ich bin ein bisschen verwirrt. Der DST-Wechsel fand um 3 Uhr morgens statt, also sollte Mitternacht an diesem Tag immer noch um 14:00 UTC sein, nicht um 13:00 Uhr. Nein? – hop

+0

@hop: konvertieren 2012 März 31 13:00 UTC nach Melbourne Zeitzone und sehen Sie selbst (es ist immer noch +11 Zeitzone (DST), nicht +10 (Standard)) – jfs

Verwandte Themen