UTC-Zeitstempel in Python mit Datum / Uhrzeit abrufen

83

Gibt es eine Möglichkeit, den UTC-Zeitstempel durch Angabe des Datums abzurufen? Was ich erwarten würde:

datetime(2008, 1, 1, 0, 0, 0, 0)

sollte ergeben

 1199145600

Das Erstellen eines naiven Datetime-Objekts bedeutet, dass keine Zeitzoneninformationen vorhanden sind. Wenn ich mir die Dokumentation zu datetime.utcfromtimestamp ansehe, bedeutet das Erstellen eines UTC-Zeitstempels, dass die Zeitzoneninformationen weggelassen werden. Ich würde also vermuten, dass das Erstellen eines naiven Datetime-Objekts (wie ich) zu einem UTC-Zeitstempel führen würde. Jedoch:

then = datetime(2008, 1, 1, 0, 0, 0, 0)
datetime.utcfromtimestamp(float(then.strftime('%s')))

führt zu

2007-12-31 23:00:00

Gibt es noch versteckte Zeitzoneninformationen im datetime-Objekt? Was mache ich falsch?

klopfen
quelle
Das Problem ist then.strftime('%s'), dass die Ortszeit erwartet wird , der Zeitstempel jedoch anzeigt, dass die datetime(2008, 1, 1)UTC vorliegt.
JFS

Antworten:

91

Naiv datetimeversus bewusstdatetime

Standardobjekte datetimewerden als "naiv" bezeichnet: Sie speichern Zeitinformationen ohne Zeitzoneninformationen. Stellen Sie sich naiv datetimeals relative Zahl (dh :) +4ohne eindeutigen Ursprung vor (tatsächlich wird Ihr Ursprung über Ihre Systemgrenze hinweg gemeinsam sein).

Denken Sie im Gegensatz dazu an Bewusstsein datetimeals absolute Zahlen (dh:8 mit einem gemeinsamen Ursprung für die ganze Welt vor.

Ohne Zeitzone Informationen Sie können nicht die „naive“ Datetime gegenüber jeder nicht-naive Zeitdarstellung umwandeln (woher kommt +4Ziele , wenn wir von nicht wissen , wo Sie anfangen sollen ?). Deshalb können Sie keine datetime.datetime.toutctimestamp()Methode haben. (vgl.: http://bugs.python.org/issue1457227 )

Um zu überprüfen, ob Sie datetime dtnaiv sind, überprüfen Sie dt.tzinfo, ob None, dann ist es naiv:

datetime.now()        ## DANGER: returns naïve datetime pointing on local time
datetime(1970, 1, 1)  ## returns naïve datetime pointing on user given time

Ich habe naive Daten, was kann ich tun?

Sie müssen abhängig von Ihrem speziellen Kontext eine Annahme treffen: Die Frage, die Sie sich stellen müssen, lautet: War Ihre datetimeUTC? oder war es Ortszeit?

  • Wenn Sie UTC verwendet haben (Sie haben keine Probleme):

    import calendar
    
    def dt2ts(dt):
        """Converts a datetime object to UTC timestamp
    
        naive datetime will be considered UTC.
    
        """
    
        return calendar.timegm(dt.utctimetuple())
    
  • Wenn Sie NICHT UTC verwendet haben , willkommen in der Hölle.

    Sie müssen Ihre datetimenicht naiv machen, bevor Sie die erstere Funktion verwenden, indem Sie ihnen ihre beabsichtigte Zeitzone zurückgeben.

    Sie benötigen den Namen der Zeitzone und die Information darüber, ob die Sommerzeit bei der Erstellung der naiven Datumszeit des Ziels wirksam war (die letzten Informationen zur Sommerzeit sind für Eckfälle erforderlich):

    import pytz     ## pip install pytz
    
    mytz = pytz.timezone('Europe/Amsterdam')             ## Set your timezone
    
    dt = mytz.normalize(mytz.localize(dt, is_dst=True))  ## Set is_dst accordingly
    

    Folgen der Nichtbereitstellungis_dst :

    is_dstWenn Sie nicht verwenden, wird eine falsche Zeit (und ein falscher UTC-Zeitstempel) generiert, wenn die Zieldatenzeit erstellt wurde, während eine Rückwärts-Sommerzeit eingerichtet wurde (z. B. Ändern der Sommerzeit durch Entfernen einer Stunde).

    Wenn Sie eine falsche Angabe machen, is_dstwird natürlich nur bei DST-Überlappung oder Löchern eine falsche Zeit (und ein falscher UTC-Zeitstempel) generiert. Und wenn auch eine falsche Zeit angegeben wird, gibt das Auftreten in "Löchern" (Zeit, die aufgrund der Vorwärtsverschiebung der Sommerzeit nie existierte) is_dsteine Interpretation darüber, wie diese falsche Zeit zu berücksichtigen ist, und dies ist der einzige Fall, in dem .normalize(..) hier tatsächlich etwas getan wird. da es dann als tatsächlich gültige Zeit übersetzt wird (Ändern der Datum / Uhrzeit UND des DST-Objekts, falls erforderlich). Beachten Sie, dass dies .normalize()nicht erforderlich ist, um am Ende einen korrekten UTC-Zeitstempel zu haben. Dies wird jedoch wahrscheinlich empfohlen, wenn Sie die Idee, falsche Zeiten in Ihren Variablen zu haben, nicht mögen, insbesondere wenn Sie diese Variable an anderer Stelle wiederverwenden.

    und VERMEIDEN SIE FOLGENDES : (vgl.: Datetime Timezone-Konvertierung mit Pytz )

    dt = dt.replace(tzinfo=timezone('Europe/Amsterdam'))  ## BAD !!
    

    Warum? weil .replace()ersetzt blind das tzinfoohne Berücksichtigung der Zielzeit und wählt ein schlechtes DST-Objekt. Während .localize()Anwendungen der Zielzeit und Ihr is_dstdas Recht DST Objekt auszuwählen Hinweis.

ALTE falsche Antwort (danke @JFSebastien für das Aufrufen):

Hoffentlich ist es ziemlich einfach, die Zeitzone (Ihren lokalen Ursprung) zu erraten, wenn Sie Ihr naives datetimeObjekt erstellen, da es mit der Systemkonfiguration zusammenhängt, die Sie hoffentlich NICHT zwischen der naiven Datums- / Uhrzeit-Objekterstellung und dem Zeitpunkt ändern würden, an dem Sie das erhalten möchten UTC-Zeitstempel. Dieser Trick kann verwendet werden, um eine unvollständige Frage zu stellen.

Mit verwenden können time.mktimewir eine erstellen utc_mktime:

def utc_mktime(utc_tuple):
    """Returns number of seconds elapsed since epoch

    Note that no timezone are taken into consideration.

    utc tuple must be: (year, month, day, hour, minute, second)

    """

    if len(utc_tuple) == 6:
        utc_tuple += (0, 0, 0)
    return time.mktime(utc_tuple) - time.mktime((1970, 1, 1, 0, 0, 0, 0, 0, 0))

def datetime_to_timestamp(dt):
    """Converts a datetime object to UTC timestamp"""

    return int(utc_mktime(dt.timetuple()))

Sie müssen sicherstellen, dass Ihr datetimeObjekt in derselben Zeitzone erstellt wird wie das , in dem Sie Ihr Objekt erstellt haben datetime.

Diese letzte Lösung ist falsch, da davon ausgegangen wird, dass der UTC-Offset von jetzt an der gleiche ist wie der UTC-Offset von EPOCH. Dies ist bei vielen Zeitzonen nicht der Fall (zu einem bestimmten Zeitpunkt des Jahres für die Sommerzeit-Offsets (DST)).

Vaab
quelle
4
Das naive Datum / Uhrzeit-Objekt sollte immer die Zeit in UTC darstellen. Andere Zeitzonen sollten nur für E / A (Anzeige) verwendet werden. Es gibt eine datetime.timestamp()Methode in Python 3.3.
JFS
2
time.mktime()sollte nur für die Ortszeit verwendet werden. calendar.timegm()könnte verwendet werden, um utc time tuple in posix timestamp umzuwandeln. Oder besser noch nur datetime-Methoden verwenden. Siehe meine Antwort
jfs
4
-1. Ihr Code geht davon aus, dass utc_offset (jetzt) ​​und utc_offset (Epoche) in der lokalen Zeitzone identisch sind. In 116 Zeitzonen (von 430 üblichen Zeitzonen) ist dies nicht der Fall.
JFS
1
immer noch -1: Nicht .replace()mit einer Zeitzone verwenden, die einen nicht festen utc-Offset hat, wie z 'Europe/Amsterdam'. Siehe Datetime Timezone-Konvertierung mit Pytz .
JFS
1
1- Verstehst du, warum du nicht verwenden solltest .replace(tzinfo=get_localzone())? 2- timegm()kehrt intbereits zurück. Keine Notwendigkeit, es mit zu wickeln int. Auch .timetuple()Tropfen Bruchteile einer Sekunde.
JFS
30

Eine andere Möglichkeit ist:

d = datetime.datetime.utcnow()
epoch = datetime.datetime(1970,1,1)
t = (d - epoch).total_seconds()

Dies funktioniert, da sowohl "d" als auch "epoch" naive Datumsangaben sind, wodurch der Operator "-" gültig wird und ein Intervall zurückgegeben wird. total_seconds()wandelt das Intervall in Sekunden um. Beachten Sie, dass total_seconds()sogar ein Float zurückgegeben wirdd.microsecond == 0

Chris Cogdon
quelle
12
Nun, nicht wirklich, die Idee ist dieselbe, aber diese ist leichter zu verstehen :)
Natim
3
Sie würden denken, es würde eine einzige Methode in der Zeitbibliothek geben oder so ... meine Güte
Worte für den
Um den Zeitstempel zu erhalten, führen Sie datetime.datetime.utcnow (). Timestamp ()
Eugene
21

Beachten Sie auch die Funktion calendar.timegm () , wie in diesem Blogeintrag beschrieben:

import calendar
calendar.timegm(utc_timetuple)

Die Ausgabe sollte mit der Lösung von Vaab übereinstimmen.

Herr Herr
quelle
13

Wenn sich das eingegebene Datum / Uhrzeit-Objekt in UTC befindet:

>>> dt = datetime(2008, 1, 1, 0, 0, 0, 0)
>>> timestamp = (dt - datetime(1970, 1, 1)).total_seconds()
1199145600.0

Hinweis: Es wird float zurückgegeben, dh Mikrosekunden werden als Sekundenbruchteile dargestellt.

Wenn sich das Eingabedatum in UTC befindet:

>>> from datetime import date
>>> utc_date = date(2008, 1, 1)
>>> timestamp = (utc_date.toordinal() - date(1970, 1, 1).toordinal()) * 24*60*60
1199145600

Weitere Informationen finden Sie unter Konvertieren von datetime.date in UTC-Zeitstempel in Python .

jfs
quelle
8

Ich denke, die Hauptantwort ist immer noch nicht so klar, und es lohnt sich, sich die Zeit zu nehmen, um Zeit und Zeitzonen zu verstehen .

Das Wichtigste im Umgang mit Zeit ist, dass Zeit relativ ist !

  • 2017-08-30 13:23:00: (eine naive Datumszeit), repräsentiert eine Ortszeit irgendwo auf der Welt, aber beachten Sie, dass 2017-08-30 13:23:00in London NICHT DIE GLEICHE ZEIT ist wie 2017-08-30 13:23:00in San Francisco.

Da dieselbe Zeitzeichenfolge je nach Standort auf der Welt als unterschiedliche Zeitpunkte interpretiert werden kann, ist ein Absolutwert erforderlich Zeitbegriff .

Ein UTC-Zeitstempel ist eine Zahl in Sekunden (oder Millisekunden) ab Epoche (definiert als 1 January 1970 00:00:00atGMT Zeitzone +00: 00 - Offset).

Die Epoche ist in der GMT-Zeitzone verankert und daher ein absoluter Zeitpunkt. Ein UTC-Zeitstempel , der ein Versatz von einer absoluten Zeit ist, definiert daher einen absoluten Zeitpunkt .

Dadurch ist es möglich, Ereignisse rechtzeitig zu bestellen.

Ohne Zeitzoneninformationen ist die Zeit relativ und kann nicht in einen absoluten Zeitbegriff umgewandelt werden, ohne einen Hinweis darauf zu geben, in welcher Zeitzone die naive Datumszeit verankert werden soll.

Welche Arten von Zeit werden im Computersystem verwendet?

  • naive datetime : normalerweise zur Anzeige in der Ortszeit (dh im Browser), wo das Betriebssystem dem Programm Zeitzoneninformationen bereitstellen kann.

  • UTC-Zeitstempel : Ein UTC-Zeitstempel ist, wie oben erwähnt, ein absoluter Zeitpunkt, der jedoch in einer bestimmten Zeitzone verankert ist. Daher kann ein UTC-Zeitstempel in jeder Zeitzone in eine Datumszeit konvertiert werden, enthält jedoch keine Zeitzoneninformationen. Was bedeutet das? Das bedeutet, dass 1504119325 2017-08-30T18:55:24Zoder 2017-08-30T17:55:24-0100oder auch entspricht 2017-08-30T10:55:24-0800. Es sagt Ihnen nicht, woher die aufgezeichnete Datums- und Uhrzeitangabe stammt. Es ist in der Regel auf der Serverseite zu zeichnen Ereignisse (Protokolle, etc ...) oder verwendet eine konvertieren Zeitzone bewusst Datetime zu einem absoluten Zeitpunkt und Rechenzeitdifferenzen .

  • ISO-8601-Datums- / Uhrzeitzeichenfolge : ISO-8601 ist ein standardisiertes Format zum Aufzeichnen von Datums- und Uhrzeitangaben mit Zeitzone. (Es gibt tatsächlich mehrere Formate, lesen Sie hier weiter: https://en.wikipedia.org/wiki/ISO_8601 ) Es wird verwendet, um zeitzonenbezogene Datums- / Uhrzeitinformationen auf serialisierbare Weise zwischen Systemen zu kommunizieren.

Wann welche verwenden? oder eher wann müssen Sie sich um Zeitzonen kümmern?

  • Wenn Sie sich in irgendeiner Weise um die Tageszeit kümmern müssen, benötigen Sie Zeitzoneninformationen. Ein Kalender oder Alarm benötigt eine Tageszeit, um ein Meeting zur richtigen Tageszeit für jeden Benutzer auf der Welt festzulegen. Wenn diese Daten auf einem Server gespeichert werden, muss der Server wissen, welcher Zeitzone die Datumszeit entspricht.

  • Um Zeitunterschiede zwischen Ereignissen zu berechnen, die von verschiedenen Orten auf der Welt kommen, reicht der UTC-Zeitstempel aus. Sie können jedoch nicht mehr analysieren, zu welcher Tageszeit Ereignisse aufgetreten sind (z. B. für Webanalysen möchten Sie möglicherweise wissen, wann Benutzer zu Ihnen kommen Website in ihrer Ortszeit : Sehen Sie morgens oder abends mehr Benutzer? Ohne Informationen zur Tageszeit können Sie das nicht herausfinden.

Zeitzonenversatz in einer Datumszeichenfolge :

Ein weiterer wichtiger Punkt ist, dass der Zeitzonenversatz in einer Datumszeichenfolge nicht festgelegt ist . Das heißt, weil 2017-08-30T10:55:24-0800sagt der Offset-0800 oder 8 Stunden zurück , heißt das nicht, dass es immer sein wird!

Im Sommer kann es durchaus Sommerzeit sein, und das wäre es auch -0700

Dies bedeutet, dass der Zeitzonenversatz (+0100) nicht mit dem Zeitzonennamen (Europa / Frankreich) oder sogar der Zeitzonenbezeichnung (MEZ) identisch ist.

America/Los_AngelesDie Zeitzone ist ein Ort auf der Welt , wird jedoch PSTim Winter zur Zeitzonen-Offset-Notation (Pacific Standard Time) und PDTim Sommer zur (Pacific Daylight Time).

Zusätzlich zum Abrufen des Zeitzonenversatzes vom Datenring sollten Sie auch den Zeitzonennamen erhalten, um genau zu sein.

Die meisten Pakete sind in der Lage, numerische Offsets von der Sommerzeit selbst in die Standardzeit umzuwandeln, aber das ist nicht unbedingt trivial, wenn nur der Offset angegeben wird. Zum Beispiel ist die WATZeitzonenbezeichnung in Westafrika genau wie UTC + 0100CET Zeitzone in Frankreich, aber Frankreich beobachtet die Sommerzeit, während Westafrika dies nicht tut (weil sie nahe am Äquator liegen).

Kurz gesagt, es ist kompliziert. SEHR kompliziert, und deshalb sollten Sie dies nicht selbst tun, sondern einem Paket vertrauen, das es für Sie erledigt, und es auf dem neuesten Stand halten!

MrE
quelle
Siehe meinen Blog-Beitrag über Datum und Uhrzeit in Python, um die Fallstricke der verschiedenen Pakete zu verstehen. medium.com/@eleroy/…
MrE
3

Eine einfache Lösung ohne externe Module:

from datetime import datetime, timezone

dt = datetime(2008, 1, 1, 0, 0, 0, 0)
int(dt.replace(tzinfo=timezone.utc).timestamp())
Mike Siomkin
quelle
1

Ich denke, die richtige Art, Ihre Frage zu formulieren, ist Is there a way to get the timestamp by specifying the date in UTC?, weil der Zeitstempel nur eine Zahl ist, die absolut und nicht relativ ist. Das relative (oder zeitzonenbezogene) Stück ist das Datum.

Ich finde Pandas sehr praktisch für Zeitstempel, also:

import pandas as pd
dt1 = datetime(2008, 1, 1, 0, 0, 0, 0)
ts1 = pd.Timestamp(dt1, tz='utc').timestamp()
# make sure you get back dt1
datetime.utcfromtimestamp(ts1)  
Itamar Katz
quelle
Die Verwendung von Pandas ist meiner Meinung nach der richtige Ansatz, für die aktuelle Zeit gibt es auch t = Timestamp.utcnow (), um direkt die richtige Zeit zu erhalten :)
ntg
0

Die akzeptierte Antwort scheint für mich nicht zu funktionieren. Meine Lösung:

import time
utc_0 = int(time.mktime(datetime(1970, 01, 01).timetuple()))
def datetime2ts(dt):
    """Converts a datetime object to UTC timestamp"""
    return int(time.mktime(dt.utctimetuple())) - utc_0
Traumwolke
quelle
es schlägt fehl, wenn der aktuelle ( dt) UTC-Offset der lokalen Zeitzone und 1970 unterschiedlich ist. mktime()erwartet Ortszeit.
JFS
0

Einfachster Weg:

>>> from datetime import datetime
>>> dt = datetime(2008, 1, 1, 0, 0, 0, 0)
>>> dt.strftime("%s")
'1199163600'

Bearbeiten: @Daniel ist korrekt, dies würde es in die Zeitzone der Maschine konvertieren. Hier ist eine überarbeitete Antwort:

>>> from datetime import datetime, timezone
>>> epoch = datetime(1970, 1, 1, 0, 0, 0, 0, timezone.utc)
>>> dt = datetime(2008, 1, 1, 0, 0, 0, 0, timezone.utc)
>>> int((dt-epoch).total_seconds())
'1199145600'

Tatsächlich muss es nicht einmal angegeben werden timezone.utc, da der Zeitunterschied gleich ist, solange beide datetimedieselbe Zeitzone (oder keine Zeitzone) haben.

>>> from datetime import datetime
>>> epoch = datetime(1970, 1, 1, 0, 0, 0, 0)
>>> dt = datetime(2008, 1, 1, 0, 0, 0, 0)
>>> int((dt-epoch).total_seconds())
1199145600
Mike Furlender
quelle
Diese Methode gibt utc nicht zurück, sondern passt die Datum / Uhrzeit an die aktuelle Zeitzone an. dh. Wenn jetzt 12 Uhr in tz +3 ist, wird es in der Epoche 9 Uhr zurückgeben.
Daniel Dubovski
Ah du hast recht Meine Zeitzone war UTC - deshalb hat es funktioniert.
Mike Furlender
Wenn Sie das timezone.utcObjekt (Python 3.2 und neuer) verwenden möchten, verwenden Sie es einfach mit .timestamp(): datetime(2008, 1, 1, tzinfo=timezone.utc).timestamp(). Keine Notwendigkeit, ein Epochenobjekt zu erstellen und zu subtrahieren.
Martijn Pieters