strptime的误解

under python

in tech

Published: 2016-10-13

strptime在解析%Y%m%d%H%M%S这样的格式时,有时位数不足14位仍能正确解析,以前以为不足的部分(时、分、秒)用0补充,但试验后发现不是。

>>> from datetime import datetime
>>> datetime.strptime('20151111000000', '%Y%m%d%H%M%S')
datetime.datetime(2015, 11, 11, 0, 0)
>>> datetime.strptime('2015111100000', '%Y%m%d%H%M%S')
datetime.datetime(2015, 11, 11, 0, 0)
>>> datetime.strptime('201511110000', '%Y%m%d%H%M%S')
datetime.datetime(2015, 11, 11, 0, 0)
>>> datetime.strptime('20151111000', '%Y%m%d%H%M%S')
datetime.datetime(2015, 11, 11, 0, 0)
>>> datetime.strptime('2015111100', '%Y%m%d%H%M%S')
datetime.datetime(2015, 11, 1, 1, 0)
>>> datetime.strptime('201511110', '%Y%m%d%H%M%S')
datetime.datetime(2015, 1, 1, 1, 1)
>>> datetime.strptime('20151111', '%Y%m%d%H%M%S')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python2.7/_strptime.py", line 325, in _strptime
    (data_string, format))
ValueError: time data '20151111' does not match format '%Y%m%d%H%M%S'

除了年必须是4位的,从月到秒都可以只有1位,看过源码后发现确实如此,_strptime使用正则表达式实现的,所涉及的各部分正则表达式定义如下:

'Y': r"(?P<Y>\d\d\d\d)",
'm': r"(?P<m>1[0-2]|0[1-9]|[1-9])",
'd': r"(?P<d>3[0-1]|[1-2]\d|0[1-9]|[1-9]| [1-9])",
'H': r"(?P<H>2[0-3]|[0-1]\d|\d)",
'M': r"(?P<M>[0-5]\d|\d)",
'S': r"(?P<S>6[0-1]|[0-5]\d|\d)",

唯一的要求是字符串和格式能完全匹配,即使有歧义也没关系,不能完全匹配则会抛出ValueError异常。

found = format_regex.match(data_string)
if not found:
    raise ValueError("time data %r does not match format %r" %
                     (data_string, format))
if len(data_string) != found.end():
    raise ValueError("unconverted data remains: %s" %
                      data_string[found.end():])

这样处理是合适的,如何使用不产生歧义是用户的责任,不应该让datetime库来背。如果不想产生歧义,有两种解决方式:

(完)