ISO-Zeit (ISO 8601) in Python

337

Ich habe eine Datei. In Python möchte ich die Erstellungszeit in eine ISO-Zeitzeichenfolge (ISO 8601) konvertieren und dabei die Tatsache beibehalten, dass sie in der Eastern Time Zone (ET) erstellt wurde .

Wie nehme ich die ctime der Datei und konvertiere sie in eine ISO-Zeitzeichenfolge, die die östliche Zeitzone angibt (und gegebenenfalls die Sommerzeit berücksichtigt)?

Joseph Turian
quelle
11
@ Nick- Nützlicher Link, aber kein Duplikat - er fragt nach der Konvertierung in die andere Richtung.
Yarin
1
@ Joseph- Ich habe dies gerade in Bezug auf RFC 3999 gefragt - sollte dafür funktionieren - Generiere RFC 3339 Zeitstempel in Python
Yarin

Antworten:

557

Lokal nach ISO 8601:

import datetime
datetime.datetime.now().isoformat()
>>> 2020-03-20T14:28:23.382748

UTC nach ISO 8601:

import datetime
datetime.datetime.utcnow().isoformat()
>>> 2020-03-20T01:30:08.180856

Lokal nach ISO 8601 ohne Mikrosekunde:

import datetime
datetime.datetime.now().replace(microsecond=0).isoformat()
>>> 2020-03-20T14:30:43

UTC nach ISO 8601 mit TimeZone-Informationen (Python 3):

import datetime
datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat()
>>> 2020-03-20T01:31:12.467113+00:00

UTC nach ISO 8601 mit lokalen TimeZone-Informationen ohne Mikrosekunde (Python 3):

import datetime
datetime.datetime.now().astimezone().replace(microsecond=0).isoformat()
>>> 2020-03-20T14:31:43+13:00

Lokal nach ISO 8601 mit TimeZone-Informationen (Python 3):

import datetime
datetime.datetime.now().astimezone().isoformat()
>>> 2020-03-20T14:32:16.458361+13:00

Beachten Sie, dass bei der Verwendung astimezone()von utc time ein Fehler auftritt. Dies ergibt ein falsches Ergebnis:

datetime.datetime.utcnow().astimezone().isoformat() #Incorrect result

Für Python 2 siehe und verwenden Sie pytz .

estani
quelle
17
.isoformat()kann einen .isoformat(' ')
Trennparameter annehmen
5
@ThorSummoner gut zu wissen! Achten Sie jedoch darauf, dass das Ändern des Trennzeichens nicht mehr mit ISO-8601 übereinstimmt ... was wenig Sinn macht (außerdem gibt es bessere Möglichkeiten, Daten zu drucken, aber das war hier nicht die Frage). RFC
estani
4
Platz ist als Teil der Norm ISO-8601 zulässig. It is permitted to omit the 'T' character by mutual agreement.
Raychi
4
@raychi Es ist immer erlaubt, einen Standard im gegenseitigen Einvernehmen zu ändern (was in vielen Fällen gegen den Standard verstößt, aber wen interessiert es, wenn es im gegenseitigen Einvernehmen ist, oder?). Mein 2c: Lass es einfach nicht so wie es ist.
Estani
14
Diese Antwort ist falsch, da datetime.datetime.now (). Isoformat () eine lokale ISO 8601-Zeichenfolge zurückgibt, ohne sie als lokal zu kennzeichnen. Sie benötigen eine datetime.timezone, die die lokale Zeitzone darstellt, damit isoformat das Richtige tut.
Sam Hartman
66

Folgendes konvertiere ich in das XSD-Datums- / Uhrzeitformat:

from datetime import datetime
datetime.now().replace(microsecond=0).isoformat()
# You get your ISO string

Ich bin auf diese Frage gestoßen, als ich nach dem XSD-Datums- / Uhrzeitformat gesucht habe ( xs:dateTime). Ich musste die Mikrosekunden von entfernen isoformat.

radtek
quelle
4
Was ist "XSD" (in diesem Zusammenhang)?
Peter Mortensen
1
Ich glaube, er meint xs:dateaus XSD / XML-Stylesheets.
Sventechie
1
Es bedeutetxs:dateTime
Radtek
56

ISO 8601 Zeitdarstellung

Die internationale Norm ISO 8601 beschreibt eine Zeichenfolgendarstellung für Datum und Uhrzeit. Zwei einfache Beispiele für dieses Format sind

2010-12-16 17:22:15
20101216T172215

(die beide für den 16. Dezember 2010 stehen), aber das Format ermöglicht auch Auflösungszeiten von weniger als einer Sekunde und die Angabe von Zeitzonen. Dieses Format ist natürlich nicht Python-spezifisch, aber es eignet sich zum Speichern von Datum und Uhrzeit in einem tragbaren Format. Details zu diesem Format finden Sie im Eintrag von Markus Kuhn .

Ich empfehle die Verwendung dieses Formats, um Zeiten in Dateien zu speichern.

Eine Möglichkeit, die aktuelle Zeit in dieser Darstellung abzurufen, besteht darin, strftime aus dem Zeitmodul in der Python-Standardbibliothek zu verwenden:

>>> from time import strftime
>>> strftime("%Y-%m-%d %H:%M:%S")
'2010-03-03 21:16:45'

Sie können den strptime-Konstruktor der datetime-Klasse verwenden:

>>> from datetime import datetime
>>> datetime.strptime("2010-06-04 21:08:12", "%Y-%m-%d %H:%M:%S")
datetime.datetime(2010, 6, 4, 21, 8, 12)

Das robusteste ist das Egenix mxDateTime-Modul:

>>> from mx.DateTime.ISO import ParseDateTimeUTC
>>> from datetime import datetime
>>> x = ParseDateTimeUTC("2010-06-04 21:08:12")
>>> datetime.fromtimestamp(x)
datetime.datetime(2010, 3, 6, 21, 8, 12)

Verweise

Voislav Sauca
quelle
2
Inwiefern ist es "robuster"?
Stéphane
Datum:2018-05-25
Loxaxs
Kombiniertes Datum und Uhrzeit in UTC:2018-05-25T12:16:14+00:00
Loxaxs
2
Kombiniertes Datum und Uhrzeit in UTC:2018-05-25T12:16:14Z
Loxaxs
Kombiniertes Datum und Uhrzeit in UTC:20180525T121614Z
Loxaxs
49

Ich habe die datetime.isoformat in der Dokumentation gefunden . Es scheint zu tun, was Sie wollen:

datetime.isoformat([sep])

Return a string representing the date and time in ISO 8601 format, YYYY-MM-DDTHH:MM:SS.mmmmmm or, if microsecond is 0, YYYY-MM-DDTHH:MM:SS

If utcoffset() does not return None, a 6-character string is appended, giving the UTC offset in (signed) hours and minutes: YYYY-MM-DDTHH:MM:SS.mmmmmm+HH:MM or, if microsecond is 0 YYYY-MM-DDTHH:MM:SS+HH:MM

The optional argument sep (default 'T') is a one-character separator, placed between the date and time portions of the result. For example,
>>>

>>> from datetime import tzinfo, timedelta, datetime
>>> class TZ(tzinfo):
...     def utcoffset(self, dt): return timedelta(minutes=-399)
...
>>> datetime(2002, 12, 25, tzinfo=TZ()).isoformat(' ')
'2002-12-25 00:00:00-06:39'
user2120810
quelle
30

ISO 8601 ermöglicht eine kompakte Darstellung ohne Trennzeichen außer dem T. Daher verwende ich diesen Einzeiler gerne, um eine schnelle Zeitstempelzeichenfolge zu erhalten:

>>> datetime.datetime.utcnow().strftime("%Y%m%dT%H%M%S.%fZ")
'20180905T140903.591680Z'

Wenn Sie die Mikrosekunden nicht benötigen, lassen Sie einfach das .%fTeil weg :

>>> datetime.datetime.utcnow().strftime("%Y%m%dT%H%M%SZ")
'20180905T140903Z'

Für Ortszeit:

>>> datetime.datetime.now().strftime("%Y%m%dT%H%M%S")
'20180905T140903'

Bearbeiten:

Nachdem Sie dies noch einmal gelesen haben, empfehlen wir Ihnen, die Interpunktion in zu belassen . RFC 3339 empfiehlt diesen Stil, da bei Verwendung von Interpunktion nicht die Gefahr besteht, dass mehrere ISO 8601-Zeichenfolgen in Gruppen nach Interpunktion sortiert werden. Der einzige Liner für eine konforme Saite wäre also:

>>> datetime.datetime.now().strftime("%Y-%m-%dT%H:%M%SZ")
'2018-09-05T14:09:03Z'
Jim Hunziker
quelle
3
Gibt es eine Möglichkeit, die Ziffern von Millisekunden auf 3 zu beschränken? dh meine andere Javascript App wird 2019-02-23T04:02:04.051Zmitnew Date().toISOString()
Miranda
19

Das ISO 8601-Zeitformat speichert keinen Zeitzonennamen, sondern nur den entsprechenden UTC-Offset.

So konvertieren Sie eine Datei ctime in eine ISO 8601-Zeitzeichenfolge unter Beibehaltung des UTC-Offsets in Python 3:

>>> import os
>>> from datetime import datetime, timezone
>>> ts = os.path.getctime(some_file)
>>> dt = datetime.fromtimestamp(ts, timezone.utc)
>>> dt.astimezone().isoformat()
'2015-11-27T00:29:06.839600-05:00'

Der Code geht davon aus, dass Ihre lokale Zeitzone Eastern Time Zone (ET) ist und dass Ihr System einen korrekten UTC-Offset für den angegebenen POSIX-Zeitstempel bereitstellt (ts ) , dh Python hat Zugriff auf eine historische Zeitzonendatenbank auf Ihrem System oder die Zeitzone hatte die gleiche Regeln zu einem bestimmten Zeitpunkt.

Wenn Sie eine tragbare Lösung benötigen; Verwenden Sie das pytzModul , das den Zugriff auf die tz-Datenbank ermöglicht :

>>> import os
>>> from datetime import datetime
>>> import pytz  # pip install pytz
>>> ts = os.path.getctime(some_file)
>>> dt = datetime.fromtimestamp(ts, pytz.timezone('America/New_York'))
>>> dt.isoformat()
'2015-11-27T00:29:06.839600-05:00'

Das Ergebnis ist in diesem Fall dasselbe.

Wenn Sie den Zeitzonennamen / die Abkürzung / die Zonen-ID benötigen, speichern Sie ihn separat.

>>> dt.astimezone().strftime('%Y-%m-%d %H:%M:%S%z (%Z)')
'2015-11-27 00:29:06-0500 (EST)'

Hinweis: Nein, :die ESTAbkürzung für UTC-Offset und Zeitzone ist nicht Teil des Zeitformats ISO 8601. Es ist nicht einzigartig.

Unterschiedliche Bibliotheken / unterschiedliche Versionen derselben Bibliothek verwenden möglicherweise unterschiedliche Zeitzonenregeln für dasselbe Datum / dieselbe Zeitzone. Wenn es sich um ein zukünftiges Datum handelt, sind die Regeln möglicherweise noch nicht bekannt. Mit anderen Worten, dieselbe UTC-Zeit kann je nach den von Ihnen verwendeten Regeln einer anderen Ortszeit entsprechen. Durch das Speichern einer Zeit im ISO 8601-Format bleiben die UTC-Zeit und die Ortszeit erhalten, die den aktuell auf Ihrer Plattform verwendeten Zeitzonenregeln entspricht . Möglicherweise müssen Sie die Ortszeit auf einer anderen Plattform neu berechnen, wenn andere Regeln gelten.

jfs
quelle
14

Sie müssen verwenden os.stat, um die Zeit für die Dateierstellung und eine Kombination aus time.strftimeund time.timezonefür die Formatierung abzurufen:

>>> import time
>>> import os
>>> t = os.stat('C:/Path/To/File.txt').st_ctime
>>> t = time.localtime(t)
>>> formatted = time.strftime('%Y-%m-%d %H:%M:%S', t)
>>> tz = str.format('{0:+06.2f}', float(time.timezone) / 3600)
>>> final = formatted + tz
>>> 
>>> final
'2008-11-24 14:46:08-02.00'
Max Shawabkeh
quelle
Berücksichtigt die Zeitzone die Sommerzeit? Es scheint, dass tz unabhängig von der Sommerzeit gleich ist oder nicht.
Joseph Turian
2
Dies ist der aktuell gültige Offset. Wenn die Sommerzeit aktiv ist, hat sie einen anderen Versatz als die Sommerzeit.
Max Shawabkeh
4

Korrigieren Sie mich, wenn ich falsch liege (ich bin es nicht), aber der Versatz von UTC ändert sich mit der Sommerzeit. Also solltest du verwenden

tz = str.format('{0:+06.2f}', float(time.altzone) / 3600)

Ich glaube auch, dass das Zeichen anders sein sollte:

tz = str.format('{0:+06.2f}', -float(time.altzone) / 3600)

Ich könnte mich irren, aber ich denke nicht.

Jarek Przygódzki
quelle
2

Ich stimme Jarek zu und stelle außerdem fest, dass das ISO-Offset-Trennzeichen ein Doppelpunkt ist. Daher denke ich, dass die endgültige Antwort lauten sollte:

isodate.datetime_isoformat(datetime.datetime.now()) + str.format('{0:+06.2f}', -float(time.timezone) / 3600).replace('.', ':')
Mattbornski
quelle
2

Hinzufügen einer kleinen Variation zu Estanis hervorragender Antwort

Lokal nach ISO 8601 mit TimeZone und ohne Mikrosekunden-Informationen (Python 3):

import datetime, time

utc_offset_sec = time.altzone if time.localtime().tm_isdst else time.timezone
utc_offset = datetime.timedelta(seconds=-utc_offset_sec)
datetime.datetime.now().replace(microsecond=0, tzinfo=datetime.timezone(offset=utc_offset)).isoformat()

Beispielausgabe:

'2019-11-06T12:12:06-08:00'

Getestet, dass diese Ausgabe sowohl von Javascript Dateals auch von C # DateTime/ analysiert werden kannDateTimeOffset

Sharpiro
quelle
1

Ich habe diese Funktion entwickelt:

def iso_8601_format(dt):
    """YYYY-MM-DDThh:mm:ssTZD (1997-07-16T19:20:30-03:00)"""

    if dt is None:
        return ""

    fmt_datetime = dt.strftime('%Y-%m-%dT%H:%M:%S')
    tz = dt.utcoffset()
    if tz is None:
        fmt_timezone = "+00:00"
    else:
        fmt_timezone = str.format('{0:+06.2f}', float(tz.total_seconds() / 3600))

    return fmt_datetime + fmt_timezone
Andre Avilla
quelle
-6
import datetime, time    
def convert_enddate_to_seconds(self, ts):
    """Takes ISO 8601 format(string) and converts into epoch time."""
     dt = datetime.datetime.strptime(ts[:-7],'%Y-%m-%dT%H:%M:%S.%f')+\
                datetime.timedelta(hours=int(ts[-5:-3]),
                minutes=int(ts[-2:]))*int(ts[-6:-5]+'1')
    seconds = time.mktime(dt.timetuple()) + dt.microsecond/1000000.0
    return seconds 

>>> import datetime, time
>>> ts = '2012-09-30T15:31:50.262-08:00'
>>> dt = datetime.datetime.strptime(ts[:-7],'%Y-%m-%dT%H:%M:%S.%f')+ datetime.timedelta(hours=int(ts[-5:-3]), minutes=int(ts[-2:]))*int(ts[-6:-5]+'1')
>>> seconds = time.mktime(dt.timetuple()) + dt.microsecond/1000000.0
>>> seconds
1348990310.26
Ronak
quelle