简体   繁体   English

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

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

I am interfacing with an API which gives year-naive RFC 3339 datetime strings for representing a users birthday.我正在与一个 API 进行交互,它提供了用于表示用户生日的原始 RFC 3339 日期时间字符串。 Naturally, I want to interpret this as some sort of datetime object - However, the python datetime library doesn't support datetime strings with values less than one.自然,我想将此解释为某种datetime时间 object - 但是,python datetime时间库不支持值小于 1 的日期时间字符串。

Here's an example datetime string given by the API: 0000-09-01T00:00:00-00:00 (Notice the year is set to 0000 ).这是 API 给出的示例日期时间字符串: 0000-09-01T00:00:00-00:00 (注意年份设置为0000 )。 If I were to just throw this into datetime.fromisoformat , it unsuprisingly raises an error:如果我只是把它扔进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

If I were to entirely remove the year section of the string, It gives the following:如果我要完全删除字符串的年份部分,它会给出以下内容:

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'

At first, I thought this was a bug or limitation.起初,我认为这是一个错误或限制。 But after a little research, I found that the RFC3339 Standard states the following in its introduction:但经过一番研究,我发现RFC3339 标准在其介绍中声明了以下内容:

All dates and times are assumed to be in the "current era", somewhere between 0000AD and 9999AD.假定所有日期和时间都在“当前时代”,介于公元 0000 年和公元 9999 年之间。

Assuming that this range is inclusive (This is based on the other uses of the term "between" within the standard, although it is never strictly specified), it is implied that the datetime module does not conform to the RFC3339 standard as it hard codes a minimum and maximum year value and also makes it a required value.假设这个范围是包容性的(这是基于标准中“介于”一词的其他用途,尽管从未严格指定),暗示 datetime 模块不符合 RFC3339 标准,因为它是硬编码的最小和最大年份值,并使其成为必需值。 However, it never claims that it does conform to the standard.但是,它从未声称它确实符合标准。 So the new issue is that if the included library doesn't support RFC3339, what does?所以新的问题是,如果包含的库不支持 RFC3339,那是什么?

My question is: Is there a method of interpreting this string as some kind of datetime object or use a third-party library?我的问题是:有没有一种方法可以将此字符串解释为某种日期时间 object 或使用第三方库?

There is no year 0 in the Anno Domini date presentation system. Anno Domini日期显示系统中没有年份 0

A quick look at the common datetime alternatives ( Pendulum , Arrow ) show that the ValueError error for parsing an ISO format string with 0000- as the year is universal.快速浏览一下常见的日期时间替代方案( PendulumArrow )表明,使用0000-解析 ISO 格式字符串的ValueError错误是通用的。 That is not a valid year and the error lies with the data source.那不是一个有效的年份,错误在于数据源。

A date with only a month and a day is not really a date - it is ambiguous.只有一个月和一天的日期并不是真正的日期 - 它是模棱两可的。 Is the date 2/23 before or after 3/1 ?日期2/23是在3/1之前还是之后? Is 2/23 + 6 days the end of February or the first of March? 2/23 + 6 天是 2 月底还是 3 月初? In both cases, it depends entirely on the year.在这两种情况下,这完全取决于年份。

It appears that the Square API is using 0000- as a flag for the year being optional since some people do not want to disclose their age. Square API似乎使用0000-作为可选年份的标志,因为有些人不想透露他们的年龄。

If your data is standardized to year 0000 , you can probably just do a string replacement to standardize on year 1:如果您的数据标准化为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)

Or, as stated in comments, perhaps use 0004 to accommodate 2/29 as a birthday:或者,如评论中所述,也许使用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)

This is a partial solution at best.这充其量只是部分解决方案。 Again, a date without a year is not a date and you will need to write and validate a lot of code to try and solve the ambiguity for sorting, comparisons, date offsets, presentation, etc.同样,没有年份的日期不是日期,您需要编写和验证大量代码来尝试解决排序、比较、日期偏移、表示等方面的歧义。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM