Python有没有相当于C#中DateTime.TryParse()的方法?

35 投票
8 回答
33177 浏览
提问于 2025-04-16 21:02

在Python中有没有类似于C#的 DateTime.TryParse() 这样的功能呢?

我指的是它可以避免抛出错误,而不是说它能猜测日期格式。

8 个回答

5

不,你问的这个问题在Python中并不是常见的写法,所以标准库里一般不会有那种直接忽略错误的函数。相关的标准库模块可以在这里找到:

http://docs.python.org/library/datetime.html

http://docs.python.org/library/time.html

所有的解析函数在输入不合法时都会抛出错误。

不过,正如其他回答所说,为你的应用程序构建一个这样的函数并不是特别困难(你问的问题是“在Python中”而不是“在Python标准库中”,所以不太清楚帮助你写这样一个“在Python中”的函数是否算是回答了你的问题)。

14

我们想要尝试多种日期时间格式 fmt1, fmt2,...,fmtn,并处理那些不匹配的错误(这些错误来自 strptime),特别是希望避免使用一大堆嵌套的 try..catch 语句。这个问题在现实数据中很常见,因为数据集中常常会混合多种不匹配、不完整、不一致以及多语言/地区的日期格式。

1) 单独尝试每种格式,并将每次 strptime() 失败处理为返回值 None,这样你可以链式调用函数...

首先,从 @OrWeis 的答案中简化一下:

def try_strptime_single_format(s, fmt):
    try:
        return datetime.datetime.strptime(s, fmt)
    except ValueError:
        return None

现在你可以像这样调用 try_strptime(s, fmt1) 或 try_strptime(s, fmt2) 或 try_strptime(s, fmt3) ... 但是我们可以进一步改进:

2) 应用多种可能的格式(可以作为参数传入或使用合理的默认值),遍历这些格式,内部捕获并处理任何错误:

更简洁、更简单且更面向对象的做法是将 formats 参数设置为单个字符串或列表,然后遍历这个列表...这样你的调用就简化为 try_strptime(s, [fmt1, fmt2, fmt3, ...])

def try_strptime(s, fmts=['%d-%b-%y','%m/%d/%Y']):
    for fmt in fmts:
        try:
            return datetime.strptime(s, fmt)
        except:
            continue

    return None # or reraise the ValueError if no format matched, if you prefer

(顺便提一下,...finally 不是我们想要的,因为它会在每次循环后执行,也就是说在每个候选格式上执行,而不是在循环结束时执行一次。)

我发现第二种实现方式更简洁、更好。特别是这个函数/方法可以存储一个默认格式的列表,这样在处理现实数据时更安全,也不容易出现异常。(我们甚至可以根据其他列推断出应该使用哪些默认格式,比如在德语数据上优先尝试德语日期格式,在阿拉伯语数据上尝试阿拉伯格式,在网页日志数据上使用网页日志的日期时间格式等等。)

29

如果你不想遇到错误,那就去处理这个错误。

try:
    d = datetime.datetime.strptime(s, "%Y-%m-%d %H:%M:%S")
except ValueError:
    d = None

在Python的哲学中,明确的比隐含的要好。strptime 总是返回一个按照你指定的格式解析的日期时间。这是有道理的,因为你需要定义在失败时该怎么处理,也许你真正想要的是这样的行为。

except ValueError:
    d = datetime.datetime.now()

或者

except ValueError:
    d = datetime.datetime.fromtimestamp(0)

或者

except ValueError:
    raise WebFramework.ServerError(404, "Invalid date")

通过明确地说明,下一位阅读代码的人就能清楚地知道在出错时应该怎么处理,这样的处理方式也是你所需要的。


或者你可能很确定日期不会无效;比如它来自数据库的DATETIME列,这种情况下就不会有错误需要处理,所以就不需要去捕捉它。

撰写回答