ฉันต้องการแยกสตริงRFC 3339"2008-09-03T20:56:35.450686Z"
เป็นdatetime
ประเภทของ Python
ฉันพบstrptime
ในไลบรารีมาตรฐานของ Python แล้ว แต่ก็ไม่สะดวก
วิธีที่ดีที่สุดในการทำเช่นนี้คืออะไร?
ฉันต้องการแยกสตริงRFC 3339"2008-09-03T20:56:35.450686Z"
เป็นdatetime
ประเภทของ Python
ฉันพบstrptime
ในไลบรารีมาตรฐานของ Python แล้ว แต่ก็ไม่สะดวก
วิธีที่ดีที่สุดในการทำเช่นนี้คืออะไร?
คำตอบ:
หลาม dateutilแพคเกจสามารถแยกไม่เพียง แต่ RFC 3339 สตริง datetime อย่างหนึ่งในคำถาม แต่ยังอื่น ๆISO 8601วันที่และเวลาสตริงที่ไม่สอดคล้องกับ RFC 3339 (เช่นคนที่ไม่มีเวลา UTC ชดเชยหรือคนที่เป็นตัวแทนของ เฉพาะวันที่)
>>> import dateutil.parser
>>> dateutil.parser.isoparse('2008-09-03T20:56:35.450686Z') # RFC 3339 format
datetime.datetime(2008, 9, 3, 20, 56, 35, 450686, tzinfo=tzutc())
>>> dateutil.parser.isoparse('2008-09-03T20:56:35.450686') # ISO 8601 extended format
datetime.datetime(2008, 9, 3, 20, 56, 35, 450686)
>>> dateutil.parser.isoparse('20080903T205635.450686') # ISO 8601 basic format
datetime.datetime(2008, 9, 3, 20, 56, 35, 450686)
>>> dateutil.parser.isoparse('20080903') # ISO 8601 basic format, date only
datetime.datetime(2008, 9, 3, 0, 0)
โปรดทราบว่าdateutil.parser.isoparse
น่าจะเข้มงวดกว่าแฮ็คมากขึ้นdateutil.parser.parse
แต่ทั้งคู่นั้นค่อนข้างให้อภัยและจะพยายามตีความสตริงที่คุณส่งผ่านหากคุณต้องการขจัดความเป็นไปได้ของความผิดพลาดใด ๆ คุณต้องใช้บางสิ่งที่เข้มงวดกว่าอย่างใดอย่างหนึ่ง ฟังก์ชั่น.
ชื่อ Pypi คือpython-dateutil
ไม่ใช่dateutil
(ขอบคุณcode3monk3y ):
pip install python-dateutil
หากคุณกำลังใช้งูหลาม 3.7 มีลักษณะที่คำตอบนี้datetime.datetime.fromisoformat
เกี่ยวกับ
python-dateutil
ไม่ได้ดังนั้น:dateutil
pip install python-dateutil
dateutil.parser
เป็นแฮ็คที่ตั้งใจ: มันพยายามที่จะคาดเดารูปแบบและทำให้สมมติฐานที่หลีกเลี่ยงไม่ได้ (ปรับแต่งด้วยมือเท่านั้น) ในกรณีที่คลุมเครือ ดังนั้นใช้เฉพาะเมื่อคุณจำเป็นต้องวิเคราะห์อินพุตของรูปแบบที่ไม่รู้จักและไม่เป็นไรที่จะยอมรับความผิดที่เกิดขึ้นเป็นครั้งคราว
ห้องสมุดมาตรฐานแนะนำฟังก์ชั่นสำหรับการกลับหัวdatetime
datetime.isoformat()
classmethod
datetime.fromisoformat(date_string)
:กลับ
datetime
สอดคล้องกับdate_string
หนึ่งในรูปแบบที่ปล่อยออกมาและdate.isoformat()
datetime.isoformat()
ฟังก์ชันนี้รองรับสตริงในรูปแบบ:
YYYY-MM-DD[*HH[:MM[:SS[.mmm[mmm]]]][+HH:MM[:SS[.ffffff]]]]
ซึ่ง
*
สามารถจับคู่อักขระเดี่ยวใดก็ได้ข้อควรระวัง : สิ่งนี้ไม่สนับสนุนการแยกสตริง ISO 8601 โดยพลการ - มันมีไว้สำหรับการดำเนินการแบบผกผัน
datetime.isoformat()
เท่านั้น
ตัวอย่างการใช้งาน:
from datetime import datetime
date = datetime.fromisoformat('2017-01-01T12:30:59.000000')
datetime
อาจมี a tzinfo
และส่งออกเขตเวลา แต่datetime.fromisoformat()
ไม่ได้แยกวิเคราะห์ tzinfo หรือไม่ ดูเหมือนว่าจะเป็นข้อผิดพลาด ..
isoformat
สตริงคนเดียวที่สร้างขึ้นโดย มันไม่ยอมรับตัวอย่างในคำถาม"2008-09-03T20:56:35.450686Z"
เพราะต่อท้ายแต่มันก็ไม่ยอมรับZ
"2008-09-03T20:56:35.450686"
Z
date_string.replace("Z", "+00:00")
หมายเหตุใน Python 2.6+ และ Py3K อักขระ% f จับไมโครวินาที
>>> datetime.datetime.strptime("2008-09-03T20:56:35.450686Z", "%Y-%m-%dT%H:%M:%S.%fZ")
ดูปัญหาที่นี่
strptime
ในความเป็นจริงเป็นไปไม่ได้
datetime.datetime.strptime(timestamp, '%Y-%m-%dT%H:%M:%S.%f')
ดังนั้นนี่จึงเป็นกลอุบาย
หลาย คำตอบ ที่นี่ ขอแนะนำให้ใช้datetime.datetime.strptime
การแยก RFC 3339 หรือ ISO 8601 datetimes กับเขตเวลา, เช่นเดียวกับการจัดแสดงในคำถาม:
2008-09-03T20:56:35.450686Z
นี่เป็นความคิดที่ไม่ดี
สมมติว่าคุณต้องการสนับสนุนรูปแบบ RFC 3339 เต็มรูปแบบรวมถึงการสนับสนุน UTC ออฟเซ็ตนอกเหนือจากศูนย์จากนั้นโค้ดที่คำตอบเหล่านี้แนะนำไม่ทำงาน อันที่จริงมันไม่สามารถทำงานได้เนื่องจากการแยกวิเคราะห์ไวยากรณ์ RFC 3339 ที่ใช้strptime
เป็นไปไม่ได้ สตริงรูปแบบที่ใช้โดยโมดูลวันที่และเวลาของ Python ไม่สามารถอธิบายไวยากรณ์ RFC 3339 ได้
ปัญหาคือ UTC ออฟเซ็ต RFC 3339 อินเทอร์เน็ตวันที่ / รูปแบบเวลากำหนดให้ทุกวันที่เวลารวมถึงการชดเชย UTC และชดเชยผู้ที่สามารถเป็นได้ทั้งZ
(ย่อมาจาก "เวลาซูลู") หรือใน+HH:MM
หรือ-HH:MM
รูปแบบเหมือนหรือ+05:00
-10:30
ดังนั้นนี่คือชุดข้อมูล RFC 3339 ที่ถูกต้องทั้งหมด:
2008-09-03T20:56:35.450686Z
2008-09-03T20:56:35.450686+05:00
2008-09-03T20:56:35.450686-10:30
อนิจจาสตริงรูปแบบที่ใช้โดยstrptime
และstrftime
ไม่มีคำสั่งที่สอดคล้องกับ UTC offsets ในรูปแบบ RFC 3339 รายการคำสั่งที่สมบูรณ์ที่สนับสนุนสามารถดูได้ที่https://docs.python.org/3/library/datetime.html#strftime-and-strptime-behaviorและคำสั่ง UTC ออฟเซ็ตเดียวที่รวมอยู่ในรายการคือ%z
:
% Z
UTC ชดเชยในรูปแบบ + HHMM หรือ -HHMM (สตริงว่างถ้าวัตถุไร้เดียงสา)
ตัวอย่าง: (ว่าง), +0000, -0400, +1030
สิ่งนี้ไม่ตรงกับรูปแบบของการชดเชย RFC 3339 และแน่นอนถ้าเราพยายามใช้%z
ในสตริงการจัดรูปแบบและแยกวิเคราะห์วัน RFC 3339 เราจะล้มเหลว:
>>> from datetime import datetime
>>> datetime.strptime("2008-09-03T20:56:35.450686Z", "%Y-%m-%dT%H:%M:%S.%f%z")
Traceback (most recent call last):
File "", line 1, in
File "/usr/lib/python3.4/_strptime.py", line 500, in _strptime_datetime
tt, fraction = _strptime(data_string, format)
File "/usr/lib/python3.4/_strptime.py", line 337, in _strptime
(data_string, format))
ValueError: time data '2008-09-03T20:56:35.450686Z' does not match format '%Y-%m-%dT%H:%M:%S.%f%z'
>>> datetime.strptime("2008-09-03T20:56:35.450686+05:00", "%Y-%m-%dT%H:%M:%S.%f%z")
Traceback (most recent call last):
File "", line 1, in
File "/usr/lib/python3.4/_strptime.py", line 500, in _strptime_datetime
tt, fraction = _strptime(data_string, format)
File "/usr/lib/python3.4/_strptime.py", line 337, in _strptime
(data_string, format))
ValueError: time data '2008-09-03T20:56:35.450686+05:00' does not match format '%Y-%m-%dT%H:%M:%S.%f%z'
(ที่จริงแล้วข้างต้นเป็นเพียงสิ่งที่คุณจะเห็นใน Python 3 ใน Python 2 เราจะล้มเหลวด้วยเหตุผลที่ง่ายกว่าซึ่งก็คือมันstrptime
ไม่ได้ใช้%z
คำสั่งเลยใน Python 2 )
คำตอบมากมายที่นี่ซึ่งแนะนำให้แก้ไขstrptime
ทั้งหมดนี้โดยรวมตัวอักษรZ
ในสตริงรูปแบบซึ่งตรงกับZ
สตริง datetime ตัวอย่างจากคำถามของผู้ถาม (และทิ้งไว้ให้ผลิตdatetime
วัตถุโดยไม่มีเขตเวลา):
>>> datetime.strptime("2008-09-03T20:56:35.450686Z", "%Y-%m-%dT%H:%M:%S.%fZ")
datetime.datetime(2008, 9, 3, 20, 56, 35, 450686)
เนื่องจากสิ่งนี้จะทิ้งข้อมูลเขตเวลาที่รวมอยู่ในสตริง datetime ดั้งเดิมจึงเป็นที่น่าสงสัยว่าเราควรคำนึงถึงผลลัพธ์ที่ถูกต้องหรือไม่ แต่ที่สำคัญกว่านั้นเพราะวิธีนี้เกี่ยวข้องกับการเข้ารหัส UTC เฉพาะที่ชดเชยลงในสตริงรูปแบบมันจะทำให้หายใจไม่ออกในขณะที่พยายามแยกวิเคราะห์ RFC 3339 datetime ด้วย UTC offset ที่แตกต่างกัน:
>>> datetime.strptime("2008-09-03T20:56:35.450686+05:00", "%Y-%m-%dT%H:%M:%S.%fZ")
Traceback (most recent call last):
File "", line 1, in
File "/usr/lib/python3.4/_strptime.py", line 500, in _strptime_datetime
tt, fraction = _strptime(data_string, format)
File "/usr/lib/python3.4/_strptime.py", line 337, in _strptime
(data_string, format))
ValueError: time data '2008-09-03T20:56:35.450686+05:00' does not match format '%Y-%m-%dT%H:%M:%S.%fZ'
ถ้าคุณกำลังบางอย่างที่คุณต้องการเพียงที่จะสนับสนุน RFC 3339 datetimes ในเวลาซูลูและไม่ได้คนที่มีการชดเชยเขตอื่น ๆ strptime
ที่ไม่ได้ใช้ ใช้หนึ่งในวิธีการอื่น ๆ อีกมากมายที่อธิบายไว้ในคำตอบที่นี่แทน
strptime()
ใน Python 3.7 ตอนนี้รองรับทุกสิ่งที่อธิบายว่าเป็นไปไม่ได้ในคำตอบนี้ ('Z' ตามตัวอักษรและ ':' ในออฟเซ็ตเขตเวลา) น่าเสียดายที่ยังมีอีกกรณีหนึ่งที่ทำให้ RFC 3339 ไม่สามารถใช้งานร่วมกับ ISO 8601 ได้ซึ่งโดยพื้นฐานแล้วในอดีตจะอนุญาตให้เขตเวลาว่างในเชิงลบเป็นค่าชดเชย -00: 00 และในภายหลังไม่ได้
ลองใช้โมดูลiso8601 มันทำอย่างนี้
มีตัวเลือกอื่น ๆ หลายตัวที่กล่าวถึงในหน้าWorkingWithTimeบนวิกิ python.org
iso8601.parse_date("2008-09-03T20:56:35.450686Z")
นำเข้าอีกครั้ง datetime s = "2008-09-03T20: 56: 35.450686Z" d = datetime.datetime (* map (int, re.split ('[^ \ d]', s) [: - 1])
datetime.datetime(*map(int, re.findall('\d+', s))
คุณได้รับข้อผิดพลาดอะไรบ้าง? เป็นเช่นนี้หรือไม่?
>>> datetime.datetime.strptime("2008-08-12T12:20:30.656234Z", "%Y-%m-%dT%H:%M:%S.Z")
ValueError: time data did not match format: data=2008-08-12T12:20:30.656234Z fmt=%Y-%m-%dT%H:%M:%S.Z
ถ้าใช่คุณสามารถแยกสตริงอินพุตของคุณเป็น "." แล้วเพิ่มไมโครวินาทีในวันที่และเวลาที่คุณได้รับ
ลองสิ่งนี้:
>>> def gt(dt_str):
dt, _, us= dt_str.partition(".")
dt= datetime.datetime.strptime(dt, "%Y-%m-%dT%H:%M:%S")
us= int(us.rstrip("Z"), 10)
return dt + datetime.timedelta(microseconds=us)
>>> gt("2008-08-12T12:20:30.656234Z")
datetime.datetime(2008, 8, 12, 12, 20, 30, 656234)
""
หรือ"Z"
จะต้องเป็นออฟเซ็ตเป็นชั่วโมง / นาทีซึ่งสามารถเพิ่ม / ลบออกจากวัตถุ datetime ได้โดยตรง คุณสามารถสร้างคลาสย่อย tzinfo เพื่อจัดการมัน แต่นั่นอาจจะไม่แนะนำอีกครั้ง
เริ่มต้นจาก Python 3.7, strptime รองรับตัวคั่นลำไส้ใหญ่ใน UTC ออฟเซ็ต ( แหล่งที่มา ) ดังนั้นคุณสามารถใช้:
import datetime
datetime.datetime.strptime('2018-01-31T09:24:31.488670+00:00', '%Y-%m-%dT%H:%M:%S.%f%z')
แก้ไข:
ดังที่ Martijn ชี้ให้เห็นถ้าคุณสร้างวัตถุ datetime โดยใช้ isoformat () คุณก็สามารถใช้ datetime ได้จาก isoformat ()
datetime.fromisoformat()
datetime.datetime.isoformat('2018-01-31T09:24:31.488670+00:00')
datetime.fromisoformat()
และdatetime.isoformat()
ในวันนี้Arrowสามารถใช้เป็นโซลูชันของบุคคลที่สามได้:
>>> import arrow
>>> date = arrow.get("2008-09-03T20:56:35.450686Z")
>>> date.datetime
datetime.datetime(2008, 9, 3, 20, 56, 35, 450686, tzinfo=tzutc())
เพียงแค่ใช้python-dateutil
โมดูล:
>>> import dateutil.parser as dp
>>> t = '1984-06-02T19:05:00.000Z'
>>> parsed_t = dp.parse(t)
>>> print(parsed_t)
datetime.datetime(1984, 6, 2, 19, 5, tzinfo=tzutc())
455051100
(ตรวจสอบที่epochconverter.com ) ,,, เว้นแต่ฉันจะหายไปบางสิ่งบางอย่าง?
หากคุณไม่ต้องการใช้ dateutil คุณสามารถลองใช้ฟังก์ชันนี้:
def from_utc(utcTime,fmt="%Y-%m-%dT%H:%M:%S.%fZ"):
"""
Convert UTC time string to time.struct_time
"""
# change datetime.datetime to time, return time.struct_time type
return datetime.datetime.strptime(utcTime, fmt)
ทดสอบ:
from_utc("2007-03-04T21:08:12.123Z")
ผลลัพธ์:
datetime.datetime(2007, 3, 4, 21, 8, 12, 123000)
strptime
เข้ามาในรูปแบบของสตริงที่ผ่านมา นี่เป็นความคิดที่ไม่ดีเพราะมันจะล้มเหลวในการแยกวิเคราะห์วันที่และเวลาด้วย UTC ตรงข้ามที่แตกต่างกันและยกข้อยกเว้น ดูคำตอบของฉันที่อธิบายถึงวิธีการแยกวิเคราะห์ RFC 3339 ด้วย strptime ในความเป็นจริงเป็นไปไม่ได้
toISOString
วิธีการของ JavaScript แต่ไม่มีการกล่าวถึงการ จำกัด เวลาวันที่ของซูลูในคำตอบนี้และคำถามก็ไม่ได้ระบุว่าเป็นสิ่งที่จำเป็นและการใช้เพียงแค่dateutil
สะดวกและเท่ากันในสิ่งที่สามารถแยกวิเคราะห์ได้
หากคุณทำงานกับ Django จะมีโมดูล dateparseที่ยอมรับรูปแบบที่คล้ายกับรูปแบบ ISO รวมถึงเขตเวลา
หากคุณไม่ได้ใช้ Django และคุณไม่ต้องการใช้หนึ่งในห้องสมุดอื่น ๆ ที่กล่าวถึงในที่นี้คุณอาจปรับซอร์สโค้ด Django สำหรับ dateparseให้กับโครงการของคุณ
DateTimeField
ใช้สิ่งนี้เมื่อคุณตั้งค่าสตริง
ฉันพบว่าciso8601เป็นวิธีที่เร็วที่สุดในการวิเคราะห์เวลา ISO 8601 ตามชื่อที่แนะนำมันถูกนำไปใช้ใน C
import ciso8601
ciso8601.parse_datetime('2014-01-09T21:48:00.921000+05:30')
GitHub Repo READMEแสดงให้เห็นว่าพวกเขา> 10 เท่าเมื่อเทียบกับการเพิ่มความเร็วทั้งหมดของห้องสมุดอื่น ๆ ที่ระบุไว้ในคำตอบอื่น ๆ
โครงการส่วนบุคคลของฉันเกี่ยวข้องกับการแยก ISO 8601 จำนวนมาก มันดีที่จะสามารถเปลี่ยนสายและไปเร็วขึ้น 10 เท่า :)
แก้ไข:ฉันได้กลายเป็นผู้ดูแลของ ciso8601 เร็วขึ้นกว่าเดิม!
datetime.strptime()
เป็นวิธีแก้ปัญหาที่เร็วที่สุดต่อไป ขอบคุณที่รวบรวมข้อมูลทั้งหมดเข้าด้วยกัน!
datetime.strptime()
ไม่ใช่ไลบรารีการแยกวิเคราะห์ ISO 8601 ที่สมบูรณ์ หากคุณใช้ Python 3.7 คุณสามารถใช้datetime.fromisoformat()
วิธีนี้ซึ่งยืดหยุ่นกว่าเล็กน้อย คุณอาจสนใจรายการ parsersที่สมบูรณ์ยิ่งขึ้นซึ่งควรจะรวมเข้ากับ ciso8601 README ในไม่ช้า
ใช้งานได้กับ stdlib ใน Python 3.2 เป็นต้นไป (สมมติว่าการประทับเวลาทั้งหมดเป็น UTC):
from datetime import datetime, timezone, timedelta
datetime.strptime(timestamp, "%Y-%m-%dT%H:%M:%S.%fZ").replace(
tzinfo=timezone(timedelta(0)))
ตัวอย่างเช่น,
>>> datetime.utcnow().replace(tzinfo=timezone(timedelta(0)))
... datetime.datetime(2015, 3, 11, 6, 2, 47, 879129, tzinfo=datetime.timezone.utc)
strptime
เข้ามาในรูปแบบของสตริงที่ผ่านมา นี่เป็นความคิดที่ไม่ดีเพราะมันจะล้มเหลวในการแยกวิเคราะห์วันที่และเวลาด้วย UTC ตรงข้ามที่แตกต่างกันและยกข้อยกเว้น ดูคำตอบของฉันที่อธิบายถึงวิธีการแยกวิเคราะห์ RFC 3339 ด้วย strptime ในความเป็นจริงเป็นไปไม่ได้
timezone.utc
timezone(timedelta(0))
นอกจากนี้รหัสทำงานใน Python 2.6+ (อย่างน้อย) หากคุณจัดหาutc
ออบเจ็กต์ tzinfo
%Z
สำหรับเขตเวลาใน Python เวอร์ชันล่าสุด
ฉันเป็นผู้เขียน iso8601 utils มันสามารถพบได้บน GitHubหรือบนPyPI นี่คือวิธีที่คุณสามารถแยกวิเคราะห์ตัวอย่างของคุณ:
>>> from iso8601utils import parsers
>>> parsers.datetime('2008-09-03T20:56:35.450686Z')
datetime.datetime(2008, 9, 3, 20, 56, 35, 450686)
วิธีการหนึ่งที่ตรงไปตรงมาแปลงเป็น ISO 8601 เหมือนสตริงวันกับเวลาในยูนิกซ์หรือdatetime.datetime
วัตถุในทุกรุ่นที่รองรับหลามโดยไม่ต้องติดตั้งโมดูลของบุคคลที่สามคือการใช้ตัวแยกวิเคราะห์วันที่ SQLite
#!/usr/bin/env python
from __future__ import with_statement, division, print_function
import sqlite3
import datetime
testtimes = [
"2016-08-25T16:01:26.123456Z",
"2016-08-25T16:01:29",
]
db = sqlite3.connect(":memory:")
c = db.cursor()
for timestring in testtimes:
c.execute("SELECT strftime('%s', ?)", (timestring,))
converted = c.fetchone()[0]
print("%s is %s after epoch" % (timestring, converted))
dt = datetime.datetime.fromtimestamp(int(converted))
print("datetime is %s" % dt)
เอาท์พุท:
2016-08-25T16:01:26.123456Z is 1472140886 after epoch
datetime is 2016-08-25 12:01:26
2016-08-25T16:01:29 is 1472140889 after epoch
datetime is 2016-08-25 12:01:29
ผมเคยขึ้นรหัส parser สำหรับมาตรฐาน ISO 8601 และวางไว้บน GitHub: https://github.com/boxed/iso8601 การใช้งานนี้รองรับทุกอย่างในข้อกำหนดยกเว้นช่วงเวลาช่วงเวลาและวันที่ที่อยู่นอกช่วงวันที่ที่สนับสนุนของโมดูลวันที่และเวลาของ Python
รวมการทดสอบแล้ว! : P
ฟังก์ชัน parse_datetime () ของ Django รองรับวันที่ด้วย UTC ออฟเซ็ต:
parse_datetime('2016-08-09T15:12:03.65478Z') =
datetime.datetime(2016, 8, 9, 15, 12, 3, 654780, tzinfo=<UTC>)
ดังนั้นจึงสามารถใช้สำหรับการแยกวิเคราะห์ ISO 8601 วันที่ในฟิลด์ภายในโครงการทั้งหมด:
from django.utils import formats
from django.forms.fields import DateTimeField
from django.utils.dateparse import parse_datetime
class DateTimeFieldFixed(DateTimeField):
def strptime(self, value, format):
if format == 'iso-8601':
return parse_datetime(value)
return super().strptime(value, format)
DateTimeField.strptime = DateTimeFieldFixed.strptime
formats.ISO_INPUT_FORMATS['DATETIME_INPUT_FORMATS'].insert(0, 'iso-8601')
เพราะมาตรฐาน ISO 8601 CCYY-MM-DDThh:mm:ss[Z|(+|-)hh:mm]
ช่วยให้หลายรูปแบบของทวิภาคตัวเลือกและพุ่งเป็นปัจจุบันโดยทั่วไป หากคุณต้องการใช้ strptime คุณจะต้องตัดการเปลี่ยนแปลงเหล่านั้นออกก่อน
เป้าหมายคือการสร้างวัตถุ utc datetime
2016-06-29T19:36:29.3453Z
:
datetime.datetime.strptime(timestamp.translate(None, ':-'), "%Y%m%dT%H%M%S.%fZ")
2016-06-29T19:36:29.3453-0400
หรือ2008-09-03T20:56:35.450686+05:00
ใช้สิ่งต่อไปนี้ สิ่งเหล่านี้จะแปลงรูปแบบทั้งหมดเป็นสิ่งที่ไม่มีตัวคั่นตัวแปรเช่น 20080903T205635.450686+0500
ทำให้การแยกวิเคราะห์สอดคล้องกัน / ง่ายขึ้น
import re
# this regex removes all colons and all
# dashes EXCEPT for the dash indicating + or - utc offset for the timezone
conformed_timestamp = re.sub(r"[:]|([-](?!((\d{2}[:]\d{2})|(\d{4}))$))", '', timestamp)
datetime.datetime.strptime(conformed_timestamp, "%Y%m%dT%H%M%S.%f%z" )
%z
คำสั่ง strptime (คุณเห็นสิ่งที่ต้องการValueError: 'z' is a bad directive in format '%Y%m%dT%H%M%S.%f%z'
) จากนั้นคุณต้องชดเชยเวลาด้วยตนเองZ
(UTC) หมายเหตุ%z
อาจใช้งานไม่ได้กับระบบของคุณในเวอร์ชันหลาม <3 เนื่องจากมันขึ้นอยู่กับการรองรับไลบรารี c ซึ่งแตกต่างกันไปตามประเภทการสร้างระบบ / หลาม (เช่น Jython, Cython ฯลฯ )
import re
import datetime
# this regex removes all colons and all
# dashes EXCEPT for the dash indicating + or - utc offset for the timezone
conformed_timestamp = re.sub(r"[:]|([-](?!((\d{2}[:]\d{2})|(\d{4}))$))", '', timestamp)
# split on the offset to remove it. use a capture group to keep the delimiter
split_timestamp = re.split(r"[+|-]",conformed_timestamp)
main_timestamp = split_timestamp[0]
if len(split_timestamp) == 3:
sign = split_timestamp[1]
offset = split_timestamp[2]
else:
sign = None
offset = None
# generate the datetime object without the offset at UTC time
output_datetime = datetime.datetime.strptime(main_timestamp +"Z", "%Y%m%dT%H%M%S.%fZ" )
if offset:
# create timedelta based on offset
offset_delta = datetime.timedelta(hours=int(sign+offset[:-2]), minutes=int(sign+offset[-2:]))
# offset datetime with timedelta
output_datetime = output_datetime + offset_delta
สำหรับสิ่งที่ใช้ได้กับไลบรารี่มาตรฐาน 2.X ลอง:
calendar.timegm(time.strptime(date.split(".")[0]+"UTC", "%Y-%m-%dT%H:%M:%S%Z"))
calendar.timegm เป็นรุ่น gm ที่ขาดหายไปของ time.mktime
หลาม -thututil จะโยนข้อยกเว้นถ้าแยกสตริงวันที่ไม่ถูกต้องดังนั้นคุณอาจต้องการที่จะจับข้อยกเว้น
from dateutil import parser
ds = '2012-60-31'
try:
dt = parser.parse(ds)
except ValueError, e:
print '"%s" is an invalid date' % ds
ทุกวันนี้มีMaya: Datetimes for Humans ™จากผู้เขียนคำขอยอดนิยม: แพ็คเกจ HTTP for Humans ™:
>>> import maya
>>> str = '2008-09-03T20:56:35.450686Z'
>>> maya.MayaDT.from_rfc3339(str).datetime()
datetime.datetime(2008, 9, 3, 20, 56, 35, 450686, tzinfo=<UTC>)
วิธีหนึ่งคือการใช้ตัวแยกวิเคราะห์เฉพาะสำหรับ ISO-8601 คือการใช้isoparseการทำงานของ parser dateutil:
from dateutil import parser
date = parser.isoparse("2008-09-03T20:56:35.450686+01:00")
print(date)
เอาท์พุท:
2008-09-03 20:56:35.450686+01:00
ฟังก์ชั่นนี้ถูกกล่าวถึงในเอกสารประกอบสำหรับฟังก์ชั่น Python มาตรฐานdatetime จากรูปแบบ :
ตัวแยกวิเคราะห์ ISO 8601 ที่มีคุณลักษณะครบถ้วนมากขึ้น dateutil.parser.isoparse มีอยู่ใน dateutil ของแพ็คเกจบุคคลที่สาม
ขอบคุณคำตอบของ Mark Ameryที่ยอดเยี่ยมฉันได้คิดหน้าที่การใช้งานสำหรับรูปแบบ ISO ที่เป็นไปได้ของ datetime
class FixedOffset(tzinfo):
"""Fixed offset in minutes: `time = utc_time + utc_offset`."""
def __init__(self, offset):
self.__offset = timedelta(minutes=offset)
hours, minutes = divmod(offset, 60)
#NOTE: the last part is to remind about deprecated POSIX GMT+h timezones
# that have the opposite sign in the name;
# the corresponding numeric value is not used e.g., no minutes
self.__name = '<%+03d%02d>%+d' % (hours, minutes, -hours)
def utcoffset(self, dt=None):
return self.__offset
def tzname(self, dt=None):
return self.__name
def dst(self, dt=None):
return timedelta(0)
def __repr__(self):
return 'FixedOffset(%d)' % (self.utcoffset().total_seconds() / 60)
def __getinitargs__(self):
return (self.__offset.total_seconds()/60,)
def parse_isoformat_datetime(isodatetime):
try:
return datetime.strptime(isodatetime, '%Y-%m-%dT%H:%M:%S.%f')
except ValueError:
pass
try:
return datetime.strptime(isodatetime, '%Y-%m-%dT%H:%M:%S')
except ValueError:
pass
pat = r'(.*?[+-]\d{2}):(\d{2})'
temp = re.sub(pat, r'\1\2', isodatetime)
naive_date_str = temp[:-5]
offset_str = temp[-5:]
naive_dt = datetime.strptime(naive_date_str, '%Y-%m-%dT%H:%M:%S.%f')
offset = int(offset_str[-4:-2])*60 + int(offset_str[-2:])
if offset_str[0] == "-":
offset = -offset
return naive_dt.replace(tzinfo=FixedOffset(offset))
def parseISO8601DateTime(datetimeStr):
import time
from datetime import datetime, timedelta
def log_date_string(when):
gmt = time.gmtime(when)
if time.daylight and gmt[8]:
tz = time.altzone
else:
tz = time.timezone
if tz > 0:
neg = 1
else:
neg = 0
tz = -tz
h, rem = divmod(tz, 3600)
m, rem = divmod(rem, 60)
if neg:
offset = '-%02d%02d' % (h, m)
else:
offset = '+%02d%02d' % (h, m)
return time.strftime('%d/%b/%Y:%H:%M:%S ', gmt) + offset
dt = datetime.strptime(datetimeStr, '%Y-%m-%dT%H:%M:%S.%fZ')
timestamp = dt.timestamp()
return dt + timedelta(hours=dt.hour-time.gmtime(timestamp).tm_hour)
โปรดทราบว่าเราควรมองถ้าสตริงไม่ได้จบลงด้วยการที่เราสามารถแยกวิเคราะห์โดยใช้Z
%z
เริ่มแรกฉันลองด้วย:
from operator import neg, pos
from time import strptime, mktime
from datetime import datetime, tzinfo, timedelta
class MyUTCOffsetTimezone(tzinfo):
@staticmethod
def with_offset(offset_no_signal, signal): # type: (str, str) -> MyUTCOffsetTimezone
return MyUTCOffsetTimezone((pos if signal == '+' else neg)(
(datetime.strptime(offset_no_signal, '%H:%M') - datetime(1900, 1, 1))
.total_seconds()))
def __init__(self, offset, name=None):
self.offset = timedelta(seconds=offset)
self.name = name or self.__class__.__name__
def utcoffset(self, dt):
return self.offset
def tzname(self, dt):
return self.name
def dst(self, dt):
return timedelta(0)
def to_datetime_tz(dt): # type: (str) -> datetime
fmt = '%Y-%m-%dT%H:%M:%S.%f'
if dt[-6] in frozenset(('+', '-')):
dt, sign, offset = strptime(dt[:-6], fmt), dt[-6], dt[-5:]
return datetime.fromtimestamp(mktime(dt),
tz=MyUTCOffsetTimezone.with_offset(offset, sign))
elif dt[-1] == 'Z':
return datetime.strptime(dt, fmt + 'Z')
return datetime.strptime(dt, fmt)
แต่นั่นไม่ได้ผลกับเขตเวลาเชิงลบ อย่างไรก็ตามฉันทำงานได้ดีใน Python 3.7.3:
from datetime import datetime
def to_datetime_tz(dt): # type: (str) -> datetime
fmt = '%Y-%m-%dT%H:%M:%S.%f'
if dt[-6] in frozenset(('+', '-')):
return datetime.strptime(dt, fmt + '%z')
elif dt[-1] == 'Z':
return datetime.strptime(dt, fmt + 'Z')
return datetime.strptime(dt, fmt)
การทดสอบบางอย่างโปรดทราบว่าผลลัพธ์จะแตกต่างกันไปตามความแม่นยำของไมโครวินาที มีความแม่นยำ 6 หลักในเครื่องของฉัน แต่ YMMV:
for dt_in, dt_out in (
('2019-03-11T08:00:00.000Z', '2019-03-11T08:00:00'),
('2019-03-11T08:00:00.000+11:00', '2019-03-11T08:00:00+11:00'),
('2019-03-11T08:00:00.000-11:00', '2019-03-11T08:00:00-11:00')
):
isoformat = to_datetime_tz(dt_in).isoformat()
assert isoformat == dt_out, '{} != {}'.format(isoformat, dt_out)
frozenset(('+', '-'))
ไหมว่าทำไมคุณถึงทำ tuple ปกติไม่ควร('+', '-')
จะสามารถทำสิ่งเดียวกันได้หรือไม่?