Python strptime () และเขตเวลา?


157

ฉันมี CSV dumpfile จากข้อมูลสำรอง IPD ของ Blackberry สร้างขึ้นโดยใช้ IPDDump สตริงวันที่ / เวลาในที่นี่จะมีลักษณะดังนี้ ( ESTเขตเวลาของออสเตรเลีย):

Tue Jun 22 07:46:22 EST 2010

ฉันต้องสามารถแยกวิเคราะห์วันที่นี้ใน Python ได้ ตอนแรกฉันพยายามใช้strptime()ฟังก์ชั่นจากชุดข้อมูล

>>> datetime.datetime.strptime('Tue Jun 22 12:10:20 2010 EST', '%a %b %d %H:%M:%S %Y %Z')

อย่างไรก็ตามด้วยเหตุผลบางอย่างdatetimeวัตถุที่กลับมาดูเหมือนจะไม่มีความtzinfoเกี่ยวข้องใด ๆ

ฉันได้อ่านในหน้านี้ซึ่งเห็นได้ชัดว่าdatetime.strptimeทิ้งไปอย่างเงียบ ๆtzinfoอย่างไรก็ตามฉันตรวจสอบเอกสารและฉันไม่พบสิ่งใดที่มีผลต่อเอกสารดังกล่าวที่นี่

ฉันสามารถแยกวิเคราะห์วันที่โดยใช้ห้องสมุด Python ของบุคคลที่สามdateutilได้ แต่ฉันก็ยังสงสัยว่าฉันใช้ตัวที่สร้างขึ้นstrptime()ไม่ถูกต้องได้อย่างไร มีวิธีใดบ้างที่จะได้strptime()เล่นกับเขตเวลาอย่างดี?


1
คุณไม่เพียงแค่ ... แปลงวันที่ทั้งหมดเป็น GMT?
Robus

2
@ Robus: อืมฉันหวังว่าจะทำอย่างนั้น - แต่ฉันกำลังสมมติว่า strftime / datetime ทำอย่างนั้นได้หรือไม่? ไม่ว่าจะด้วยวิธีใดฉันต้องจัดเก็บ / แยกวิเคราะห์ข้อเท็จจริงว่าชุดข้อมูลอยู่ในเขตเวลา EST หรือเขตเวลาใดก็ตามที่เกิดขึ้นกับฉัน สคริปต์ต้องสามารถวิเคราะห์ชุดข้อมูลทั่วไปด้วยข้อมูลเขตเวลา (เช่น ETC อาจเป็นเขตเวลาอื่น)
victorhooi

3
EST ยังเป็นตัวย่อเขตเวลาของสหรัฐอเมริกา (ในทำนองเดียวกัน BST เป็นทั้งตัวย่อของสหราชอาณาจักรและเขตเวลาของบราซิล) ตัวย่อดังกล่าวมีความคลุมเครือโดยเนื้อแท้ ใช้ offsets สัมพันธ์กับ UTC / GMT แทน (หากคุณต้องการสนับสนุนตัวย่อคุณต้องทำการแมปโลแคลและเป็นรูชหนูที่ยุ่งเหยิง)
Donal Fellows

คำตอบ:


58

datetimeเอกสารโมดูลพูดว่า:

ส่งคืนวันที่และเวลาที่สอดคล้องกับ date_string แยกตามรูปแบบ datetime(*(time.strptime(date_string, format)[0:6]))นี้จะเทียบเท่ากับ

เห็น[0:6]ไหม (year, month, day, hour, minute, second)ที่ทำให้คุณได้รับ ไม่มีอะไรอีกแล้ว. ไม่มีการเอ่ยถึงเขตเวลา

น่าสนใจ [Win XP SP2, Python 2.6, 2.7] ส่งตัวอย่างของคุณไปtime.strptimeไม่ทำงาน แต่ถ้าคุณถอด "% Z" และ "EST" ออกมามันจะทำงาน นอกจากนี้ยังใช้ "UTC" หรือ "GMT" แทนที่จะใช้งาน "EST" "PST" และ "MEZ" ไม่ทำงาน ทำให้งง

เป็นที่น่าสังเกตว่านี่ได้รับการอัปเดตเป็นเวอร์ชัน 3.2 และเอกสารเดียวกันยังระบุสิ่งต่อไปนี้:

เมื่อคำสั่ง% z ถูกจัดเตรียมให้กับเมธอด strptime () จะมีการสร้างออบเจ็กต์วันที่และเวลาที่ทราบ tzinfo ของผลลัพธ์จะถูกตั้งค่าเป็นอินสแตนซ์ของเขตเวลา

โปรดทราบว่าสิ่งนี้ไม่สามารถใช้งานได้กับ% Z ดังนั้นเคสจึงมีความสำคัญ ดูตัวอย่างต่อไปนี้:

In [1]: from datetime import datetime

In [2]: start_time = datetime.strptime('2018-04-18-17-04-30-AEST','%Y-%m-%d-%H-%M-%S-%Z')

In [3]: print("TZ NAME: {tz}".format(tz=start_time.tzname()))
TZ NAME: None

In [4]: start_time = datetime.strptime('2018-04-18-17-04-30-+1000','%Y-%m-%d-%H-%M-%S-%z')

In [5]: print("TZ NAME: {tz}".format(tz=start_time.tzname()))
TZ NAME: UTC+10:00

13
งูหลามที่เกี่ยวข้องข้อผิดพลาด: % Z ใน strptime ไม่ตรงกับ EST และอื่น ๆ
jfs

353

ผมขอแนะนำให้ใช้หลาม dateutil โปรแกรมแยกวิเคราะห์มันสามารถแยกวิเคราะห์ทุกรูปแบบวันที่ที่ฉันส่งไปได้

>>> from dateutil import parser
>>> parser.parse("Tue Jun 22 07:46:22 EST 2010")
datetime.datetime(2010, 6, 22, 7, 46, 22, tzinfo=tzlocal())
>>> parser.parse("Fri, 11 Nov 2011 03:18:09 -0400")
datetime.datetime(2011, 11, 11, 3, 18, 9, tzinfo=tzoffset(None, -14400))
>>> parser.parse("Sun")
datetime.datetime(2011, 12, 18, 0, 0)
>>> parser.parse("10-11-08")
datetime.datetime(2008, 10, 11, 0, 0)

และอื่น ๆ ไม่มีการจัดการกับstrptime()เรื่องไร้สาระรูปแบบ ... เพียงแค่ใส่วันที่และสิ่งที่ถูกต้อง

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


เนื่องจากผู้คนจำนวนมากมักใช้ไพ ธ อน - ทู ธ ทิลฉันอยากจะชี้ให้เราทราบถึงข้อ จำกัด หนึ่งของ lib นั้น >>> parser.parse("Thu, 25 Sep 2003 10:49:41,123 -0300") Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/Users/wanghq/awscli/lib/python2.7/site-packages/dateutil/parser.py", line 748, in parse return DEFAULTPARSER.parse(timestr, **kwargs) File "/Users/wanghq/awscli/lib/python2.7/site-packages/dateutil/parser.py", line 310, in parse res, skipped_tokens = self._parse(timestr, **kwargs) TypeError: 'NoneType' object is not iterable
wanghq

1
@wanghq คุณต้องแทนที่เครื่องหมายจุลภาคสุดท้ายด้วยจุด จากนั้นparser.parse("Thu, 25 Sep 2003 10:49:41.123 -0300") returns: datetime.datetime(2003, 9, 25, 10, 49, 41, 123000, tzinfo=tzoffset(None, -10800))
flyingfoxlee

7
@flyingfoxlee ใช่ฉันเข้าใจแล้ว ฉันแค่อยากจะบอกผู้คนถึงข้อ จำกัด ของ python-dateutil มันทำสิ่งมหัศจรรย์ แต่บางครั้งก็ล้มเหลวในการทำเช่นนั้น ดังนั้น "เพียงแค่ใส่วันที่และสิ่งที่ถูกต้อง" ไม่เป็นความจริง 100%
wanghq

4
dateutil.parser.parse("10-27-2016 09:06 AM PDT")คืนค่า: datetime.datetime(2016, 10, 27, 9, 6)ล้มเหลวในการหาเขตเวลา ...
HaPsantran

2
ขึ้นอยู่กับเป้าหมาย dateutil parserอาจใช้งานง่าย แต่strptime()เร็วกว่า นอกจากนี้รูปแบบของมันค่อนข้างง่ายต่อการเรียนรู้
ลืมตัว

9

สตริงเวลาของคุณมีลักษณะคล้ายกับรูปแบบเวลาในRFC 2822 (รูปแบบวันที่ในอีเมล http หัว) คุณสามารถวิเคราะห์โดยใช้ stdlib เท่านั้น:

>>> from email.utils import parsedate_tz
>>> parsedate_tz('Tue Jun 22 07:46:22 EST 2010')
(2010, 6, 22, 7, 46, 22, 0, 1, -1, -18000)

ดูการแก้ปัญหาที่วัตถุผลผลิตเขตตระหนักถึงวันที่และเวลาสำหรับรุ่นหลามต่างๆ: แยกวันที่มีเขตเวลาจากอีเมล์

ในรูปแบบนี้ คือความหมายเทียบเท่ากับEST -0500แม้ว่าโดยทั่วไปย่อเขตเวลาไม่เพียงพอที่จะระบุเขตเวลาที่ไม่ซ้ำกัน


0

วิ่งเข้าไปหาปัญหาตรงนี้

สิ่งที่ฉันทำลงไป:

# starting with date string
sdt = "20190901"
std_format = '%Y%m%d'

# create naive datetime object
from datetime import datetime
dt = datetime.strptime(sdt, sdt_format)

# extract the relevant date time items
dt_formatters = ['%Y','%m','%d']
dt_vals = tuple(map(lambda formatter: int(datetime.strftime(dt,formatter)), dt_formatters))

# set timezone
import pendulum
tz = pendulum.timezone('utc')

dt_tz = datetime(*dt_vals,tzinfo=tz)
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.