我目前正在开发一个应用程序,该应用程序需要处理复杂的本地化日期和时间。
作为一个简单的例子,如果一个事件没有发生;今天";在新加坡,这很容易表示:我们将日期存储在UTC中,即IANA时区Asia/Singapore
,也许还有给定时间戳(例如+08:00
)的有效UTC偏移量,这样我们就不必每次呈现它们时都查阅IANA数据库。
如果你不熟悉时区,那么处理时区绝对是疯狂的。我们不能仅仅假设新加坡总是+08:00:
- 夏令时可能会发生,也可能不会发生,不同地区在不同的日历日开始和结束夏令时,某些地区的夏令时偏移量可能超过或少于一小时
- 随着时间的推移,DST和实际UTC偏移量可能会发生变化。虚构的例子:
- 作为一个虚构的例子,1971年夏令时的开始和结束日期分别改为3月31日和10月1日,而不是2月27日和9月16日
- 1933年,夏令时偏移量从1小时改为1小时30分钟
- 是的,这些事情确实会发生,IANA数据库在每个时区区域设置的基础上覆盖它们,这就是为什么我们需要存储给定日期时间的UTC偏移量和相关时区标识符
- 更糟糕的是,当实际使用的日历随着时间的推移而变化时,各地区在不同的时间采用格里高利/ISO日历,因此,在过渡期间,他们不得不跳过几周的时间。
- 一个实际的例子是1918年的苏联:在1918年1月31日之前,俄罗斯和其他国家使用儒略历,儒略历比格里高利历缩短了14天,因此从俄罗斯到欧洲只需要几个小时的火车旅行就可以使当前日期提前两周。当它真正改变时,1月31日是儒略历的最后一天,第二天是公历的2月14日
- 在表记法中,这种转换之前的日期带有旧式(O.S.)或新式(N.S.)日期的说明符
因此,为了正确地表示这些转换之前/之后的日期,我们必须存储:
- 日期时间是格里高利/ISO日历中以UTC为单位的RFC-3339时间戳
- 与特定日期相关的最近的命名时区,例如
Asia/Singapore
:这意味着我们还必须收集一个带有日期的位置,我们希望可以使用该位置来选择其中一个命名时区 - 根据命名时区的特定日期时间的UTC偏移量,例如
+08:00
- 一个可选的其他日历(我称之为日历"投影"),它在所讨论的日期时间内在给定的地区使用,因此可以在两个日历中表示日期,以进一步澄清事情并提供更好的准确性
如上所述,IANA数据库确实为每个时区提供了一个复杂的数据库,以保持UTC偏移量变化和夏令时变化的历史准确时间线。在Java和其他编程语言中,日期时间库使用此数据库在UTC和指定时区的本地时间之间执行转换。
然而,我需要的是一个类似的数据库,它可以用来知道哪个日历在给定的时区或地区使用,这样我就可以提供一个";投影";本地使用的日历。我可以为此编写自己的系统,包含我可以用来提供这些预测的数据,但众所周知,时间非常困难,我确实不想参与日历的历史研究,以制定自己的一套规则。
另一个问题似乎是为给定的一般地理位置找到正确的时区。在战争期间和之后,不同的地理位置易手,成为自己的国家,等等。1917年,俄罗斯的首都是彼得格勒(后来是列宁格勒,后来是圣彼得堡),但在某个时候,这里变成了莫斯科。如果我有一个给定的一般地理区域(例如"基辅"或"乌克兰"),我需要尝试以某种方式将该城市与一个命名的时区联系起来,我该如何做到这一点?我是否在地理上搜索与同一纬度内的任意城市最近的命名时区?
总结:
- 是否存在IANA数据库,该数据库可以跟踪某个地理区域使用不同日历的时间
- 如果我有一个给定城市或国家的地理区域,我如何计算出该使用哪个命名时区
提醒读者有关定义:
- 与UTC的偏移量仅为UTC之前或之后的小时-分-秒数。现代协议通常指正数在UTC之前,负数在UTC之后。但有些协议的作用恰恰相反,所以要小心
- 时区要多得多。时区是特定地区的人民根据其政治家的决定使用的偏移量的过去、现在和未来变化的命名历史
,这样就不必在每次渲染它们时都查阅IANA数据库。
小心:政客改变时区规则。他们这样做的频率令人惊讶,更令人惊讶的是,他们几乎没有预警。这种情况发生在不同的文化和大洲,在那里,许多政客都表现出了玩弄时区规则的嗜好。
我建议不要预先计算UTC的偏移量。我建议用UTC(从UTC偏移0小时-分-秒)存储一个时刻,即时间线上的一个特定点。为了向用户演示,或者在业务逻辑需要的地方,动态地调整到时区中。
如果你不熟悉时区,那么处理时区绝对是疯狂的。
不是真的"疯狂",但是的,非常棘手,违背直觉,容易出错。
我们不能仅仅假设新加坡总是+08:00
不,不能。正如我上面所说,偏移和时区是政治性的时间,由变化无常的政客定义。
夏令时可能会发生,也可能不会发生,不同地区在不同的日历日开始和结束夏令时,某些地区的夏令时偏移量可能超过或少于一小时。
是的,政客们经常改变开始&夏令时(DST)的停止日期。
是的,这些事情绝对会发生
是的,政客们发明了各种各样的调整,有时非常古怪和愚蠢。
最新的时尚正在进入夏令时,而且从未停止,一个永恒的夏令时。因此,太阳再也不会在中午直接落在头顶上了——这与正午的定义背道而驰。
夏令时偏移量从1小时更改为1小时30分钟。
政客们可以在自己的时区内自由更改当前偏移量,任意数量的小时分秒。
地区在不同时间采用格里高利/ISO日历
在谈论日期时间处理时,请避免使用"locale"一词。这个词在本地化工作中有着特殊的含义。许多开发人员错误地认为区域设置和时区是相关的,但事实并非如此。时区与特定政客控制下的法律管辖区相联系;区域设置不是。
不要将格里高利历与ISO 8601日历混为一谈。例如,ISO 8601规定每周从星期一开始。各种公历实现可能使用不同的一周中的某一天。此外,这意味着每个日历系统下的周数不同。
据我所知,不同时区在不同时间采用日历系统并不是什么大问题。这些变化在IANA数据库中得到了解释,也称为tz数据库,以前称为 Olson数据库👉注意:tz数据库通常预计只有在1970年左右才是准确的。即使在最近几十年里,也出现了一些错误和疏漏。 令人惊讶的是,政府官僚机构和学术历史学家忽略了收集时区变化的完整记录。直到最近几十年,才拼凑出一份有组织的记录。 日期时间作为RFC-3339时间戳 我建议您避免RFC 3339。该文档只是ISO 8601标准的一个自我声明的"概要文件"。但是RFC 3339故意破坏了ISO 8601的一些元素。 例如,这些破坏规则之一是允许零的负偏移,除了 遵守ISO 8601。 最接近特定日期的命名时区,例如亚洲/新加坡:这意味着我们还必须收集位置 否,位置不相关。意图和背景是相关的,法律管辖权是相关的。位置不一定表示相关时区。 例如,坐在巴黎( 另一个问题似乎是为给定的一般地理位置找到正确的命名时区 同样,时区是由政治家决定的,而不是由地理决定的。如果当地政客定义了与较大地区/管辖区不同的偏移量,则会创建一个细分时区名称。请参阅维基百科中的tz数据库时区列表(顺便说一句,不一定更新到最新信息)。以美国印第安纳州为例: 是否存在IANA数据库,该数据库跟踪不同日历在一个地理区域使用的时间? 我没有听说过。 如果我有一个给定城市或国家的地理区域,我如何计算出该使用哪个命名时区? 如果有这样的查找,我会感到惊讶。正如我试图解释的那样,时区是管辖区,而不是地理区域。对于空间(地理)中的任何一点,您首先必须确定在您感兴趣的时刻,哪个管辖区拥有控制权。然后你需要将管辖区映射到时区名称,这是我从未见过的映射。 最后,我想知道你的问题对于历史上遥远的时刻是否真的没有意义。在1917年的俄罗斯,你真的关心时区之间的谨慎调整吗?我承认,时区调整在当代可能至关重要,比如我上面提到的确定合同何时签署和生效。但在过去的那些时刻,我无法想象它的实际用处。 正如我所说,自1970年以来,我们才有一个不错的时区历史,即使如此,也几乎没有。+00:00
之外还允许-00:00
。他们的逻辑让我无法理解。根据ISO8601,-00:00
是被禁止的。Europe/Paris
时区)的两名商务人员可能正在签署一份合同,该合同的法律条款在加拿大使用America/Edmonton
时区定义。可能会有两个不同的日期,欧洲的"明天"同时也是美洲的"昨天"。