Konvertieren Sie datetime in Unix timestamp und konvertieren Sie es zurück in Python

183

Ich habe dt = datetime(2013,9,1,11)und möchte einen Unix-Zeitstempel für dieses Datum / Uhrzeit-Objekt erhalten.

Wenn ich das tue, (dt - datetime(1970,1,1)).total_seconds()bekomme ich den Zeitstempel 1378033200.

Beim Zurückkonvertieren habe datetime.fromtimestampich bekommen datetime.datetime(2013, 9, 1, 6, 0).

Die Stunde stimmt nicht überein. Was habe ich hier vermisst?

Brückenwasser
quelle
Nebenbei bemerkt, wenn Sie Python 3.3+ verwenden, möchten Sie die timestampMethode wirklich, wirklich verwenden , anstatt zu versuchen, es selbst zu tun. Zum einen wird dadurch die Möglichkeit, naive Zeiten von verschiedenen Zeitzonen zu subtrahieren, vollständig vermieden.
Abarnert
1
Woher kommt dtdas? Ist es eine Ortszeit oder eine Zeit in UTC?
JFS
2
@abarnert Ich möchte auch eine Anfrage einreichen, um alle Codepages und Unicode-Symbole zu löschen, dh alle Nicht-ASCII- und Nicht-Standard-Codepage-Sprachen zu verbieten. Das Malen von Symbolen ist weiterhin erlaubt.
Daniel F
6
@ DanielF: Anfrage abgelehnt. Ich bin nicht daran interessiert, hier eine Ein-Welt-Sprache zu schaffen, und selbst wenn wir das tun würden, würde ich historischen Linguisten und Tolkien-Gelehrten das Leben nicht unmöglich machen wollen. Unicode löst das Problem bereits, mit der Ausnahme, dass bestimmte Organisationen und Produkte (das TRON-Konsortium, japanische Software, die Shift-JIS über UTF-8 verwendet, Microsoft weiterhin ein Betriebssystem mit dem Standardwert cp1252 für Benutzertextdateien und verschiedene SDKs bereitstellen, die diese UTF vortäuschen) -16 ist ein Zeichensatz mit fester Breite und / oder dasselbe wie Unicode) muss bestraft werden, um sie in Einklang zu bringen.
Abarnert

Antworten:

103

Was Sie hier verpasst haben, sind Zeitzonen.

Vermutlich haben Sie fünf Stunden vor UTC, also sind 2013-09-01T11: 00: 00 local und 2013-09-01T06: 00: 00Z dieselbe Zeit.

Sie müssen den Anfang der datetimeDokumente lesen , in denen Zeitzonen sowie "naive" und "bewusste" Objekte erläutert werden.

Wenn Ihre ursprüngliche naive Datumszeit UTC war, können Sie sie utcfromtimestampanstelle von verwenden fromtimestamp.

Wenn andererseits Ihre ursprüngliche naive Datumszeit lokal war, hätten Sie keinen UTC-Zeitstempel davon subtrahieren sollen. Verwenden Sie datetime.fromtimestamp(0)stattdessen.

Wenn Sie ein bewusstes Datum / Uhrzeit-Objekt hatten, müssen Sie entweder eine lokale (bewusste) Epoche auf beiden Seiten verwenden oder explizit in und von UTC konvertieren.

Wenn Sie Python 3.3 oder höher haben oder auf dieses aktualisieren können, können Sie all diese Probleme vermeiden, indem Sie einfach die timestampMethode verwenden, anstatt herauszufinden, wie Sie es selbst tun können. Und selbst wenn Sie dies nicht tun, sollten Sie den Quellcode ausleihen .

(Und wenn Sie auf Python 3.4 warten können, sieht es so aus, als würde PEP 341 es wahrscheinlich in die endgültige Version schaffen, was bedeutet, dass all die Dinge, über die JF Sebastian und ich in den Kommentaren gesprochen haben, nur mit der stdlib und möglich sein sollten unter Unix und Windows gleich funktionieren.)

abarnert
quelle
1
Wenn dtes sich in der lokalen Zeitzone befindet, ist die Formel in der Frage falsch datetime.fromtimestamp(0)(Epoche in der aktuellen Zeitzone) sollte anstelle von datetime(1970, 1,1)(Unix-Epoche in UTC) verwendet werden.
JFS
@JFSebastian: Ich wollte nicht alle drei Möglichkeiten im Detail behandeln, aber ich denke, Sie haben Recht, ich sollte.
Abarnert
Übrigens kann dies fromtimestamp(0)fehlschlagen, wenn das System keine historischen Zeitzoneninformationen speichert, z. B. unter Windows. pytzkönnte in diesem Fall verwendet werden.
JFS
@JFSebastian: Aber pytzhilft nur, wenn Sie bereits wissen, in welcher Zeitzone Sie sich befinden. Um dies programmgesteuert zu tun, benötigen Sie eine andere Bibliothek, die die aktuelle Windows-Zeitzone abruft und in eine pytzZeitzone konvertiert und / oder nach Namen sucht.
Abarnert
Es gibt ein tzlocalModul, das auch unter Windows funktioniert. Hier erfahren Sie , wie Sie die UTC-Zeit in die Ortszeit umwandeln können .
JFS
141

Lösung ist

import time
import datetime
d = datetime.date(2015,1,5)

unixtime = time.mktime(d.timetuple())
DmitrySemenov
quelle
12
Es wird davon dausgegangen, dass es sich um ein naives Datums- / Datums- / Uhrzeitobjekt handelt, das die Ortszeit darstellt (es kann für mehrdeutige Zeiten oder für vergangene / zukünftige Daten fehlschlagen, wenn das Betriebssystem keine historische tz-Datenbank bereitstellt (der UTC-Offset war in der Vergangenheit möglicherweise anders als in der Ortszeit) Zeitzone)). Weitere Optionen .
JFS
6
Es sieht so aus, als hätte niemand etwas gegen Gleitkomma-Lösungen. Ist das für alle so offensichtlich?
Ivan Balashov
4
Dies verringert die Mikrosekunden. Könnte interessant sein.
Alfe
Das einzige Problem ist, dass Sie die Zeitzone nicht berücksichtigen.
Blairg23
es sollte nicht. Wenn Sie TZ anpassen müssen, müssen Sie dies zuerst tun.
Marcin Orlowski
69

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

>>> import datetime
>>> datetime.datetime(2012,04,01,0,0).strftime('%s')
'1333234800'
>>> (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 :

>>> import datetime
>>> datetime.datetime(2012,4,1,0,0).timestamp()
1333234800.0
Francisco Costa
quelle
5
Berücksichtigt keine Zeitzonen.
Blairg23
3
Sie möchten nicht verwenden %s, da es auf der Uhr des Systems lokalisiert ist, auf dem Sie sich gerade befinden. Sie sollten immer nur verwenden .timestamp(), um die richtige Epoch / UNIX-Zeit zu erhalten.
Blairg23
3
%sfunktioniert nicht auf Windows-Systemen ( ValueError: Invalid format string)
chrki
1
@ amitnair92 nur setzen 8oder9
Francisco Costa
54

Anstelle dieses Ausdrucks zum Erstellen eines POSIX-Zeitstempels aus dt,

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

Benutze das:

int(dt.strftime("%s"))

Ich bekomme die richtige Antwort in Ihrem Beispiel mit der zweiten Methode.

EDIT: Einige Follow-up ... Nach einigen Kommentaren (siehe unten) war ich neugierig auf den Mangel an Unterstützung oder Dokumentation für %sin strftime. Folgendes habe ich gefunden:

In der Python-Quelle für datetimeundtimeSTRFTIME_FORMAT_CODES sagt uns der String :

"Other codes may be available on your platform.
 See documentation for the C library strftime function."

Also jetzt, wenn wir man strftime (auf BSD-Systemen wie Mac OS X) Unterstützung finden für %s:

"%s is replaced by the number of seconds since the Epoch, UTC (see mktime(3))."

Aus diesem Grund %sfunktioniert es auf den Systemen, die es verwendet. Es gibt jedoch bessere Lösungen für das Problem von OP (die Zeitzonen berücksichtigen). Siehe @ abarnerts akzeptierte Antwort hier.

Darren Stone
quelle
4
Dies ist undokumentiertes Verhalten (glaube ich). Unter Windows führt dies beispielsweise zu einer "ungültigen Formatzeichenfolge".
Crescent Fresh
@CrescentFresh, interessant. Du könntest Recht haben. Obwohl ich dies nicht strftime("%s")in der Dokumentation sehe , habe ich dies nur für Mac und Linux bestätigt. Vielen Dank.
Darren Stone
1
anscheinend ignoriert es das tzinfo-Feld.
Daniel F
1
@DarrenStone: Sie müssen die Quelle nicht lesen. Sowohl time.strftime()und datetime.strftimedie an die Plattformen delegierte Dokumentation strftime(3)funktionieren für nicht unterstützte Anweisungen. %skann sogar unter Mac OS X fehlschlagen, z. B. sollte datetime.strftime ('% s') tzinfo berücksichtigen .
JFS
1
Sie sollten niemals verwenden, %sda Sie nur die lokalisierte Systemzeit des Systems verwenden, auf dem Sie sich befinden. Sie möchten verwenden, .timestamp()wenn Sie versuchen, den tatsächlichen UNIX-Zeitstempel abzurufen.
Blairg23
6

Für die Arbeit mit UTC-Zeitzonen:

time_stamp = calendar.timegm(dt.timetuple())

datetime.utcfromtimestamp(time_stamp)
Emin Temiz
quelle
Nach einer Stunde der Suche war dies die einzige Antwort, die funktionierte: ')
Qurashi
4

Sie haben die Zeitzoneninformationen verpasst (bereits beantwortet, vereinbart)

arrowPaket ermöglicht es, diese Folter mit datetimes zu vermeiden; Es ist bereits geschrieben, getestet, pypi-veröffentlicht, Cross-Python (2.6 - 3.xx).

Alles was Sie brauchen: pip install arrow(oder zu Abhängigkeiten hinzufügen)

Lösung für Ihren Fall

dt = datetime(2013,9,1,11)
arrow.get(dt).timestamp
# >>> 1378033200

bc = arrow.get(1378033200).datetime
print(bc)
# >>> datetime.datetime(2013, 9, 1, 11, 0, tzinfo=tzutc())
print(bc.isoformat())
# >>> '2013-09-01T11:00:00+00:00'
maxkoryukov
quelle
3

Wenn Ihr datetime-Objekt die UTC-Zeit darstellt, verwenden Sie time.mktime nicht, da davon ausgegangen wird, dass sich das Tupel in Ihrer lokalen Zeitzone befindet. Verwenden Sie stattdessen calendar.timegm:

>>> import datetime, calendar
>>> d = datetime.datetime(1970, 1, 1, 0, 1, 0)
>>> calendar.timegm(d.timetuple())
60
Matt Kramer
quelle
1
def dt2ts(dt, utc=False):
    if utc:
        return calendar.timegm(dt.timetuple())
    if dt.tzinfo is None:
        return int(time.mktime(dt.timetuple()))
    utc_dt = dt.astimezone(tz.tzutc()).timetuple()
    return calendar.timegm(utc_dt)

Wenn Sie einen UTC-Zeitstempel wünschen: time.mktimenur für lokales dt. Die Verwendung calendar.timegmist sicher, aber dt muss die utc-Zone sein, also ändern Sie die Zone in utc. Wenn dt in UTC einfach verwenden calendar.timegm.

Wyx
quelle
1
def datetime_to_epoch(d1):

    # create 1,1,1970 in same timezone as d1
    d2 = datetime(1970, 1, 1, tzinfo=d1.tzinfo)
    time_delta = d1 - d2
    ts = int(time_delta.total_seconds())
    return ts


def epoch_to_datetime_string(ts, tz_name="UTC"):
    x_timezone = timezone(tz_name)
    d1 = datetime.fromtimestamp(ts, x_timezone)
    x = d1.strftime("%d %B %Y %H:%M:%S")
    return x
rjha94
quelle
0

Diese Klasse deckt Ihre Anforderungen ab. Sie können die Variable an ConvertUnixToDatetime übergeben und aufrufen, von welcher Funktion sie ausgeführt werden soll.

from datetime import datetime
import time

class ConvertUnixToDatetime:
    def __init__(self, date):
        self.date = date

    # Convert unix to date object
    def convert_unix(self):
        unix = self.date

        # Check if unix is a string or int & proceeds with correct conversion
        if type(unix).__name__ == 'str':
            unix = int(unix[0:10])
        else:
            unix = int(str(unix)[0:10])

        date = datetime.utcfromtimestamp(unix).strftime('%Y-%m-%d %H:%M:%S')

        return date

    # Convert date to unix object
    def convert_date(self):
        date = self.date

        # Check if datetime object or raise ValueError
        if type(date).__name__ == 'datetime':
            unixtime = int(time.mktime(date.timetuple()))
        else:
            raise ValueError('You are trying to pass a None Datetime object')
        return type(unixtime).__name__, unixtime


if __name__ == '__main__':

    # Test Date
    date_test = ConvertUnixToDatetime(datetime.today())
    date_test = date_test.convert_date()
    print(date_test)

    # Test Unix
    unix_test = ConvertUnixToDatetime(date_test[1])
    print(unix_test.convert_unix())
Cryptopotluck
quelle