使用 Python 解析北欧格式日期(首先是 DMY,然后是 YMD)的最佳方法

elg*_*lge 5 python date-parsing

我正在寻找一种按优先顺序使用以下“元格式”来解析未知格式的日期的方法:

  1. 日-月-年 (DMY)
  2. 年月日 (YMD)
  3. 可能是其他格式(但这并不重要)

这是来自挪威、丹麦、芬兰和荷兰的几乎所有发票上实际存在的元格式,因此它应该是一个常见的用例。然而,似乎没有一个库能够在不需要定义大量可能格式的情况下处理它。

再具体一点。我需要一个方法 ( parse) 来满足以下条件: parse("01-02-03") == "datetime.datetime(2003, 2, 1, 0, 0)" parse("2003-02-01") == "datetime.datetime(2003, 2, 1, 0, 0)"

但它也应该适用于其他分隔符等。

关于如何在不定义大量格式列表的情况下实现这一点的任何建议?

编辑:由于瑞典有不同的偏好,我更喜欢一个可以概括为适用于 YMD 优于 DMY 的情况的答案。

elg*_*lge 0

正如 Scotty1 正确指出的那样,pandas.to_datetime它实际上适用于我描述的用例,但是它并不能推广到 YMD 优于 DMY 的用例(这恰好是瑞典的偏好)。

我最终得到了可以在超过 95% 的情况下工作的东西,这比任何现有的开箱即用的日期解析库可以匹配的要好得多。这是我的解决方案:

def parse(string):
    dmy = ['%d{sep}%m{sep}%Y', '%d{sep}%m{sep}%y']
    ymd = ['%Y{sep}%m{sep}%d', '%y{sep}%m{sep}%d']
    seperators = ['', ' ', '-', '.', '/']
    formats = [f.format(sep=sep) for f in dmy + ymd for sep in seperators]
    additional = ['%d/%m %Y']
    return dateparser.parse(string, date_formats=formats + additional)
Run Code Online (Sandbox Code Playgroud)

dmy + ymd对“YMD 优先于 DMY”的支持可以通过替换为 来实现ymd + dmy

为了帮助传达上述代码的行为,这里有一组全部通过的测试:

out = datetime.datetime(2003, 2, 1, 0, 0)

# straight forward DMY
assert out == extractors.extract_date('010203')
assert out == extractors.extract_date('01022003')
assert out == extractors.extract_date('01-02-03')
assert out == extractors.extract_date('01-02-2003')

# alternative delimiters
assert out == extractors.extract_date('01.02.03')
assert out == extractors.extract_date('01 02 03')
assert out == extractors.extract_date('01/02/03')
assert out == extractors.extract_date('01/02 2003')

# YMD (when the first cannot parse as a day, default to YMD)
assert out == extractors.extract_date('2003-02-01')
assert extractors.extract_date('98-02-01') == \
    datetime.datetime(1998, 2, 1, 0, 0)

# single digits
assert out == extractors.extract_date('1-2-2003')
assert out == extractors.extract_date('1/2 2003')
assert out == extractors.extract_date('2003-2-1')

# when there are not other possibilities (MDY, YDM)
assert extractors.extract_date('12-31-98') == \
    datetime.datetime(1998, 12, 31, 0, 0)
assert extractors.extract_date('98-31-12') == \
    datetime.datetime(1998, 12, 31, 0, 0)
Run Code Online (Sandbox Code Playgroud)