Konvertieren Sie Python datetime mit strftime in eine Epoche


209

Ich habe eine Zeit in UTC, ab der ich die Anzahl der Sekunden seit der Epoche angeben möchte.

Ich verwende strftime, um es in die Anzahl der Sekunden umzuwandeln. Am Beispiel des 1. April 2012.

>>>datetime.datetime(2012,04,01,0,0).strftime('%s')
'1333234800'

1. April 2012 UTC aus der Epoche ist 1333238400, aber dies oben gibt 1333234800 zurück, was sich um 1 Stunde unterscheidet.

Es sieht also so aus, als würde die Strftime meine Systemzeit berücksichtigen und irgendwo eine Zeitzonenverschiebung anwenden. Ich dachte, datetime sei rein naiv?

Wie kann ich das umgehen? Vermeiden Sie nach Möglichkeit den Import anderer Bibliotheken, sofern dies nicht Standard ist. (Ich habe Bedenken hinsichtlich der Portabilität).



11
Bin ich der einzige, der bemerkt, dass Sie in den Zahlen Oktalliterale verwenden?
Fisch - Monitor


3
Neuere Python 3.3+ hatdatetime.datetime.timestamp(datetime.datetime.utcnow())
MarkHu

Antworten:


389

Wenn Sie eine Python-Datumszeit in Sekunden seit der Epoche konvertieren möchten, können Sie dies explizit tun:

>>> (datetime.datetime(2012,04,01,0,0) - datetime.datetime(1970,1,1)).total_seconds()
1333238400.0

In Python 3.3+ können Sie timestamp()stattdessen Folgendes verwenden :

>>> datetime.datetime(2012,4,1,0,0).timestamp()
1333234800.0

Warum sollten Sie nicht verwenden datetime.strftime('%s')

Python unterstützt% s nicht als Argument für strftime (wenn Sie unter http://docs.python.org/library/datetime.html#strftime-and-strptime-behavior nachsehen, ist es nicht in der Liste enthalten), das einzige Der Grund dafür ist, dass Python die Informationen an die Strftime Ihres Systems weiterleitet, die Ihre lokale Zeitzone verwendet.

>>> datetime.datetime(2012,04,01,0,0).strftime('%s')
'1333234800'

7
Ich bin verrückt geworden, um herauszufinden, warum ich oft Strftime ("% s") sehe, aber es steht nicht in den Dokumenten. Danke für nichts das!
Jonathan Vanasco

54
nicht verwenden .strftime("%s"): es wird nicht unterstützt, es ist nicht portierbar, es kann stillschweigend ein falsches Ergebnis für ein bewusstes Datum / Uhrzeit-Objekt erzeugen, es schlägt fehl, wenn die Eingabe in UTC erfolgt (wie in der Frage), aber die lokale Zeitzone nicht UTC ist
jfs

2
@earthmeLon Deine Klammer ist falsch. Zeitdeltas (erstellt durch Subtrahieren von zwei Datumsangaben) haben total_seconds, Datumsangaben jedoch nicht.
Jleahy

2
Das funktioniert bei mir nicht:AttributeError: 'datetime.timedelta' object has no attribute 'total_seconds'
Michael

3
@Michael Diese Funktion ist neu in Python 2.7. Sie müssen eine ältere Version verwenden. Für Versionen vor 2.7 können Sie tun td.seconds + td.days*24*3600. Dadurch wird der Mikrosekunden-Teil verworfen.
Jleahy

100

Ich hatte ernsthafte Probleme mit Timezones und so. Die Art und Weise, wie Python mit all dem umgeht, ist (für mich) ziemlich verwirrend. Mit dem Kalendermodul scheinen die Dinge gut zu funktionieren (siehe Links 1 , 2 , 3) und 4 ).

>>> import datetime
>>> import calendar
>>> aprilFirst=datetime.datetime(2012, 04, 01, 0, 0)
>>> calendar.timegm(aprilFirst.timetuple())
1333238400

7
+1, da dies die einzige Antwort ist, die für die Eingabe in der Frage funktioniert.
JFS

ist das tragbar?
Benjamin

1
Dies sollte als rechtmäßige Antwort markiert werden, da dies das betreffende Anliegen beantwortet. vnice kudos
Leo Prince

2
Dies 'funktioniert', aber beachten Sie die Frage: "Ich habe eine Zeit in UTC" Diese Methode verwendet immer die lokale Zeitzone des Systems. Es gibt keine Möglichkeit, eine Zeitzone anzugeben. Wenn aprilFirstin diesem Beispiel eine "bewusste" Instanz wäre und eine andere Zeitzone als die Zeitzone des Systems verwendet würde, wäre das Ergebnis nicht korrekt (die Zeitzone geht beim timetuple()Aufruf verloren). Um die richtige Antwort für eine "bewusste" Datumszeit zu erhalten, können Sie das awaredt.timestamp()aktuelle Python 3 verwenden. Für Python 2 ist es schwieriger. Eine Möglichkeit besteht darin, die arrowBibliothek zu verwenden. arrow.get(awaredt).timestampwerde es richtig machen.
Adam Williamson

1
Guter Punkt, @AdamWilliamson, aber der Code im Beispiel lokalisiert das datetimeObjekt nicht. Daher nahm ich an, dass "Ich habe eine Zeit in UTC" bedeutet, dass das OP ein ahnungsloses datetimeObjekt hatte, von dem angenommen wurde , dass es in UTC ist, für das er wollte zu bekommen epoch(wenn das datetimezufällig TZ-bewusst ist, könnte dies tatsächlich Dinge ändern). Denken Sie auch daran, dass diese Antwort fast 8 Jahre alt ist und seitdem viel passiert ist ( arrowwurde zum Beispiel 2013 veröffentlicht)
BorrajaX

35
import time
from datetime import datetime
now = datetime.now()

time.mktime(now.timetuple())

1
Es ist eine falsche Schreibweise time.time()( mktime()kann während der Sommerzeitübergänge fehlschlagen, während time.time()die Arbeit fortgesetzt wird). Die Frage wird nur beantwortet, wenn die lokale Zeitzone UTC ist (die Eingabe in der Frage erfolgt in UTC). Selbst wenn die Eingabe eine Ortszeit darstellen würde, mktime()kann dies auch für vergangene / zukünftige Daten fehlschlagen, wenn die tz-Datenbank nicht verwendet wird und wenn die lokale Zeitzone im Laufe der Jahre unterschiedliche UTC-Offsets aufweist, z. B. Europa / Moskau in den Jahren 2010-2015 - - Verwenden Sie stattdessen UTC-Zeit (wie in der Frage) oder zeitzonenbezogene Datums- / Uhrzeitobjekte.
JFS

Hier finden Sie weitere Probleme beim Konvertieren einer Ortszeit (z. B. zurückgegeben von .now()) in einen Epochenzeitstempel (zurückgegeben von mktime()) . Wenn du es liest; Sie verstehen, warum UTC-Eingabe (in der Frage verwendet) (viel) vorzuziehen ist als ein naives Datum / Uhrzeit-Objekt, das die Ortszeit darstellt
jfs

14
import time
from datetime import datetime
now = datetime.now()

# same as above except keeps microseconds
time.mktime(now.timetuple()) + now.microsecond * 1e-6

(Entschuldigung, ich würde die vorhandene Antwort nicht kommentieren können.)


Das liegt daran, dass time.mktime den Mikrosekunden-Teil nicht berücksichtigt, oder?
Eduardo

1
Richtig. Die Zeittupelstruktur (basierend auf der C-Strebe) hat keinen Platz für Mikrosekunden, daher müssen wir die Informationen aus dem datetime-Objekt abrufen und am Ende hinzufügen.
Charles Plager


Auf meinen Maschinen funktioniert dies korrekt, obwohl meine Zeitzone ET ist.
Charles Plager

1
Auf diese Weise erhalten Sie je nach Ortszeit des Systems unterschiedliche Zeitstempel auf verschiedenen Systemen.
Yousaf

6

Wenn Sie nur einen Zeitstempel in Unix- / Epochenzeit benötigen, funktioniert diese eine Zeile:

created_timestamp = int((datetime.datetime.now() - datetime.datetime(1970,1,1)).total_seconds())
>>> created_timestamp
1522942073L

und hängt nur von datetime Arbeiten in Python2 und Python3 ab


2

Dies funktioniert in Python 2 und 3:

>>> import time
>>> import calendar
>>> calendar.timegm(time.gmtime())
1504917998

Folgen Sie einfach den offiziellen Dokumenten ... https://docs.python.org/2/library/time.html#module-time


1) Dies setzt voraus, dass Sie jetzt konvertieren möchten, nicht ein zufälliges Datum / Uhrzeit-Objekt. 2) Sie brauchen keinen Kalender. time.mktime (randomDateTime.timetuple ()) + randomDateTime.microsecond * 1e-6
Charles Plager

@CharlesPlager time.mktime ist falsch; Es interpretiert das Argument in der lokalen Zeitzone, während das OP die Zeit in UTC interpretieren möchte (wie dies bei calendar.timegm der Fall ist).
Stewbasic

Dies ist die genaueste Antwort für mich, wenn Sie Ihre Zeit in GMT konvertieren möchten und dies auch bei der Konvertierung in einen Epochenzeitstempel beibehalten möchten.
Yousaf

Folgen Sie einfach Ihrer Antwort: calendar.timegm (datetime.strptime ("2019-05-03T05: 40: 09.770494 + 00: 00" [: 16], '% Y-% m-% dT% H:% M'). timetuple ()) Ich habe einen Zeitstempel in utc und egal auf welchem ​​System Sie ihn ausführen, er gibt mir den richtigen Zeitstempel. Der Trick besteht darin, strptime.timetumple zu verwenden
Yousaf

2

Verwenden Sie für eine explizite zeitzonenunabhängige Lösung die Pytz-Bibliothek.

import datetime
import pytz

pytz.utc.localize(datetime.datetime(2012,4,1,0,0), is_dst=False).timestamp()

Ausgabe (float): 1333238400.0


Ich habe eine ähnliche Antwort unter stackoverflow.com/a/21145908/4355695 gesehen , aber diese als Einzeiler eignet sich hervorragend für meinen Anwendungsfall, bei dem die eingehenden Daten in UTC vorliegen und nur .timestamp () davon ausgeht, dass sie in Ortszeit vorliegen .
Nikhil VJ

Dies funktioniert für Daten unter 1970. Vielen Dank. Die akzeptierte Antwort funktioniert nicht für Daten unter 1970. (Python 3.7.3 64-Bit-Anaconda3)
canbax

-1

In Python 3.7

Gibt eine Datums- / Uhrzeitangabe zurück, die einer Datumszeichenfolge in einem der von date.isoformat () und datetime.isoformat () ausgegebenen Formate entspricht. Insbesondere unterstützt diese Funktion Zeichenfolgen in den Formaten JJJJ-MM-TT [* HH [: MM [: SS [.fff [fff]]] [+ HH: MM [: SS [.ffffff]]] , wobei * mit jedem einzelnen Zeichen übereinstimmen kann.

https://docs.python.org/3/library/datetime.html#datetime.datetime.fromisoformat


1
Beachten Sie, dass dies in Python 3.7 eingeführt wurde.
Keithpjolley
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.