Format ISO objek datetime Python UTC tidak menyertakan Z (Zulu atau Zero offset)

120

Mengapa python 2.7 tidak menyertakan karakter Z (Zulu atau nol offset) di akhir string isoformat objek waktu UTC tidak seperti JavaScript?

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

Sedangkan di javascript

>>>  console.log(new Date().toISOString()); 
2013-10-29T09:38:41.341Z
Murali Mopuru
sumber
1
Nilai datetime Python TIDAK memiliki informasi zona waktu. Coba pytz atau Babel jika Anda ingin info zona waktu disimpan di stempel waktu Anda.
tnknepp
67
datetime.datetime.utcnow().isoformat() + 'Z'
jfs
3
..dan Z yang hilang secara mengejutkan menyebabkan beberapa hal tidak berfungsi misalnya panggilan API
kapulaga
Lebih buruk lagi, jika bagian terakhir dari datetime adalah 0, itu akan memotongnya ...
ntg

Jawaban:

52

datetimeObjek Python tidak memiliki info zona waktu secara default, dan tanpanya, Python sebenarnya melanggar spesifikasi ISO 8601 ( jika tidak ada info zona waktu yang diberikan, diasumsikan sebagai waktu lokal ). Anda dapat menggunakan paket pytz untuk mendapatkan beberapa zona waktu default, atau langsung membuat subkelas tzinfoAnda sendiri:

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

Kemudian Anda dapat menambahkan info zona waktu secara manual ke utcnow():

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

Perhatikan bahwa ini TIDAK sesuai dengan format ISO 8601, yang memungkinkan salah satu Zatau +00:00sebagai sufiks untuk UTC. Perhatikan bahwa yang terakhir sebenarnya lebih sesuai dengan standar, dengan bagaimana zona waktu direpresentasikan secara umum (UTC adalah kasus khusus.)

stiv
sumber
108
bagaimana cara memasukkan, Zbukan +00:00?
leopoodle
14
PERINGATAN!!! pytzmelanggar tzinfoprotokol Python dan berbahaya untuk digunakan! Lihat blog.ganssle.io/articles/2018/03/pytz-fastest-footgun.html
ivan_pozdeev
@ivan_pozdeev thanks for linknya, sangat menarik. Perhatikan bahwa perubahan yang memungkinkan dateutiluntuk bekerja tidak diimplementasikan hingga Python 3.6 dengan PEP 495, jadi mengatakan pytztidak menggunakan antarmuka standar tidak adil karena antarmuka berubah. Sebelum perubahan, satu-satunya cara untuk membuatnya berhasil adalah dengan pytzmelakukannya.
Mark Ransom
67

Pilihan: isoformat()

Python datetimetidak mendukung sufiks zona waktu militer seperti akhiran 'Z' untuk UTC. Penggantian string sederhana berikut berhasil:

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) pada dasarnya sama dengan d.isoformat(sep=' ')

Lihat: Datetime, Python Standard Library

Pilihan: strftime()

Atau Anda bisa menggunakan strftimeuntuk mencapai efek yang sama:

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

Catatan: Opsi ini hanya berfungsi jika Anda mengetahui tanggal yang ditentukan dalam UTC.

Lihat: datetime.strftime ()


Tambahan: Zona Waktu yang Dapat Dibaca Manusia

Lebih jauh lagi, Anda mungkin tertarik untuk menampilkan informasi zona waktu yang dapat dibaca manusia, pytzdengan strftime %Zbendera zona waktu:

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'
Manav Kataria
sumber
1
Bukankah seharusnya pemisah menjadi Tkosong?
Marcello Romani
1
itu harus d = datetime.datetime(2014, 12, 10, 12, 0, 0, tzinfo=datetime.timezone.utc)di baris 2. Btw., di RFC3339 dikatakan bahwa spasi adalah 'ok' (bukan 'T').
MrFuppes
16

Skrip javascript dan python berikut memberikan keluaran yang identik. Saya pikir itu yang Anda cari.

JavaScript

new Date().toISOString()

Python

import datetime

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

Output yang mereka berikan adalah waktu utc (zelda) yang diformat sebagai string ISO dengan digit signifikan 3 milidetik dan ditambahkan dengan Z.

2019-01-19T23:20:25.459Z
Jam Risser
sumber
12

Dengan Python> = 3.2 Anda cukup menggunakan ini:

>>> from datetime import datetime, timezone
>>> datetime.now(timezone.utc).isoformat()
'2019-03-14T07:55:36.979511+00:00'
Michel Samia
sumber
3
Solusi yang sangat bagus. Untuk pertanyaan mereka tentang Z, Anda dapat memotong offsetnya:.isoformat()[:-6] + 'Z'
Maximilian Burszley
11

Waktu data Python agak kikuk. Gunakan arrow.

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

Arrow pada dasarnya memiliki api yang sama dengan datetime, tetapi dengan zona waktu dan beberapa kenyamanan tambahan yang harus ada di perpustakaan utama.

Format yang kompatibel dengan Javascript dapat dicapai dengan:

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

Javascript Date.parseakan melepaskan mikrodetik secara diam-diam dari stempel waktu.

U2EF1
sumber
7
Ini tidak menjawab pertanyaan karena string tidak diakhiri dengan 'Z'.
kaleissin
3

Ada banyak jawaban bagus di posting, tapi saya ingin formatnya keluar persis seperti pada JavaScript. Inilah yang saya gunakan dan berfungsi dengan baik.

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'
Michael Cox
sumber
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())
W Yg
sumber
3

Saya mendekati masalah ini dengan beberapa tujuan:

  • menghasilkan string waktu "sadar" UTC dalam format ISO 8601
  • hanya menggunakan fungsi Python Standard Library untuk objek datetime dan pembuatan string
  • memvalidasi objek dan string datetime dengan timezonefungsi utilitas Django dandateutil parser
  • menggunakan fungsi JavaScript untuk memvalidasi bahwa string tanggal waktu ISO 8601 adalah UTC

Pendekatan ini tidak menyertakan sufiks Z dan tidak digunakan utcnow(), tetapi didasarkan pada rekomendasi dalam dokumentasi Python dan lolos dikumpulkan dengan Django dan JavaScript.

Mari kita mulai dengan meneruskan objek zona waktu UTC datetime.now()daripada menggunakan 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'

Itu terlihat baik, jadi mari kita lihat apa yang Django dan dateutilberpikir:

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

Oke, objek tanggal waktu Python dan string ISO 8601 adalah UTC "aware". Sekarang mari kita lihat apa yang JavaScript pikirkan tentang string datetime. Meminjam dari jawaban ini kita mendapatkan:

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

Anda mungkin juga ingin membaca posting blog ini .

highpost
sumber
1
Bonus untuk tetap berpegang pada fungsi pustaka dasar dan menindaklanjuti posting lama.
Victor Romeo
1

Dengan menggabungkan semua jawaban di atas saya datang dengan fungsi berikut:

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)
EmptyData
sumber
1

Saya menggunakan pendulum:

import pendulum


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

>>> 2019-10-30T00:11:21.818265Z
pengguna3249641
sumber
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'

Atau, untuk mendapatkannya dalam satu gerakan:

>>> zulu = "{}Z".format(arrow.utcnow().format('YYYY-MM-DDTHH:mm:ss.SSS'))
>>> zulu
'2018-11-28T21:54:49.639Z'
digitalshadow
sumber