使用零填充格式的 python datetime strptime 的意外行为

问题描述

我有以不同格式表示日期时间的字符串列表。即:

list_date_str = ['2021010112','202101011210']

一个应转换为 2021-01-01 12:00,第二个应转换为 2021-01-01 12:10。 我没有多想就写了这个片段:

import datetime as dt

for date_str in list_date_str:
    try:
        date = dt.datetime.strptime(date_str,'%Y%m%d%H%M')
    except ValueError:
        date = dt.datetime.strptime(date_str,'%Y%m%d%H') 
    print(date)

经过艰苦的错误搜索,我意识到第一个字符串没有按预期解析。代码给出:

2021-01-01 01:02:00
2021-01-01 12:10:00

我确实明白发生了什么:永远不会到达except-block。相反,“2021010112”的倒数第二个字符被解释为小时数字,最后一个字符被解释为分钟数字。

这是假设的行为吗? datetime doc 明确指出 %H 表示补零十进制数以及 %M。

我是不是没明白,还是文档只是在误导?为什么 try 块不会引发 ValueError?

是否有一种既方便又可靠的方法解决这个问题?我知道在这种特殊情况下,可以通过交换 try- 和 expect- 块来修复代码。但这不是正确的做法。

PS:这个问题也适用于 pd.to_datetime。

解决方法

使用 len 从字典中获取字符串长度和时间格式。

例如:

import datetime
list_date_str = ['2021010112','202101011210']

frmt = {10: '%Y%m%d%H',12: '%Y%m%d%H%M'}
for date_str in list_date_str:
    try:
        print(datetime.datetime.strptime(date_str,frmt.get(len(date_str))))
    except:
        raise Exception("Date Format Not Found.")
,

也许最简单的方法是在需要时对日期时间字符串进行零填充:

list_date_str = ['2021010112','202101011210']

for date_str in list_date_str:
    try:
        date = dt.datetime.strptime(f'{date_str:0<12}','%Y%m%d%H%M')
    except ValueError:
        print(f'Failed to convert {date_str!r}')
        continue 
    print(date)

此处 fstring f'{date_str:0<12}' 用于使用字段宽度 12 对字符串的末尾进行零填充。这也允许解析可能根本没有时间分量的较短字符串:

>>> list_date_str = ['2021010112','202101011210','baddate','20210101','2021']
>>> for date_str in list_date_str:
...     try:
...         date = dt.datetime.strptime(f'{date_str:0<12}','%Y%m%d%H%M')
...     except ValueError:
...         print(f'Failed to convert {date_str!r}')
...         continue 
...     print(date)
... 
2021-01-01 12:00:00
2021-01-01 12:10:00
Failed to convert 'baddate'
2021-01-01 00:00:00
Failed to convert '2021'
,

我怀疑文档更准确地反映了字符串格式,而不是字符串解析。

就您而言,实际问题是您的数据格式不一致。我不会依赖解析尝试来确定它应该被解析为什么格式。相反,您应该明确检查例如你的字符串的长度来决定你想用什么格式来解析它。这也让您能够优雅地处理这里描述的两种情况。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...