รูปแบบ ISO ของวัตถุ Python UTC datetime ไม่รวม Z (Zulu หรือ Zero offset)


120

เหตุใด python 2.7 จึงไม่มีอักขระ Z (ซูลูหรือศูนย์ออฟเซ็ต) ที่ส่วนท้ายของสตริง isoformat ของวัตถุเวลา UTC ซึ่งแตกต่างจาก JavaScript

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

ในขณะที่ในจาวาสคริปต์

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

1
ค่าวันที่และเวลาของ Python ไม่มีข้อมูลเขตเวลา ลอง pytz หรือ Babel หากคุณต้องการข้อมูลเขตเวลาที่จัดเก็บไว้ในการประทับเวลาของคุณ
tnknepp

68
datetime.datetime.utcnow().isoformat() + 'Z'
jfs


3
.. และ Z ที่หายไปทำให้บางอย่างไม่ทำงานอย่างน่าประหลาดใจเช่นการเรียก API
กระวาน

มันจะแย่ไปกว่านั้นถ้าส่วนสุดท้ายของวันที่และเวลาเป็น 0 มันจะตัดทอน ...
ntg

คำตอบ:


52

datetimeอบเจ็กต์Python ไม่มีข้อมูลโซนเวลาตามค่าเริ่มต้นและถ้าไม่มี Python ก็ละเมิดข้อกำหนด ISO 8601 จริง ๆ ( หากไม่มีการระบุข้อมูลโซนเวลาจะถือว่าเป็นเวลาท้องถิ่น ) คุณสามารถใช้แพ็คเกจ pytzเพื่อรับเขตเวลาเริ่มต้นหรือคลาสย่อยโดยตรงtzinfoด้วยตัวคุณเอง:

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

จากนั้นคุณสามารถเพิ่มข้อมูลโซนเวลาด้วยตนเองในutcnow():

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

หมายเหตุว่านี้ไม่เป็นไปตามรูปแบบมาตรฐาน ISO 8601 ซึ่งช่วยให้การอย่างใดอย่างหนึ่งZหรือ+00:00เป็นคำต่อท้ายสำหรับ UTC โปรดทราบว่าอันหลังเป็นไปตามมาตรฐานที่ดีกว่าจริง ๆ โดยมีการแสดงเขตเวลาโดยทั่วไป (UTC เป็นกรณีพิเศษ)


110
ฉันจะรวมZแทนได้+00:00อย่างไร
leopoodle

14
คำเตือน!!! pytzละเมิดtzinfoโปรโตคอลของ Python และเป็นอันตรายต่อการใช้งาน! ดูblog.ganssle.io/articles/2018/03/pytz-fastest-footgun.html
ivan_pozdeev

@ivan_pozdeev ขอบคุณสำหรับลิงค์น่าสนใจมาก โปรดทราบว่าการเปลี่ยนแปลงที่อนุญาตให้dateutilทำงานนั้นไม่ได้ถูกนำไปใช้จนกว่า Python 3.6 กับ PEP 495 ดังนั้นการบอกpytzว่าไม่ได้ใช้อินเทอร์เฟซมาตรฐานนั้นไม่ยุติธรรมเพราะอินเทอร์เฟซเปลี่ยนไป ก่อนที่จะมีการเปลี่ยนแปลงวิธีเดียวที่จะทำให้มันใช้งานได้คือวิธีpytzนี้
Mark Ransom

67

ตัวเลือก: isoformat()

Python datetimeไม่รองรับคำต่อท้ายเขตเวลาทางทหารเช่นคำต่อท้าย 'Z' สำหรับ UTC การเปลี่ยนสตริงอย่างง่ายต่อไปนี้เป็นเคล็ดลับ:

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) โดยพื้นฐานแล้วจะเหมือนกับ d.isoformat(sep=' ')

ดู: Datetime, Python Standard Library

ตัวเลือก: strftime()

หรือคุณสามารถใช้strftimeเพื่อให้ได้ผลเช่นเดียวกัน:

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

หมายเหตุ: ตัวเลือกนี้ใช้ได้เฉพาะเมื่อคุณทราบว่าวันที่ที่ระบุเป็น UTC

ดู: datetime.strftime ()


เพิ่มเติม: เขตเวลาที่มนุษย์อ่านได้

นอกจากนี้คุณอาจสนใจที่จะแสดงข้อมูลเขตเวลาที่มนุษย์สามารถอ่านได้pytzพร้อมกับstrftime %Zธงเขตเวลา:

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
ตัวคั่นไม่ควรTแทนที่จะเป็นช่องว่าง?
Marcello Romani

1
มันควรจะd = datetime.datetime(2014, 12, 10, 12, 0, 0, tzinfo=datetime.timezone.utc)อยู่ในบรรทัดที่ 2 Btw ในRFC3339มันบอกว่าช่องว่างนั้น 'ok' (แทนที่จะเป็น 'T')
MrFuppes

16

สคริปต์ javascript และ python ต่อไปนี้ให้เอาต์พุตที่เหมือนกัน ฉันคิดว่ามันคือสิ่งที่คุณกำลังมองหา

JavaScript

new Date().toISOString()

Python

import datetime

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

ผลลัพธ์ที่ให้คือเวลา utc (zelda) ที่จัดรูปแบบเป็นสตริง ISO โดยมีตัวเลขนัยสำคัญ 3 มิลลิวินาทีและต่อท้ายด้วย Z

2019-01-19T23:20:25.459Z

12

ใน Python> = 3.2 คุณสามารถใช้สิ่งนี้:

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

3
ทางออกที่ดีมาก สำหรับคำถามของพวกเขาเกี่ยวกับเรื่องZนี้คุณสามารถตัด.isoformat()[:-6] + 'Z'
ทอน

11

วันที่ของ Python ค่อนข้างอึดอัดเล็กน้อย ใช้arrow.

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

Arrow มี api เดียวกับวันที่และเวลา แต่มีเขตเวลาและสิ่งพิเศษบางอย่างที่ควรอยู่ในไลบรารีหลัก

รูปแบบที่เข้ากันได้กับ Javascript สามารถทำได้โดย:

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

Javascript Date.parseจะลดระดับไมโครวินาทีจากการประทับเวลาอย่างเงียบ ๆ


7
สิ่งนี้ไม่ตอบคำถามเนื่องจากสตริงไม่ได้ลงท้ายด้วย 'Z'
kaleissin

3

มีคำตอบที่ดีมากมายในโพสต์ แต่ฉันต้องการให้รูปแบบออกมาเหมือนกับ JavaScript นี่คือสิ่งที่ฉันใช้และทำงานได้ดี

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())

3

ฉันเข้าหาปัญหานี้ด้วยเป้าหมายสองสามประการ:

  • สร้างสตริงวันที่และเวลา "ทราบ" UTC ในรูปแบบ ISO 8601
  • ใช้เฉพาะฟังก์ชัน Python Standard Library สำหรับการสร้างวัตถุและสตริงวันที่และเวลา
  • ตรวจสอบความถูกต้องของอ็อบเจ็กต์ datetime และสตริงด้วยtimezoneฟังก์ชันยูทิลิตี้Django และdateutilตัวแยกวิเคราะห์
  • ใช้ฟังก์ชัน JavaScript เพื่อตรวจสอบความถูกต้องว่าสตริงวันที่และเวลาของ ISO 8601 เป็น UTC ที่รับรู้

วิธีนี้ไม่รวมคำต่อท้าย Z และไม่ได้ใช้utcnow()แต่เป็นไปตามคำแนะนำในเอกสาร Pythonและผ่านการรวบรวมด้วย Django และ JavaScript

เริ่มต้นด้วยการส่งวัตถุเขตเวลา UTC ไปdatetime.now()แทนการใช้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'

ที่รูปลักษณ์ที่ดีดังนั้นเรามาดูสิ่ง Django และdateutilคิดว่า:

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

โอเควัตถุ Python datetime และสตริง ISO 8601 คือ UTC "ทราบ" ทีนี้มาดูกันว่า JavaScript คิดอย่างไรกับสตริงวันที่และเวลา ยืมจากคำตอบนี้เราได้รับ:

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

คุณอาจต้องการอ่านบทความในบล็อกนี้


1
โบนัสสำหรับการยึดติดกับฟังก์ชันไลบรารีพื้นฐานและติดตามโพสต์เก่า ๆ
Victor Romeo

1

โดยการรวมคำตอบทั้งหมดข้างต้นฉันมาพร้อมกับฟังก์ชันต่อไปนี้:

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)


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'

หรือเพื่อรับมันในบัดดล:

>>> zulu = "{}Z".format(arrow.utcnow().format('YYYY-MM-DDTHH:mm:ss.SSS'))
>>> zulu
'2018-11-28T21:54:49.639Z'
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.