Konvertieren von datetime.date in UTC-Zeitstempel in Python

295

Ich habe es mit Datumsangaben in Python zu tun und muss sie in UTC-Zeitstempel konvertieren, um sie in Javascript zu verwenden. Der folgende Code funktioniert nicht:

>>> d = datetime.date(2011,01,01)
>>> datetime.datetime.utcfromtimestamp(time.mktime(d.timetuple()))
datetime.datetime(2010, 12, 31, 23, 0)

Das Konvertieren des Datumsobjekts zuerst in datetime hilft ebenfalls nicht. Ich habe das Beispiel unter diesem Link ausprobiert , aber:

from pytz import utc, timezone
from datetime import datetime
from time import mktime
input_date = datetime(year=2011, month=1, day=15)

und jetzt entweder:

mktime(utc.localize(input_date).utctimetuple())

oder

mktime(timezone('US/Eastern').localize(input_date).utctimetuple())

funktioniert.

Also allgemeine Frage: Wie kann ich ein Datum nach UTC in Sekunden seit der Epoche umrechnen lassen?

Andreas Jung
quelle
Mögliches Duplikat von Wie konvertiere ich die Ortszeit in Python in UTC?
Piotr Dobrogost
29
Ich bin mir nicht sicher, ob ich damit einverstanden bin, es als Duplikat zu markieren. Während die Lösungen ähnlich sind, sind die Fragen nicht. Einer (dieser) versucht, einen Zeitstempel aus a zu erstellen datetime.date, der andere versucht, eine Zeichenfolgendarstellung von einer Zeitzone in eine andere zu konvertieren. Als jemand, der nach einer Lösung für dieses Problem sucht, kann ich möglicherweise nicht den Schluss ziehen, dass letzteres die Antwort liefert, nach der ich suche.
DRH
5
Datum / Uhrzeit (Datum.Jahr, Datum.Monat, Datum.Tag) .Zeitstempel ()
Julian
4
Mögliches Duplikat von In Python, wie konvertiert man ein "datetime" -Objekt in Sekunden?
Trevor Boyd Smith

Antworten:

462

Wenn d = date(2011, 1, 1)in UTC ist:

>>> from datetime import datetime, date
>>> import calendar
>>> timestamp1 = calendar.timegm(d.timetuple())
>>> datetime.utcfromtimestamp(timestamp1)
datetime.datetime(2011, 1, 1, 0, 0)

Wenn din der lokalen Zeitzone:

>>> import time
>>> timestamp2 = time.mktime(d.timetuple()) # DO NOT USE IT WITH UTC DATE
>>> datetime.fromtimestamp(timestamp2)
datetime.datetime(2011, 1, 1, 0, 0)

timestamp1und timestamp2kann abweichen, wenn Mitternacht in der lokalen Zeitzone nicht dieselbe Zeitinstanz wie Mitternacht in UTC ist.

mktime()kann ein falsches Ergebnis zurückgeben, wenn dies deiner mehrdeutigen Ortszeit entspricht (z. B. während des DST-Übergangs) oder wenn des sich um ein vergangenes (zukünftiges) Datum handelt, an dem der UTC-Offset möglicherweise anders war und das C mktime()keinen Zugriff auf die tz-Datenbank auf der angegebenen Plattform hat . Sie können das pytzModul (z. B. via tzlocal.get_localzone()) verwenden, um auf allen Plattformen Zugriff auf die tz-Datenbank zu erhalten . Auch utcfromtimestamp()kann fehlschlagen und mktime()kann nicht-POSIX - Zeitstempel zurück , wenn "right"Zeitzone verwendet wird .


So konvertieren Sie ein datetime.dateObjekt, das das Datum in UTC darstellt, ohne calendar.timegm():

DAY = 24*60*60 # POSIX day in seconds (exact value)
timestamp = (utc_date.toordinal() - date(1970, 1, 1).toordinal()) * DAY
timestamp = (utc_date - date(1970, 1, 1)).days * DAY

Wie kann ich ein Datum nach UTC in Sekunden seit der Epoche umrechnen lassen?

Konvertieren von datetime.datetime(nicht datetime.date) Objekten, die bereits die Zeit in UTC darstellen, in den entsprechenden POSIX-Zeitstempel (a float).

Python 3.3+

datetime.timestamp()::

from datetime import timezone

timestamp = dt.replace(tzinfo=timezone.utc).timestamp()

Hinweis: Es muss timezone.utcexplizit angegeben werden, andernfalls wird .timestamp()davon ausgegangen, dass sich Ihr naives datetime-Objekt in der lokalen Zeitzone befindet.

Python 3 (<3.3)

Aus den Dokumenten für datetime.utcfromtimestamp():

Es gibt keine Methode, um den Zeitstempel von einer datetime-Instanz abzurufen, aber der POSIX-Zeitstempel, der einer datetime-Instanz dt entspricht, kann wie folgt einfach berechnet werden. Für einen naiven dt:

timestamp = (dt - datetime(1970, 1, 1)) / timedelta(seconds=1)

Und für einen bewussten dt:

timestamp = (dt - datetime(1970,1,1, tzinfo=timezone.utc)) / timedelta(seconds=1)

Interessante Lektüre: Epochenzeit vs. Tageszeit über den Unterschied zwischen Wie spät ist es? und wie viele Sekunden sind vergangen?

Siehe auch: datetime benötigt eine "Epochen" -Methode

Python 2

So passen Sie den obigen Code für Python 2 an:

timestamp = (dt - datetime(1970, 1, 1)).total_seconds()

Dabei timedelta.total_seconds()entspricht dies der (td.microseconds + (td.seconds + td.days * 24 * 3600) * 10**6) / 10**6Berechnung mit aktivierter wahrer Division.

Beispiel

from __future__ import division
from datetime import datetime, timedelta

def totimestamp(dt, epoch=datetime(1970,1,1)):
    td = dt - epoch
    # return td.total_seconds()
    return (td.microseconds + (td.seconds + td.days * 86400) * 10**6) / 10**6 

now = datetime.utcnow()
print now
print totimestamp(now)

Vorsicht vor Gleitkomma-Problemen .

Ausgabe

2012-01-08 15:34:10.022403
1326036850.02

So konvertieren Sie ein bewusstes datetimeObjekt in einen POSIX-Zeitstempel

assert dt.tzinfo is not None and dt.utcoffset() is not None
timestamp = dt.timestamp() # Python 3.3+

Auf Python 3:

from datetime import datetime, timedelta, timezone

epoch = datetime(1970, 1, 1, tzinfo=timezone.utc)
timestamp = (dt - epoch) / timedelta(seconds=1)
integer_timestamp = (dt - epoch) // timedelta(seconds=1)

Auf Python 2:

# utc time = local time              - utc offset
utc_naive  = dt.replace(tzinfo=None) - dt.utcoffset()
timestamp = (utc_naive - datetime(1970, 1, 1)).total_seconds()
jfs
quelle
2
Warum nicht für den Fall Python 2 : timestamp = (dt - datetime.fromtimestamp(0)).total_seconds()?
m01
7
@ m01: datetime(1970, 1, 1)ist expliziter. fromtimestamp()ist hier falsch ( dtist in UTC und utcfromtimestamp()sollte stattdessen verwendet werden).
JFS
1
@ Fedorqui Blick auf totimestamp()Funktion in der Antwort.
JFS
14
So sehr ich Python liebe, ist seine Datums- / Zeitbibliothek ernsthaft gebrochen.
Realfun
3
@ Realfun: Zeitzonen, Sommerzeitübergänge, die tz-Datenbank, Schaltsekunden existieren unabhängig von Python.
JFS
81

Nur für Unix-Systeme :

>>> import datetime
>>> d = datetime.date(2011,01,01)
>>> d.strftime("%s")  # <-- THIS IS THE CODE YOU WANT
'1293832800'

Anmerkung 1: Dizzyf stellte fest, dass dies lokalisierte Zeitzonen anwendet . Nicht in der Produktion verwenden.

Anmerkung 2: Jakub Narębski stellte fest, dass dies Zeitzoneninformationen selbst für versatzbewusste Datums- und Uhrzeitangaben ignoriert (getestet für Python 2.7).

Ulf Aslak
quelle
4
Eine gute Antwort, wenn Sie wissen, unter welchem ​​System Ihr Code ausgeführt wird. Beachten Sie jedoch, dass die Formatzeichenfolge '% s' nicht auf allen Betriebssystemen vorhanden ist, sodass dieser Code nicht portierbar ist. Wenn Sie überprüfen möchten, ob es unterstützt wird, können Sie man strftimeUnix-ähnliche Systeme überprüfen .
Alice Heaton
5
Es sollte erwähnt werden, dass dies den Bruchteil der Sekunden (Mikrosekunden oder was auch immer) fallen lässt.
Alfe
11
WARNUNG: Dies gilt für lokalisierte Zeitzonen! Sie erhalten je nach Maschinenzeit ein unterschiedliches Strftime-Verhalten für identische Datetime-Objekte
dizzyf
3
Darüber hinaus werden Zeitzoneninformationen ignoriert und es wird davon ausgegangen, dass sich die Datumszeit auch für die Offset-fähige Datumszeit in der lokalen Zeitzone befindet , wobei tzinfo festgelegt ist. Zumindest in Python 2.7.
Jakub Narębski
1
Javascript Zeitstempel = Python Zeitstempel * 1000
Trinh Hoang Nhu
38
  • Annahme 1: Sie versuchen, ein Datum in einen Zeitstempel umzuwandeln. Da ein Datum jedoch einen Zeitraum von 24 Stunden abdeckt, gibt es keinen einzigen Zeitstempel, der dieses Datum darstellt. Ich gehe davon aus, dass Sie den Zeitstempel dieses Datums um Mitternacht (00: 00: 00.000) darstellen möchten.

  • Annahme 2: Das von Ihnen angegebene Datum ist keiner bestimmten Zeitzone zugeordnet. Sie möchten jedoch den Versatz von einer bestimmten Zeitzone (UTC) bestimmen. Ohne Kenntnis der Zeitzone, in der sich das Datum befindet, ist es nicht möglich, einen Zeitstempel für eine bestimmte Zeitzone zu berechnen. Ich gehe davon aus, dass Sie das Datum so behandeln möchten, als ob es in der Zeitzone des lokalen Systems liegt.

Zunächst können Sie die Datumsinstanz mithilfe des Elements in ein Tupel konvertieren, das die verschiedenen Zeitkomponenten darstellt timetuple():

dtt = d.timetuple() # time.struct_time(tm_year=2011, tm_mon=1, tm_mday=1, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=5, tm_yday=1, tm_isdst=-1)

Sie können dies dann in einen Zeitstempel konvertieren, indem Sie time.mktime:

ts = time.mktime(dtt) # 1293868800.0

Sie können diese Methode überprüfen, indem Sie sie mit der Epochenzeit selbst (1970-01-01) testen. In diesem Fall sollte die Funktion den Zeitzonenversatz für die lokale Zeitzone an diesem Datum zurückgeben:

d = datetime.date(1970,1,1)
dtt = d.timetuple() # time.struct_time(tm_year=1970, tm_mon=1, tm_mday=1, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=3, tm_yday=1, tm_isdst=-1)
ts = time.mktime(dtt) # 28800.0

28800.0 beträgt 8 Stunden, was für die pazifische Zeitzone (in der ich mich befinde) korrekt wäre.

DRH
quelle
Ich bin mir nicht sicher, warum dies abgelehnt wurde. Es behebt das Problem des OP (den Arbeitscode, den das OP als "nicht funktionierend" bezeichnet). Es beantwortet meine Frage nicht (konvertiere UTC datetime.datetime in timestamp), aber immer noch… upvoting.
Thanatos
9
Achtung. Die Annahme, dass "Sie das Datum so behandeln möchten, als ob es sich in der Zeitzone des lokalen Systems befindet, ist die Wurzel aller Probleme mit der Zeitzone in Python. Es sei denn, Sie sind sich zu 100% sicher, dass der Computer lokalisiert ist, auf dem Ihr Skript ausgeführt wird, insbesondere Wenn Sie Kunden bedienen, die von überall auf der Welt kommen können, gehen Sie IMMER davon aus, dass die Daten in UTC liegen, und führen Sie die Konvertierung so früh wie möglich durch. Sie werden die Haare auf dem Kopf halten, vertrauen Sie mir.
Romain G
8

Folgen Sie dem python2.7-Dokument. Sie müssen calendar.timegm () anstelle von time.mktime () verwenden.

>>> d = datetime.date(2011,01,01)
>>> datetime.datetime.utcfromtimestamp(calendar.timegm(d.timetuple()))
datetime.datetime(2011, 1, 1, 0, 0)
Wang
quelle
3
Wie unterscheidet es sich von meiner Antwort, wenn des in UTC ist?
JFS
8

Ich habe meine eigenen zwei Funktionen definiert

  • utc_time2datetime (utc_time, tz = Keine)
  • datetime2utc_time (datetime)

Hier:

import time
import datetime
from pytz import timezone
import calendar
import pytz


def utc_time2datetime(utc_time, tz=None):
    # convert utc time to utc datetime
    utc_datetime = datetime.datetime.fromtimestamp(utc_time)

    # add time zone to utc datetime
    if tz is None:
        tz_datetime = utc_datetime.astimezone(timezone('utc'))
    else:
        tz_datetime = utc_datetime.astimezone(tz)

    return tz_datetime


def datetime2utc_time(datetime):
    # add utc time zone if no time zone is set
    if datetime.tzinfo is None:
        datetime = datetime.replace(tzinfo=timezone('utc'))

    # convert to utc time zone from whatever time zone the datetime is set to
    utc_datetime = datetime.astimezone(timezone('utc')).replace(tzinfo=None)

    # create a time tuple from datetime
    utc_timetuple = utc_datetime.timetuple()

    # create a time element from the tuple an add microseconds
    utc_time = calendar.timegm(utc_timetuple) + datetime.microsecond / 1E6

    return utc_time
Agittarius
quelle
1
Ich blätterte direkt an Ihrem Beispiel vorbei. Viel zu chaotisch und kompliziert für so eine einfache Sache. Überhaupt nicht pythonisch.
Wütend 84
@ Mayhem: Ich habe es ein wenig aufgeräumt und Kommentare hinzugefügt. Wenn Sie eine bessere und allgemeinere Lösung für die Konvertierung von Zeit zu Datum und Uhrzeit haben und in der Lage sind, die Zeitzone festzulegen, teilen Sie uns dies bitte mit. Lassen Sie mich auch wissen, wie ein pythonischeres Beispiel für meinen Code aussehen sollte.
Agittarius
3

Die Frage ist etwas verwirrt. Zeitstempel sind nicht UTC - sie sind eine Unix-Sache. das Datum könnte UTC sein? Angenommen, dies ist der Fall, und wenn Sie Python 3.2+ verwenden, macht das einfache Datum dies trivial:

>>> SimpleDate(date(2011,1,1), tz='utc').timestamp
1293840000.0

Wenn Sie tatsächlich das Jahr, den Monat und den Tag haben, müssen Sie nicht Folgendes erstellen date:

>>> SimpleDate(2011,1,1, tz='utc').timestamp
1293840000.0

und wenn sich das Datum in einer anderen Zeitzone befindet (dies ist wichtig, da wir Mitternacht ohne zugehörige Zeit annehmen ):

>>> SimpleDate(date(2011,1,1), tz='America/New_York').timestamp
1293858000.0

[Die Idee hinter simple-date ist, alle Datums- und Zeitangaben von Python in einer konsistenten Klasse zu sammeln, damit Sie jede Konvertierung durchführen können. so wird es zum Beispiel auch in die andere Richtung gehen:

>>> SimpleDate(1293858000, tz='utc').date
datetime.date(2011, 1, 1)

]]

Andrew Cooke
quelle
SimpleDate(date(2011,1,1), tz='America/New_York')erhöht NoTimezone, während pytz.timezone('America/New_York')keine Ausnahmen ausgelöst werden ( simple-date==0.4.8, pytz==2014.7).
JFS
Ich erhalte eine Fehlermeldung pip install simple-date, es sieht so aus, als wäre es nur Python3 / Pip3.
NoBugs
3

Verwenden des Pfeilpakets :

>>> import arrow
>>> arrow.get(2010, 12, 31).timestamp
1293753600
>>> time.gmtime(1293753600)
time.struct_time(tm_year=2010, tm_mon=12, tm_mday=31, 
    tm_hour=0, tm_min=0, tm_sec=0, 
    tm_wday=4, tm_yday=365, tm_isdst=0)
Mathieu Longtin
quelle
Hinweis: arrowVerwendet dateutil und dateutilkennt seit vielen Jahren Fehler im Zusammenhang mit der Zeitzonenbehandlung. Verwenden Sie es nicht, wenn Sie korrekte Ergebnisse für Zeitzonen mit einem nicht festen UTC-Versatz benötigen (es ist in Ordnung, es für die UTC-Zeitzone zu verwenden, aber die stdlib behandelt auch den UTC-Fall in Ordnung).
JFS
@JFSebastian Dieser Fehler tritt nur während eines Übergangs in einer mehrdeutigen Zeit auf.
Paul
Sieht aus wie der Fehler am 28. März behoben wurde
Mathieu Longtin
Sieht so aus, als wäre es die beste und pythonübergreifende Lösung. Verwenden Sie einfach den Pfeil . Danke;)
maxkoryukov
@ MathieuLongtin dateutil kann andere Probleme haben
jfs
1

Eine vollständige Zeitzeichenfolge enthält:

  • Datum
  • Zeit
  • utcoffset [+HHMM or -HHMM]

Beispielsweise:

1970-01-01 06:00:00 +0500 == 1970-01-01 01:00:00 +0000 == UNIX timestamp:3600

$ python3
>>> from datetime import datetime
>>> from calendar import timegm
>>> tm = '1970-01-01 06:00:00 +0500'
>>> fmt = '%Y-%m-%d %H:%M:%S %z'
>>> timegm(datetime.strptime(tm, fmt).utctimetuple())
3600

Hinweis:

UNIX timestampist eine Gleitkommazahl, die in Sekunden seit der Epoche in UTC ausgedrückt wird .


Bearbeiten:

$ python3
>>> from datetime import datetime, timezone, timedelta
>>> from calendar import timegm
>>> dt = datetime(1970, 1, 1, 6, 0)
>>> tz = timezone(timedelta(hours=5))
>>> timegm(dt.replace(tzinfo=tz).utctimetuple())
3600
kev
quelle
6
Und wie beantwortet das meine Frage?
Andreas Jung
1
@ user908088 Convert 1970-01-01 06:00:00 +0500zu , 3600wie Sie gefragt.
Kev
1
@ user908088 Es gibt kein timezoneIn python2, Sie können die Berechnung ( 06:00:00- +0500= 01:00:00) manuell durchführen.
Kev
5
warum diese Antwort oben ist, obwohl sie -1 Stimmen hat, stimmt etwas nicht mit SO
Umair
1

Wenn Sie ein datetimeObjekt namens haben d, verwenden Sie Folgendes, um den Zeitstempel in UTC abzurufen:

d.strftime("%Y-%m-%dT%H:%M:%S.%fZ")

Verwenden Sie für die entgegengesetzte Richtung Folgendes:

d = datetime.strptime("2008-09-03T20:56:35.450686Z", "%Y-%m-%dT%H:%M:%S.%fZ")
Max
quelle
0

Ich bin beeindruckt von der tiefen Diskussion.

meine 2 Cent:

ab datetime import datetime import time

der zeitstempel in utc ist:

timestamp = \
(datetime.utcnow() - datetime(1970,1,1)).total_seconds()

oder,

timestamp = time.time()

Wenn jetzt aus datetime.now () resultiert, in derselben Sommerzeit

utcoffset = (datetime.now() - datetime.utcnow()).total_seconds()
timestamp = \
(now - datetime(1970,1,1)).total_seconds() - utcoffset
nicht bekannt gegeben
quelle