我如何解释 Python 中的原始年份 RFC 3339 日期时间字符串?

How can I interpret a year-naive, RFC 3339 datetime string in Python?

我正在与一个 API 交互,它给出了代表用户生日的原始 RFC 3339 日期时间字符串。当然,我想将其解释为某种 datetime 对象 - 但是,python datetime 库不支持值小于 1 的日期时间字符串。

这是 API 给出的示例日期时间字符串:0000-09-01T00:00:00-00:00(注意年份设置为 0000)。如果我只是将其放入 datetime.fromisoformat,它会引发一个错误:

In [1]: from datetime import datetime

In [2]: datetime.fromisoformat("0000-09-01T00:00:00-00:00")
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-2-e1d8a5624d92> in <module>
----> 1 datetime.fromisoformat("0000-09-01T00:00:00-00:00")

ValueError: year 0 is out of range

如果我要完全删除字符串的年份部分,它会给出以下内容:

In [1]: from datetime import datetime

In [2]: datetime.fromisoformat("09-01T00:00:00-00:00")
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-2-a027335f00c1> in <module>
----> 1 datetime.fromisoformat("09-01T00:00:00-00:00")

ValueError: Invalid isoformat string: '09-01T00:00:00-00:00'

起初,我认为这是一个错误或限制。但经过一番研究,我发现 RFC3339 Standard 在其介绍中指出以下内容:

All dates and times are assumed to be in the "current era", somewhere between 0000AD and 9999AD.

假设这个范围是包含在内的(这是基于标准中术语“between”的其他用法,虽然它从未被严格指定),这意味着 datetime 模块不符合 RFC3339标准,因为它硬编码了最小和最大年份值,并使其成为必需值。但是,它从不声称它确实符合标准。所以新问题是,如果包含的库不支持 RFC3339,那什么支持?

我的问题是:是否有方法将此字符串解释为某种日期时间对象或使用第三方库?

没有 year 0 in the Anno Domini 日期显示系统。

快速查看常见的日期时间替代项 (Pendulum, Arrow) 表明 ValueError 解析带有 0000- 作为年份的 ISO 格式字符串的错误是普遍存在的。那不是一个有效的年份,错误在于数据源。

只有一个月零一天的日期不是真正的日期 - 它是不明确的。日期 2/23 是在 3/1 之前还是之后? 2/23 + 6 天是二月底还是三月初?在这两种情况下,它完全取决于年份。

Square API 似乎使用 0000- 作为可选年份的标志,因为有些人不想透露他们的年龄。

如果您的数据标准化为 0000 年,您可以只进行字符串替换以标准化第 1 年:

from datetime import datetime

s="0000-09-01T00:00:00-00:00"

>>> datetime.fromisoformat(s.replace("0000-","0001-"))
datetime.datetime(1, 9, 1, 0, 0, tzinfo=datetime.timezone.utc)

或者,如评论中所述,也许使用 0004 来容纳 2/29 作为生日:

s="0000-02-29T00:00:00-00:00"

>>> datetime.fromisoformat(s.replace("0000-","0004-"))
datetime.datetime(4, 2, 29, 0, 0, tzinfo=datetime.timezone.utc)

这充其量只是部分解决方案。同样,没有年份的日期不是日期,您将需要编写和验证大量代码来尝试解决排序、比较、日期偏移、表示等方面的歧义。