如何编写带有时区但没有时间组件的 ISO 8601 日期

How can I write an ISO 8601 date with a timezone but no time component

带有时区的 ISO 8601 datetime 格式如下:

2018-09-07T05:28:42Z

但是,我需要在我的系统中表示一些精度为天而不是秒的日期,这意味着它将是 ISO 8601 calendar date。日历日期格式如下:

2018-09-07

在有关该标准的维基百科文章中(我无权访问该标准本身,因为您必须为该特权付费),在讨论日期时没有提及时区。它确实谈到了省略部分时间:

Either the seconds, or the minutes and seconds, may be omitted from the basic or extended time formats for greater brevity but decreased accuracy: [hh]:[mm], [hh][mm] and [hh] are the resulting reduced accuracy time formats.

由此看来,你不能省略小时,所以我不能这样写日历日期:

2018-09-07TZ

看来我能做的最好的事情就是缩短到小时:

2018-09-07T00Z

但是,如果可以避免,我不想这样做,因为我为日期增加了比实际更精确的日期。日期表示 "sometime during the day of 07 September, 2018 in the UTC timezone",而不是 "sometime during the midnight hour of 07 September, 2018 in the UTC timezone"。

有什么建议吗?

带时区的日期没有意义,因为时区会在一天内调整 hours/minutes。也许你有一个日期和一个单独的时区,你需要不同的东西?如果您需要国际日期变更线的时区,您还需要格式为 hours:minutes 的时间,否则时区将没有意义。

顺便说一句。 W3C 也有一些关于 ISO8601 Date and Time Formats 的例子。 最后但同样重要的是,您始终可以编写自己的解析器,例如 Antlr.

另请记住,时区 might/will 会随着时间而变化 - 例如正常时间与夏令时。

这里的主要问题(对我来说)似乎是你用什么写出你的date/time。

举个例子,在 C++ 中你可以这样做:

time_t n = std::time(NULL);

tm *now = std::localtime(&n);

std::cout << std::put_time(now, "%F %z") << '\n';

这会产生如下输出:

2018-09-07 -0700

如果您真正的问题是这是否对应于 ISO 8601 中指定的格式,我相信答案是否定的。但是制作它还是相当容易的。

哦,至少在 IMO 上,是的,只有带时区的日期就非常有意义。即使你只关心日期,时区也会告诉你那个日期 begins/ends 相对于地球上其他地方的时间,所以如果我说“2019 年 1 月 1 日 PDT”,(比如说)伦敦的某个人知道这个日期有问题的是从他的本地日期偏移 7 小时。

正式地,ISO 8601 规范不允许带有时区的日期,除非提供了时间。因此,如果您希望保持 ISO 8601 合规性,则不能为仅日期值提供除年、月和日之外的其他信息(不求助于时间间隔 - 下文将进一步提及)。

允许的一种格式是 XML 架构(又名 "XSD"),在 xs:date type. There, it is optional, and would immediately follow the day, such as 2018-09-07Z. The XSD spec calls out in Section D.3 Deviations from ISO 8601 Formats:

D.3.4 Time zone permitted
The lexical representations for the datatypes date, gYearMonth, gMonthDay, gDay, gMonth and gYear permit an optional trailing time zone specificiation.

我知道你不是在问 XSD,但这是我所知道的唯一可在网上免费获得的、标明日期时区的规范性参考,与 ISO 8601 有偏差。

正如其他人指出的那样 - 考虑带时区的约会是一件棘手的事情。在许多方面,仅日期值是不明确的。考虑一下我是否向您展示了这样一个日历:

指向此日历上的任何给定日期都不会告诉我有关时区的任何信息。我可以把日历给不同时区的人,他们仍然可以谈论日期。很简单,如果我们同时指向 "today",我们 可能 不会指向同一日期。因此,时区仅在我们应用时间上下文时适用,无论是 "now" 还是特定时间上下文。

但是,我们确实倾向于根据时区合理化给定日期的所有时间点。在您的示例中,"UTC Day"。我们的意思是它从一天的 T00:00Z 运行到下一天的 T00:00Z 之前。这通常是 xs:date 允许时区偏移的原因。

如果我们想严格符合 ISO 8601 并表示相同的含义,我们必须提供一系列日期+时间值,在 ISO 8601 规范的第 4.4 节中称为 "time intervals" , 并用正斜杠 (/) 字符分隔。这种值的一个例子是 2018-09-07T00:00Z/2018-09-08T00:00Z。但是,要小心,因为 ISO 8601 说 nothing 关于结束日期应该被解释为包含还是排除。 .

间隔的另一种 ISO 8601 表示允许开始时间和 持续时间 组件,例如 2018-09-07T00:00Z/P1D。在我看来,这就像最接近完全符合 ISO 8601 标准的方式来表示以 UTC 解释的整个日期。

不过,就我个人而言,如果我需要用日期来传达时区,我会使用 2018-09-07Z,即使它不严格符合要求。只需确保您数据的所有消费者都同意这种格式。如果你不能这样做,只需传递 2018-09-07 并将你的字段命名为 utcDate.