使用年和月解析日期时间的逻辑是什么?

时间:2016-11-28 17:52:11

标签: python python-3.x datetime strptime

我不确定为什么'200011'用'%Y%m'解析为'%Y%m'为'%Y%m'失败的'200013'和'%Y%m'为'200011'的格式? %d'成功。见代码:

>>> datetime.datetime.strptime('200013', '%Y%m')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File ".../lib/python3.5/_strptime.py", line 510, in _strptime_datetime
    tt, fraction = _strptime(data_string, format)
  File ".../lib/python3.5/_strptime.py", line 346, in _strptime
    data_string[found.end():])
ValueError: unconverted data remains: 3
>>> datetime.datetime.strptime('200011', '%Y%m')
datetime.datetime(2000, 11, 1, 0, 0)
>>> datetime.datetime.strptime('200011', '%Y%m%d')
datetime.datetime(2000, 1, 1, 0, 0)

任何想法发生了什么?

3 个答案:

答案 0 :(得分:3)

TL; DR:Python文档忽略了零填充月是可选的

>>> from datetime import datetime
>>> pattern = '%Y%m'
>>> datetime.strptime('20161', pattern).strftime(pattern)
'201601'  # Note an extra "0" has appeared

strptimestrftime的时间格式来自C标准库。这里的Python文档有点缺乏一些重要的细节,Python文档中的relevant section只是说:

  

%m月份为零填充十进制数。

但是也提到了

  

支持的全套格式代码因平台而异,因为Python调用平台C库的strftime()函数,并且平台变体很常见。

这里导致令人惊讶的结果的行为,即前导零的处理,更好地记录在C:

  

%Y   全年{4};应允许前导零,但不应要求。在任何前导零之前允许使用前导'+'或' - '字符,但不需要。

     

%米   月份号[01,12];应允许前导零,但不得要求。

     

%d   每月的某一天[01,31];应允许前导零,但不得要求。

强调我的。来源here

因此,在知道前导零可能存在或不存在的情况下,所有提到的案例都被正确解释:

datetime.strptime('200013', '%Y%m')  # Can not parse

由于13不是有效月份,因此解析强制取1是省略前导零的月份。然后你得到ValueError,因为解析器不知道如何处理额外的数据“3”。

datetime.datetime.strptime('200011', '%Y%m')  # Parses to 1st Nov

解析器将11月(11)作为月份。 Day只是默认为1.这里的月份不可能是1月份,因为这会使这种模式的额外数据无法计算 - 剩下的会有一个额外的“1”剩余。因此,解析器必须贪婪并且在本月消耗'11'。

datetime.datetime.strptime('200011', '%Y%m%d')  # Parses to 1st Jan

在这里,我们看到模式%Y%m%Y%m%d可以成功解析'200011'。如果您使用%Y%m%d模式进行解析,那么您将被迫将月份视为1月(1),否则没有剩余数据填充%d。请注意,%d的前导零也是可选的。

答案 1 :(得分:2)

整数13没有相应的月份,因此在3被解析为月份之后,您必须添加一个说明符来解析1

>>> datetime.datetime.strptime('200013', '%Y%m%d')
datetime.datetime(2000, 1, 3, 0, 0)

'200011'有效,因为11对应11月,可以安全地解析为月份,而未指定时则默认为1。

答案 2 :(得分:0)

实施例: 月,日,小时和分钟缺失,因此这些设置为默认值:

  
    
      

datetime.datetime.strptime('2000','%Y')       datetime.datetime(2000,1,1,0,0)

    
  

月,小时和分钟设置为默认值:

  
    
      

datetime.datetime.strptime('200012','%Y%d')       datetime.datetime(2000,1,12,0,0)

    
  

在你的例子中,它寻找一个月作为第二个参数,但没有'13'月 - datetime.datetime.strptime('200013','%Y%m')

但是当你说,datetime.datetime.strptime('200013','%Y%m%d')时,它会查找年份:2000,月,因为13无效,它需要1个月, 3日当天

最后,在这种情况下:datetime.datetime.strptime('200011','%Y%m'),它查找年份,2000年有效年份,查找月份,11月份是有效月份。现在休息被设置为默认值(就像我在最顶部给出的例子一样)。

注意以下命令,默认为月份,并将13作为有效日期。

  
    
      

datetime.datetime.strptime('200013','%Y%d')       datetime.datetime(2000,1,13,0,0)