เวลา ISO (ISO 8601) ใน Python


340

ฉันมีไฟล์ ในหลาม, ผมอยากจะใช้เวลาในการสร้างและแปลงเป็นเวลา ISO (ISO 8601) สตริง ในขณะที่รักษาความเป็นจริงที่ว่ามันถูกสร้างขึ้นในโซนเวลาตะวันออก (ET)

ฉันจะใช้เวลาของไฟล์และแปลงเป็นสตริงเวลา ISO ที่ระบุโซนเวลาตะวันออก (และพิจารณาถึงการประหยัดเวลาตามฤดูกาลหากจำเป็น)



11
@ Nick - ลิงก์ที่มีประโยชน์ แต่ไม่ใช่ข้อมูลซ้ำซ้อน - เขาถามเกี่ยวกับการแปลงในทางอื่น
Yarin

1
@ Joseph- ฉันเพิ่งถามเรื่องที่เกี่ยวกับ RFC 3999- ควรใช้สำหรับเรื่องนี้ - สร้างการประทับเวลา RFC 3339 ใน Python
Yarin

คำตอบ:


560

Local เป็น ISO 8601:

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

UTC เป็น ISO 8601:

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

Local เป็น ISO 8601 โดยไม่ต้องใช้ไมโครวินาที:

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

UTC เป็น ISO 8601 พร้อมกับข้อมูล TimeZone (Python 3):

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

UTC เป็น ISO 8601 พร้อมข้อมูลโซนเวลาท้องถิ่นโดยไม่มีไมโครวินาที (Python 3):

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

Local เป็น ISO 8601 พร้อมข้อมูล TimeZone (Python 3):

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

สังเกตเห็นว่ามีข้อผิดพลาดเมื่อใช้astimezone()ในเวลา utc สิ่งนี้ให้ผลลัพธ์ที่ไม่ถูกต้อง:

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

สำหรับงูหลาม 2 มองเห็นและใช้pytz


17
.isoformat()สามารถใช้พารามิเตอร์ตัวแยก (ในกรณีที่คุณต้องการสิ่งอื่นที่ไม่ใช่ 'T'):.isoformat(' ')
ThorSummoner

5
@ThorSummoner รู้ดี! แต่ระวังว่าการเปลี่ยนตัวคั่นจะไม่เป็นไปตามมาตรฐาน ISO-8601 อีกต่อไป ... ซึ่งค่อนข้างสมเหตุสมผล (นอกจากมีวิธีที่ดีกว่าในการพิมพ์วันที่ แต่นั่นไม่ใช่คำถามที่นี่) RFC
estani

4
อนุญาตให้ใช้พื้นที่เป็นส่วนหนึ่งของมาตรฐาน ISO-8601 It is permitted to omit the 'T' character by mutual agreement.
raychi

4
@raychi ได้รับอนุญาตให้เปลี่ยนมาตรฐานโดยข้อตกลงร่วมกัน (ซึ่งในหลายกรณีจะผิดมาตรฐาน แต่ใครจะสนใจว่าเป็นข้อตกลงร่วมกันใช่มั้ย) 2c ของฉัน: เพียงแค่อย่าปล่อยให้เป็นอย่างที่เป็นอยู่
estani

14
คำตอบนี้ผิดเพราะ datetime.datetime.now (). isoformat () ส่งคืนสตริง ISO 8601 ในเครื่องโดยไม่ต้องติดฉลากให้เป็น local คุณต้องมี datetime เขตเวลาที่เป็นตัวแทนของเขตเวลาท้องถิ่นเพื่อให้ได้รับ isoformat เพื่อทำสิ่งที่ถูกต้อง
Sam Hartman

66

นี่คือสิ่งที่ฉันใช้ในการแปลงเป็นรูปแบบวันที่ XSD:

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

ฉันเจอคำถามนี้เมื่อค้นหารูปแบบวันที่ XSD ( xs:dateTime) ฉันต้องการที่จะลบ microseconds isoformatจาก


4
"XSD"คืออะไร(ในบริบทนี้)
Peter Mortensen

1
ฉันเชื่อว่าเขาหมายถึงxs:dateสไตล์ชีต XSD / XML
sventechie

1
มันหมายถึงxs:dateTime
radtek

56

การรับรองเวลา ISO 8601

มาตรฐานสากล ISO 8601 อธิบายการแทนค่าสตริงสำหรับวันที่และเวลา ตัวอย่างที่ง่ายของรูปแบบนี้คือ

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

(ซึ่งทั้งคู่ตรงกับวันที่ 16 ธันวาคม 2010) แต่รูปแบบยังอนุญาตให้ใช้เวลาในการแก้ปัญหาย่อยวินาทีและระบุเขตเวลา รูปแบบนี้แน่นอนว่าไม่ใช่รูปแบบ Python แต่เป็นรูปแบบที่ดีสำหรับการจัดเก็บวันที่และเวลาในรูปแบบพกพา รายละเอียดเกี่ยวกับรูปแบบนี้สามารถพบได้ในรายการมาร์คัส Kuhn

ฉันแนะนำให้ใช้รูปแบบนี้เพื่อเก็บเวลาในไฟล์

วิธีหนึ่งในการรับเวลาปัจจุบันในการนำเสนอนี้คือการใช้ strftime จากโมดูลเวลาในไลบรารีมาตรฐาน Python:

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

คุณสามารถใช้ตัวสร้าง strptime ของคลาส datetime:

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

แข็งแกร่งที่สุดคือโมดูล Egenix mxDateTime:

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

อ้างอิง


2
“ แข็งแกร่งขึ้น” ในแง่ใด
Stéphane

วันที่:2018-05-25
loxaxs

รวมวันที่และเวลาใน UTC:2018-05-25T12:16:14+00:00
loxaxs

2
รวมวันที่และเวลาใน UTC:2018-05-25T12:16:14Z
loxaxs

รวมวันที่และเวลาใน UTC:20180525T121614Z
loxaxs

49

ผมพบว่า datetime.isoformat ในเอกสาร ดูเหมือนว่าจะทำสิ่งที่คุณต้องการ:

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'

30

ISO 8601 อนุญาตให้ใช้ตัวย่อขนาดกะทัดรัดโดยไม่มีตัวคั่นยกเว้นTดังนั้นฉันต้องการใช้สายการบินเดียวนี้เพื่อรับสตริงการประทับเวลาอย่างรวดเร็ว:

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

ถ้าคุณไม่จำเป็นต้อง microseconds ที่เพียงแค่ปล่อยออก.%fส่วนหนึ่ง:

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

สำหรับเวลาท้องถิ่น:

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

แก้ไข:

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

>>> datetime.datetime.now().strftime("%Y-%m-%dT%H:%M%SZ")
'2018-09-05T14:09:03Z'

3
มีวิธี จำกัด ตัวเลขของมิลลิวินาทีเป็น 3 หรือไม่? เช่นแอพพลิเคชั่นจาวาสคริปต์อื่น ๆ ของฉันจะจัดทำขึ้น2019-02-23T04:02:04.051Zด้วยnew Date().toISOString()
มิแรนดา

19

รูปแบบเวลามาตรฐาน ISO 8601จะไม่จัดเก็บชื่อโซนเวลาเพียง UTC สอดคล้องชดเชยการเก็บรักษาไว้

ในการแปลงไฟล์ ctime เป็นสตริงเวลา ISO 8601 ในขณะที่รักษาการชดเชย UTC ใน 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'

รหัสจะถือว่าเขตเวลาท้องถิ่นของคุณคือ Eastern Time Zone (ET) และระบบของคุณมี UTC offset ที่ถูกต้องสำหรับ POSIX Timestamp ที่กำหนด ( ts) เช่น Python มีการเข้าถึงฐานข้อมูลเขตเวลาประวัติศาสตร์ในระบบของคุณหรือเขตเวลามี กฎเดียวกันในวันที่กำหนด

หากคุณต้องการโซลูชันแบบพกพา ใช้pytzโมดูลที่ให้การเข้าถึงฐานข้อมูล tz :

>>> 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'

ผลลัพธ์จะเหมือนกันในกรณีนี้

หากคุณต้องการชื่อเขตเวลา / ตัวย่อ / รหัสเขตให้เก็บแยกไว้

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

หมายเหตุ: ไม่:ใน UTC ออฟเซ็ตและESTตัวย่อเขตเวลาไม่ได้เป็นส่วนหนึ่งของรูปแบบเวลา ISO 8601 มันไม่ซ้ำกัน

ไลบรารีที่แตกต่างกัน / เวอร์ชันที่แตกต่างกันของไลบรารีเดียวกันอาจใช้กฎเขตเวลาที่แตกต่างกันสำหรับวันที่ / เขตเวลา หากเป็นวันที่ในอนาคตอาจยังไม่ทราบกฎ กล่าวอีกนัยหนึ่งเวลา UTC เดียวกันอาจสอดคล้องกับเวลาท้องถิ่นที่แตกต่างกันขึ้นอยู่กับกฎที่คุณใช้ - ประหยัดเวลาในรูปแบบ ISO 8601 รักษาเวลา UTC และเวลาท้องถิ่นที่สอดคล้องกับกฎโซนเวลาปัจจุบันที่ใช้งานบนแพลตฟอร์มของคุณ . คุณอาจต้องคำนวณเวลาท้องถิ่นบนแพลตฟอร์มอื่นหากมีกฎที่แตกต่างกัน


14

คุณจะต้องใช้os.statเพื่อให้ได้เวลาในการสร้างไฟล์และการรวมกันtime.strftimeและtime.timezoneสำหรับการจัดรูปแบบ:

>>> 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'

เขตเวลามีการบันทึกเวลาตามฤดูกาลหรือไม่? ดูเหมือนว่า tz จะเหมือนกันโดยไม่คำนึงถึงเวลาออมแสงหรือไม่
Joseph Turian

2
มันจะเป็นสิ่งที่ชดเชยในปัจจุบันมีผลบังคับใช้ หาก DST แอ็คทีฟจะมีออฟเซ็ตต่างจากเมื่อ DST ไม่
Max Shawabkeh

4

แก้ไขให้ถูกต้องหากฉันผิด (ไม่ใช่ฉัน) แต่การชดเชยจาก UTC จะเปลี่ยนไปตามการปรับเวลาตามฤดูกาล ดังนั้นคุณควรใช้

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

ฉันเชื่อว่าเครื่องหมายควรแตกต่างกัน:

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

ฉันอาจจะผิด แต่ฉันไม่คิดอย่างนั้น


2

ฉันเห็นด้วยกับ Jarek และฉันยังทราบด้วยว่าตัวคั่น ISO ออฟเซ็ตเป็นเครื่องหมายจุดคู่ดังนั้นฉันคิดว่าคำตอบสุดท้ายควรเป็น:

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

2

การเพิ่มความหลากหลายให้กับคำตอบที่ยอดเยี่ยมของ estani

Local เป็น ISO 8601 พร้อม TimeZone และไม่มีข้อมูลวินาที (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()

ตัวอย่างผลลัพธ์:

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

ทดสอบแล้วว่าเอาต์พุตนี้สามารถแยกวิเคราะห์ได้ทั้ง Javascript Dateและ C # DateTime/DateTimeOffset


1

ฉันได้พัฒนาฟังก์ชั่นนี้:

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

-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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.