Das ISO-Format des Python UTC-Datetime-Objekts enthält kein Z (Zulu oder Zero Offset).


119

Warum enthält Python 2.7 im Gegensatz zu JavaScript kein Z-Zeichen (Zulu oder Nullpunktverschiebung) am Ende der Isoformat-Zeichenfolge des UTC-Datetime-Objekts?

>>> datetime.datetime.utcnow().isoformat()
'2013-10-29T09:14:03.895210'

Während in Javascript

>>>  console.log(new Date().toISOString()); 
2013-10-29T09:38:41.341Z

1
Python-Datums- / Uhrzeitwerte enthalten KEINE Zeitzoneninformationen. Versuchen Sie es mit Pytz oder Babel, wenn Sie Zeitzoneninformationen in Ihrem Zeitstempel speichern möchten.
tnknepp

67
datetime.datetime.utcnow().isoformat() + 'Z'
JFS

Verwandte Themen
JFS

3
..und das fehlende Z führt überraschenderweise dazu, dass einige Dinge nicht funktionieren, z. B. API-Aufruf
Kardamom

Es wird noch schlimmer, wenn der letzte Teil von datetime 0 ist, wird es abgeschnitten ...
ntg

Antworten:


52

Python- datetimeObjekte haben standardmäßig keine Zeitzoneninformationen. Ohne diese Informationen verstößt Python tatsächlich gegen die ISO 8601-Spezifikation ( wenn keine Zeitzoneninformationen angegeben werden, wird davon ausgegangen, dass es sich um Ortszeit handelt ). Sie können das Pytz-Paket verwenden , um einige Standardzeitzonen abzurufen , oder sich direkt in eine Unterklasse einteilen tzinfo:

from datetime import datetime, tzinfo, timedelta
class simple_utc(tzinfo):
    def tzname(self,**kwargs):
        return "UTC"
    def utcoffset(self, dt):
        return timedelta(0)

Anschließend können Sie die Zeitzoneninformationen manuell hinzufügen zu utcnow():

>>> datetime.utcnow().replace(tzinfo=simple_utc()).isoformat()
'2014-05-16T22:51:53.015001+00:00'

Beachten Sie, dass dies dem ISO 8601-Format entspricht, das entweder Zoder +00:00als Suffix für UTC zulässt . Beachten Sie, dass letzteres tatsächlich besser dem Standard entspricht, wie Zeitzonen im Allgemeinen dargestellt werden (UTC ist ein Sonderfall.)


108
Wie füge ich Zstatt ein +00:00?
Leopudel

14
WARNUNG!!! pytzverstößt gegen Pythons tzinfoProtokoll und ist gefährlich zu bedienen! Siehe blog.ganssle.io/articles/2018/03/pytz-fastest-footgun.html
ivan_pozdeev

@ivan_pozdeev danke für den Link, sehr interessant. Beachten Sie, dass die Änderungen, die das Funktionieren ermöglichen dateutil, erst in Python 3.6 mit PEP 495 pytzimplementiert wurden. Es ist also unfair, die Standardschnittstelle nicht zu verwenden, da sich die Schnittstelle geändert hat. Vor der Änderung war die einzige Möglichkeit, es zum Laufen zu bringen, die Art und Weise, pytzwie es funktioniert hat.
Mark Ransom

65

Möglichkeit: isoformat()

Pythons unterstützt datetimekeine militärischen Zeitzonensuffixe wie das Z-Suffix für UTC. Der folgende einfache String-Ersatz reicht aus:

In [1]: import datetime

In [2]: d = datetime.datetime(2014, 12, 10, 12, 0, 0)

In [3]: str(d).replace('+00:00', 'Z')
Out[3]: '2014-12-10 12:00:00Z'

str(d) ist im Wesentlichen das gleiche wie d.isoformat(sep=' ')

Siehe: Datetime, Python Standard Library

Möglichkeit: strftime()

Oder Sie könnten strftimeden gleichen Effekt erzielen:

In [4]: d.strftime('%Y-%m-%d %H:%M:%SZ')
Out[4]: '2014-12-10 12:00:00Z'

Hinweis: Diese Option funktioniert nur, wenn Sie wissen, dass das angegebene Datum in UTC angegeben ist.

Siehe: datetime.strftime ()


Zusätzlich: Vom Menschen lesbare Zeitzone

Wenn Sie weiter gehen, könnten Sie daran interessiert sein, von Menschen lesbare Zeitzoneninformationen pytzmit strftime %ZZeitzonenflag anzuzeigen :

In [5]: import pytz

In [6]: d = datetime.datetime(2014, 12, 10, 12, 0, 0, tzinfo=pytz.utc)

In [7]: d
Out[7]: datetime.datetime(2014, 12, 10, 12, 0, tzinfo=<UTC>)

In [8]: d.strftime('%Y-%m-%d %H:%M:%S %Z')
Out[8]: '2014-12-10 12:00:00 UTC'

1
Sollte das Trennzeichen nicht Tanstelle eines Leerzeichens sein?
Marcello Romani

es sollte d = datetime.datetime(2014, 12, 10, 12, 0, 0, tzinfo=datetime.timezone.utc)in Zeile 2 stehen. Übrigens heißt es in RFC3339 , dass ein Leerzeichen 'ok' ist (anstelle des 'T').
MrFuppes

16

Die folgenden Javascript- und Python-Skripte liefern identische Ausgaben. Ich denke, es ist das, wonach Sie suchen.

JavaScript

new Date().toISOString()

Python

import datetime

datetime.datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%S.%f')[:-3] + 'Z'

Die Ausgabe, die sie geben, ist die utc (zelda) -Zeit, die als ISO-Zeichenfolge mit einer 3-Millisekunden-signifikanten Ziffer formatiert und mit einem Z versehen ist.

2019-01-19T23:20:25.459Z

12

In Python> = 3.2 können Sie einfach Folgendes verwenden:

>>> from datetime import datetime, timezone
>>> datetime.now(timezone.utc).isoformat()
'2019-03-14T07:55:36.979511+00:00'

2
Sehr schöne Lösung. Für ihre Frage über die Zkönnen Sie den Offset .isoformat()[:-6] + 'Z'
abschneiden

11

Python-Daten sind etwas klobig. Verwenden Sie arrow.

> str(arrow.utcnow())
'2014-05-17T01:18:47.944126+00:00'

Arrow hat im Wesentlichen die gleiche API wie datetime, jedoch mit Zeitzonen und einigen zusätzlichen Feinheiten, die in der Hauptbibliothek enthalten sein sollten.

Ein mit Javascript kompatibles Format kann erreicht werden durch:

arrow.utcnow().isoformat().replace("+00:00", "Z")
'2018-11-30T02:46:40.714281Z'

Javascript löscht Date.parseleise Mikrosekunden vom Zeitstempel.


7
Dies beantwortet die Frage nicht, da die Zeichenfolge nicht mit 'Z' endet.
Kaleissin

3

Es gibt viele gute Antworten auf den Beitrag, aber ich wollte, dass das Format genau so herauskommt wie bei JavaScript. Dies ist, was ich benutze und es funktioniert gut.

In [1]: import datetime

In [1]: now = datetime.datetime.utcnow()

In [1]: now.strftime('%Y-%m-%dT%H:%M:%S') + now.strftime('.%f')[:4] + 'Z'
Out[3]: '2018-10-16T13:18:34.856Z'

3
pip install python-dateutil
>>> a = "2019-06-27T02:14:49.443814497Z"
>>> dateutil.parser.parse(a)
datetime.datetime(2019, 6, 27, 2, 14, 49, 443814, tzinfo=tzutc())

2

Ich habe dieses Problem mit ein paar Zielen angegangen:

  • Generieren Sie eine UTC-Zeichenfolge "Aware" im ISO 8601-Format
  • Verwenden Sie nur Python Standard Library-Funktionen für die Erstellung von Datetime-Objekten und Zeichenfolgen
  • Überprüfen Sie das datetime-Objekt und die Zeichenfolge mit einer Django- timezoneDienstprogrammfunktion und derdateutil Parser
  • Verwenden Sie JavaScript-Funktionen, um zu überprüfen, ob die ISO 8601-Datums- / Uhrzeitzeichenfolge UTC-fähig ist

Dieser Ansatz enthält kein Z-Suffix und wird nicht verwendet utcnow(). Er basiert jedoch auf der Empfehlung in der Python-Dokumentation und besteht die Musterung mit Django und JavaScript.

Beginnen wir damit, ein UTC-Zeitzonenobjekt zu übergeben, datetime.now()anstatt Folgendes zu verwenden datetime.utcnow():

from datetime import datetime, timezone

datetime.now(timezone.utc)
>>> datetime.datetime(2020, 1, 8, 6, 6, 24, 260810, tzinfo=datetime.timezone.utc)

datetime.now(timezone.utc).isoformat()
>>> '2020-01-08T06:07:04.492045+00:00'

Das sieht gut aus, also mal sehen was Django und dateutildenken:

from django.utils.timezone import is_aware

is_aware(datetime.now(timezone.utc))
>>> True

import dateutil.parser

is_aware(dateutil.parser.parse(datetime.now(timezone.utc).isoformat()))
>>> True

Okay, das Python-Datum / Uhrzeit-Objekt und die ISO 8601-Zeichenfolge sind UTC-fähig. Schauen wir uns nun an, was JavaScript von der datetime-Zeichenfolge hält. Aus dieser Antwort entlehnt erhalten wir:

let date= '2020-01-08T06:07:04.492045+00:00';
const dateParsed = new Date(Date.parse(date))

document.write(dateParsed);
document.write("\n");
// Tue Jan 07 2020 22:07:04 GMT-0800 (Pacific Standard Time)

document.write(dateParsed.toISOString());
document.write("\n");
// 2020-01-08T06:07:04.492Z

document.write(dateParsed.toUTCString());
document.write("\n");
// Wed, 08 Jan 2020 06:07:04 GMT

Vielleicht möchten Sie auch diesen Blog-Beitrag lesen .


1
Bonus für das Festhalten an den Funktionen der Basisbibliothek und das Nachverfolgen eines älteren Beitrags.
Victor Romeo

1

Durch die Kombination aller obigen Antworten kam ich mit folgender Funktion:

from datetime import datetime, tzinfo, timedelta
class simple_utc(tzinfo):
    def tzname(self,**kwargs):
        return "UTC"
    def utcoffset(self, dt):
        return timedelta(0)


def getdata(yy, mm, dd, h, m, s) :
    d = datetime(yy, mm, dd, h, m, s)
    d = d.replace(tzinfo=simple_utc()).isoformat()
    d = str(d).replace('+00:00', 'Z')
    return d


print getdata(2018, 02, 03, 15, 0, 14)

1

Ich benutze Pendel:

import pendulum


d = pendulum.now("UTC").to_iso8601_string()
print(d)

>>> 2019-10-30T00:11:21.818265Z

0
>>> import arrow

>>> now = arrow.utcnow().format('YYYY-MM-DDTHH:mm:ss.SSS')
>>> now
'2018-11-28T21:34:59.235'
>>> zulu = "{}Z".format(now)
>>> zulu
'2018-11-28T21:34:59.235Z'

Oder um es auf einen Schlag zu bekommen:

>>> zulu = "{}Z".format(arrow.utcnow().format('YYYY-MM-DDTHH:mm:ss.SSS'))
>>> zulu
'2018-11-28T21:54:49.639Z'
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.