2016-12-13 94 views
1

我想写一个函数,它接受一个字符串,并返回True,如果它是一个有效的ISO-8601日期时间 - 精确到微秒,包括时区偏移量 - 否则为False在Python中验证ISO-8601 datetime字符串?

我发现otherquestions提供解析日期时间字符串的方式不同,但我想只有ISO-8601格式的情况下返回True。解析不会帮助我,除非我可以让它为与ISO-8601不匹配的格式引发错误。

(我在别处使用nice arrow库在我的代码使用arrow会欢迎的解决方案。)


编辑:看来,一个通用的解决方案,以“这是字符串有效的ISO 8601 datetime“在公共Python日期时间程序包中不存在。

因此,为了使这个问题更窄,更具体,更交代,我会满足于一个格式字符串,将这种形式验证的时间字符串:

'2016-12-13T21:20:37.593194+00:00' 

目前我使用:

format_string = '%Y-%m-%dT%H:%M:%S.%f%z' 
datetime.datetime.strptime(my_timestamp, format_string) 

这给:

ValueError: time data '2016-12-13T21:20:37.593194+00:00' does not match format '%Y-%m-%dT%H:%M:%S.%f%z' 

的问题似乎在于用的UTC结肠fset(+00:00)。如果我使用不带冒号的偏移量(例如'2016-12-13T21:20:37.593194+0000'),则按预期正确解析。这显然是因为datetime%z标记does not respect the UTC offset form that has a colon,只有表格没有,即使both are valid per the spec

+0

格式是足够严格单单通过艰难的方式验证它并不难。 –

+0

而你已经尝试......究竟是什么? – jonrsharpe

+1

你看过PyPI上的'iso8601'包吗? –

回答

1

鉴于您对问题所施加的限制,您可以使用正则表达式轻松解决该问题。

>>> import re 
>>> re.match(r'^\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d\.\d{6}[+-]\d\d:\d\d$', '2016-12-13T21:20:37.593194+00:00') 
<_sre.SRE_Match object; span=(0, 32), match='2016-12-13T21:20:37.593194+00:00'> 

如果你需要传递ISO 8601的所有变化将是一个更为复杂的正则表达式,但它仍然可以完成。如果您还需要验证数字范围,例如验证小时是在0到23之间,则可以将括号放入正则表达式中以创建匹配组,然后验证每个组。

+0

谢谢你的建议!我想避免滚动我自己的日期解析实现,因为其他人已经这样做了。我更喜欢不重新发明轮子,我更喜欢使用已被其他许多人使用和测试的代码,只要有可能。 – Stew

0

下面是使用datetime.strptime()粗但功能性溶液(对于更窄的问题):

import datetime 

def is_expected_datetime_format(timestamp): 
    format_string = '%Y-%m-%dT%H:%M:%S.%f%z' 
    try: 
     colon = timestamp[-3] 
     if not colon == ':': 
      raise ValueError() 
     colonless_timestamp = timestamp[:-3] + timestamp[-2:] 
     datetime.datetime.strptime(colonless_timestamp, format_string) 
     return True 
    except ValueError: 
     return False 
0

https://www.safaribooksonline.com/library/view/regular-expressions-cookbook/9781449327453/ch04s07.html

给出在ISO8601格式验证日期和时间(例如,2008-08-许多变型30T01:45:36或2008-08-30T01:45:36.123Z)。所以为了验证你可以做

>>> regex = r'^(-?(?:[1-9][0-9]*)?[0-9]{4})-(1[0-2]|0[1-9])-(3[01]|0[1-9]|[12][0-9])T(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])(\.[0-9]+)?(Z|[+-](?:2[0-3]|[01][0-9]):[0-5][0-9])?$' 

>>> import re 
>>> match_iso8601 = re.compile(regex).match 
>>> def validate_iso8601(str_val): 
...  try:    
...   if match_iso8601(str_val) is not None: 
...    return True 
...  except: 
...   pass 
...  return False 

一些例子:对XML Schema的DateTime类型的正则表达式给出

>>> validate_iso8601('2017-01-01') 
False 

>>> validate_iso8601('2008-08-30T01:45:36.123Z') 
True 

>>> validate_iso8601('2016-12-13T21:20:37.593194+00:00') 
True