Python UTC datetime object ' s ISO format nie zawiera Z (Zulu lub Zero offset)

Dlaczego python 2.7 nie zawiera znaku Z (Zulu lub Zero offset) na końcu łańcucha isoformat obiektu UTC datetime w przeciwieństwie do JavaScript?

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

Natomiast w javascript

>>>  console.log(new Date().toISOString()); 
2013-10-29T09:38:41.341Z
Author: Cœur, 2013-10-29

12 answers

Python datetime obiekty nie mają domyślnie informacji o strefie czasowej, a bez niej Python faktycznie narusza specyfikację ISO 8601 ( jeśli nie podano informacji o strefie czasowej, przyjmuje się, że jest to czas lokalny ). Możesz użyć pakietu pytz , aby uzyskać domyślne strefy czasowe, lub bezpośrednio podklasę tzinfo:

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

Następnie możesz ręcznie dodać informacje o strefie czasowej do utcnow():

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

Zauważ, że jest to zgodne z formatem ISO 8601, który pozwala na Z lub +00:00 jako przyrostek dla UTC. Zauważ, że ten ostatni rzeczywiście lepiej odpowiada standardowi, z tym, jak strefy czasowe są reprezentowane w ogóle (UTC jest szczególnym przypadkiem.)

 62
Author: stiv,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-09 18:08:34

Opcja: isoformat()

W Pythonie datetime nie obsługuje przyrostków wojskowej strefy czasowej, takich jak przyrostek " z " Dla UTC. Następująca prosta Zamiana ciągów rozwiązuje ten trik:

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) jest zasadniczo tym samym co d.isoformat(sep=' ')

Zobacz: Datetime, Python Standard Library

Opcja: strftime()

Lub możesz użyć strftime, aby osiągnąć ten sam efekt:

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

Uwaga: Ta opcja działa tylko wtedy, gdy wiesz, że podana data jest w UTC.

Zobacz: datetime.strftime()


Dodatkowe: Strefa Czasowa Czytelna Dla Człowieka

Idąc dalej, możesz być zainteresowany wyświetlaniem czytelnych dla człowieka informacji o strefie czasowej, pytz z strftime %Z flaga strefy czasowej:

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'
 75
Author: Manav Kataria,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2021-01-11 16:05:53

Następujące skrypty javascript i python dają identyczne wyniki. Myślę, że tego właśnie szukasz.

JavaScript

new Date().toISOString()

Python

from datetime import datetime

datetime.utcnow().isoformat()[:-3]+'Z'

Dane wyjściowe, które dają, to czas utc (zelda) sformatowany jako ciąg ISO o znaczącej cyfrze 3 milisekundy i uzupełniony o Z.

2019-01-19T23:20:25.459Z
 18
Author: Jam Risser,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-09-02 07:59:44

W Pythonie > = 3.2 możesz po prostu użyć tego:

>>> from datetime import datetime, timezone
>>> datetime.now(timezone.utc).isoformat()
'2019-03-14T07:55:36.979511+00:00'
 16
Author: Michel Samia,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-03-14 07:56:39

Dane Pythona są trochę niezgrabne. Użyj arrow.

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

Arrow ma zasadniczo to samo api co datetime, ale z strefami czasowymi i dodatkowymi cechami, które powinny znajdować się w Bibliotece Głównej.

Format zgodny z Javascript można uzyskać poprzez:

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

Javascript Date.parse po cichu upuści mikrosekundy ze znacznika czasu.

 12
Author: U2EF1,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-11-30 02:46:59

Przekaż obiekt strefy czasowej UTC do {[3] } zamiast używać 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'

That looks good, so let ' s see what Django and dateutil think:

from django.utils.timezone import is_aware

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

from dateutil.parser import isoparse

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

Należy pamiętać, że należy użyć isoparse(), ponieważ dokumentacja dla datetime.fromisoformat() mówi, że "nie obsługuje parsowania dowolnych ciągów ISO 8601".

Ok, obiekt DateTime Pythona i łańcuch ISO 8601 są UTC "aware". Teraz spójrzmy, co JavaScript myśli o łańcuchu datetime. Pożyczka od to odpowiedź otrzymujemy:

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

uwagi:

Podszedłem do tego problemu z kilkoma celami:

  • Wygeneruj łańcuch DateTime UTC "aware" w formacie ISO 8601
  • używaj tylko funkcji biblioteki standardowej Pythona do tworzenia obiektów datetime i łańcuchów
  • zweryfikuj obiekt datetime i łańcuch za pomocą funkcji Narzędzia Django timezone i parsera dateutil
  • użyj funkcji JavaScript, aby sprawdzić, czy łańcuch DateTime ISO 8601 jest UTC aware

Zauważ, że to podejście nie zawiera sufiksu Z I nie używa utcnow(). Ale jest on oparty na rekomendacji w dokumentacji Pythona i przechodzi muster zarówno z Django, jak i JavaScript.

Możesz również przeczytać ten wpis na blogu.

 10
Author: highpost,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-12-06 11:56:34

Krótka odpowiedź

datetime.now(timezone.utc).isoformat().replace("+00:00", "Z")

Długa odpowiedź

Powodem, dla którego "Z" nie jest włączone, jest to, że datetime.now() a nawet datetime.utcnow() zwracają daty naiwne, to znaczy daty Bez powiązanych informacji ze strefą czasową. Aby uzyskać timezone aware datetime, musisz przekazać strefę czasową jako argument do datetime now. Na przykład:

from datetime import datetime, timezone

datetime.utcnow()
#> datetime.datetime(2020, 9, 3, 20, 58, 49, 22253)
# This is timezone naive

datetime.now(timezone.utc)
#> datetime.datetime(2020, 9, 3, 20, 58, 49, 22253, tzinfo=datetime.timezone.utc)
# This is timezone aware

Gdy masz znacznik czasu świadomy strefy czasowej, isoformat będzie zawierać oznaczenie strefy czasowej. W ten sposób możesz uzyskać znacznik czasu ISO 8601 via:

datetime.now(timezone.utc).isoformat()
#> '2020-09-03T20:53:07.337670+00:00'

"+00:00" jest prawidłowym oznaczeniem strefy czasowej ISO 8601 dla UTC. Jeśli chcesz mieć "Z" Zamiast "+00: 00", musisz zrobić zastąpienie samodzielnie:

datetime.now(timezone.utc).isoformat().replace("+00:00", "Z")
#> '2020-09-03T20:53:07.337670Z'
 5
Author: Zags,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-09-03 21:02:44

W poście jest wiele dobrych odpowiedzi, ale chciałem, aby format wyszedł dokładnie tak, jak ma to miejsce w JavaScript. To jest to, czego używam i działa dobrze.

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
Author: Michael Cox,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-10-16 13:22:16
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())
 3
Author: W Yg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-06-27 06:21:34

Łącząc wszystkie powyższe odpowiedzi otrzymałem następującą funkcję:

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
Author: EmptyData,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-28 10:24:24
>>> 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'

Lub, aby uzyskać go za jednym zamachem:

>>> zulu = "{}Z".format(arrow.utcnow().format('YYYY-MM-DDTHH:mm:ss.SSS'))
>>> zulu
'2018-11-28T21:54:49.639Z'
 1
Author: digitalshadow,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-11-28 21:56:53

Używam wahadła:

import pendulum


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

>>> 2019-10-30T00:11:21.818265Z
 1
Author: user3249641,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-10-30 00:19:09