datetime 解析年月月的逻辑是什么?

What is the logic of parsing datetime with years and months?

我不确定为什么当带有“%Y%m”的“200013”失败而带有“%Y”的“200011”时,“200011”以“%Y%m”作为格式解析为 2000-11-01 %m%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)

有什么想法吗?

整数13没有对应的月份,所以在1被解析为月份后,你必须添加一个说明符来解析3

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

'200011' 有效是因为 11 对应于 11 月,可以安全地解析为一个月,而未指定日期时默认为 1。

示例: 缺少月份、日期、小时和分钟,因此将这些设置为默认值:

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为有效月份。现在 rest 设置为默认值(就像我在最上面给出的示例一样)。

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

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

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 Month as a zero-padded decimal number.

不过也提到了

The full set of format codes supported varies across platforms, because Python calls the platform C library’s strftime() function, and platform variations are common.

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

%Y The full year {4}; leading zeros shall be permitted but shall not be required. A leading '+' or '-' character shall be permitted before any leading zeros but shall not be required.

%m The month number [01,12]; leading zeros shall be permitted but shall not be required.

%d The day of the month [01,31]; leading zeros shall be permitted but shall not be required.

强调我的。来源 here


因此,在知道可能存在或不存在前导零的情况下,所有提到的情况都已正确说明:

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

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

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

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

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

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