如何将ISO 8601日期时间字符串转换为Python日期时间对象?

我得到一个像“2009-05-28T16:15:00”(这是ISO 8601,我相信)格式的日期时间字符串一个hack-ish选项似乎是使用time.strptime解析字符串,并通过首先将6个元素的touple插入到datetime构造函数中,如:

 datetime.datetime(*time.strptime("2007-03-04T21:08:12", "%Y-%m-%dT%H:%M:%S")[:6]) 

我一直没有找到一个“干净”的方式来做到这一点,有吗?

我更喜欢使用dateutil库进行时区处理,并且通常使用固定日期解析。 如果你想获得一个ISO 8601字符串,比如:2010-05-08T23:41:54.000Z你会有一个有趣的时间用strptime解析,特别是如果你不知道时区是否包含在内。 pyiso8601有几个问题(检查他们的跟踪器),我在使用过程中遇到过,并且在几年内还没有更新。 相反,dateutil一直在为我工作:

 import dateutil.parser yourdate = dateutil.parser.parse(datestring) 

用Python 2.5:

 datetime.datetime.strptime( "2007-03-04T21:08:12", "%Y-%m-%dT%H:%M:%S" ) 

由于RFC 3339允许存在许多可选冒号和破折号的变体,基本上是CCYY-MM-DDThh:mm:ss[Z|(+|-)hh:mm] 。 如果你想使用strptime,你需要首先去掉这些变体。

目标是生成一个utc日期时间对象。


如果你只是想要一个基本的情况下工作的UTC与Z后缀像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-04002008-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可能无法在python版本<3的系统上工作,因为它依赖于系统/ python构建类型(即Jython,Cython等)不同的c库支持。

 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 

箭头看起来很有希望:

 >>> import arrow >>> arrow.get('2014-11-13T14:53:18.694072+00:00').datetime datetime.datetime(2014, 11, 13, 14, 53, 18, 694072, tzinfo=tzoffset(None, 0)) 

Arrow是一个Python库,提供了创建,操作,格式化和转换日期和时间的明智的智能方式。 箭头简单,轻便,深受moment.js和请求的启发。

您应该留意时区信息,因为您可能在将非tz感知日期时间与tz感知日期时间进行比较时遇到麻烦。

这可能是最好的,总是让他们知道(即使只是作为utc),除非你真的知道为什么这样做没有任何用处。

 #----------------------------------------------- import datetime import pytz import dateutil.parser #----------------------------------------------- utc = pytz.utc BERLIN = pytz.timezone('Europe/Berlin') #----------------------------------------------- def to_iso8601(when=None, tz=BERLIN): if not when: when = datetime.datetime.now(tz) if not when.tzinfo: when = tz.localize(when) _when = when.strftime("%Y-%m-%dT%H:%M:%S.%f%z") return _when[:-8] + _when[-5:] # remove microseconds #----------------------------------------------- def from_iso8601(when=None, tz=BERLIN): _when = dateutil.parser.parse(when) if not _when.tzinfo: _when = tz.localize(_when) return _when #----------------------------------------------- 

我还没有尝试过,但pyiso8601承诺支持这一点。

Isodate似乎拥有最完整的支持。

 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 

这还包括毫秒和时区。

如果时间是“2012-09-30T15:31:50.262-08:00”,则会转换为纪元时间。

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

双向:

纪元ISO时间:

 isoTime = time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime(epochTime)) 

ISO时代到时代:

 epochTime = time.mktime(time.strptime(isoTime, '%Y-%m-%dT%H:%M:%SZ')) 

aniso8601应该处理这个。 它也了解时区,python2和python3,并且如果您需要,还可以合理地涵盖ISO8601的其余部分。

 import aniso8601 aniso8601.parse_datetime('2007-03-04T21:08:12') 

这是一个简单的方法来做这种转换。 不需要解析或额外的库。 清洁,简单,快速。

 import datetime import time ################################################ # # Takes the time (in seconds), # and returns a string of the time in ISO8601 format. # Note: Timezone is UTC # ################################################ def TimeToISO8601(seconds): strKv = datetime.datetime.fromtimestamp(seconds).strftime('%Y-%m-%d') strKv = strKv + "T" strKv = strKv + datetime.datetime.fromtimestamp(seconds).strftime('%H:%M:%S') strKv = strKv +"Z" return strKv ################################################ # # Takes a string of the time in ISO8601 format, # and returns the time (in seconds). # Note: Timezone is UTC # ################################################ def ISO8601ToTime(strISOTime): K1 = 0 K2 = 9999999999 K3 = 0 counter = 0 while counter < 95: K3 = (K1 + K2) / 2 strK4 = TimeToISO8601(K3) if strK4 < strISOTime: K1 = K3 if strK4 > strISOTime: K2 = K3 counter = counter + 1 return K3 ################################################ # # Takes a string of the time in ISO8601 (UTC) format, # and returns a python DateTime object. # Note: returned value is your local time zone. # ################################################ def ISO8601ToDateTime(strISOTime): return time.gmtime(ISO8601ToTime(strISOTime)) #To test: Test = "2014-09-27T12:05:06.9876" print ("The test value is: " + Test) Ans = ISO8601ToTime(Test) print ("The answer in seconds is: " + str(Ans)) print ("And a Python datetime object is: " + str(ISO8601ToDateTime(Test)))