【问题标题】:Retrieve historical local datetime from UTC datetime after DST rules have changed在 DST 规则更改后从 UTC 日期时间检索历史本地日期时间
【发布时间】:2018-10-16 06:47:37
【问题描述】:

假设我正在使用 Oracle SGBD (RDBMS) 和 Java 8。

我的历史日期时间存储在 UTC 时区,但我的应用程序仅显示本地日期时间,而且我的统计计算也仅适用于本地日期时间。

现在,假设欧洲的 DST 规则发生了变化,as is planned

让我的应用和统计信息保持正常运行的最简单方法是什么?

到目前为止,我所读到的是 OracleJava 中都有与 DST 规则相关的时区,但它们不会自动更新。此外,我想做的是在更改之前和之后保留规则,而不仅仅是更新规则,因为我需要历史统计数据,所以我需要“更改之前的欧洲/巴黎”时区和“之后的欧洲/巴黎”更改”时区,或者更好的时区与根据需要应用自身的规则历史相关联。

即使在 Java 中有一些方便的方法可以做到这一点,它仍然应该在 Oracle 中修复以涵盖所有用例。

这是芝加哥相关的历史性规则变化之一。 DST 结束于 9 月的最后一个星期日到 1954 年,然后是 1955 年的 10 月的最后一个星期日(直到下一次规则更改):

DST 开始(时钟向前)-> DST 结束(时钟向后)
1953 年 dimanche 26 月 26 日,02 时 00 -> dimanche 9 月 27 日,02 时 00
1954 年 25 月 25 日,02 时 00 -> 迪曼奇 9 月 26 日,02 时 00
1955 年 24 月 24 日,02 时 00 -> 迪曼奇 10 月 30 日,02 时 00
1956 年 dimanche 4 月 29 日,02 时 00 -> dimanche 10 月 28 日,02 时 00

附: : 我知道IANA historical timezone database,但是如果您已经这样做了,请展示如何将它实际用于 Oracle SGBD 和 Java。

附言: 也欢迎任何关于在未来数据库中比“UTC”更好地处理这个问题的建议。

【问题讨论】:

  • 感谢一位欧盟公民的好消息!
  • 好吧,我还不确定“好”消息是什么...... :)
  • 我只知道 Java。新规则正式生效后,Olson/IANA 数据库将更新。之后,新的 Java 版本将具有新规则,但仍将包含历史更改。这对你来说还不够吗?如果您当时不想升级您的 Java,我预计将发布一个新版本的 Java Timezone Updater Tool,以便您可以更新现有的 Java 安装并获得相同的版本。
  • 你将如何参考最新或旧时区?我只知道我所在时区的“欧洲/巴黎”。你应该为 java 做一个答案,并创建一个芝加哥的例子,他已经改变了多个规则。
  • 与俄罗斯或智利的突然变化相比,至少有更长的准备时间以防发生变化

标签: java oracle datetime


【解决方案1】:

Java 或 Oracle 将自动为任何 UTC 日期应用正确的规则 - 当然,只要您拥有最新的时区数据文件。

由于您询问了 Oracle (SGBD/RDBMS) 方法并提到了芝加哥,因此生成时钟在不同规则下发生变化的示例日期相当简单,并查看更改应用于正确的日期(与示例相比)规则更改添加到问题中,https://www.timeanddate.com/time/zone/usa/chicago)。

alter session set nls_timestamp_tz_format = 'YYYY-MM-DD HH24:MI:SS TZH:TZM';

with t (utc) as (
            select timestamp '1954-04-25 07:59:59 UTC' from dual
  union all select timestamp '1954-04-25 08:00:00 UTC' from dual
  union all select timestamp '1954-09-26 06:59:59 UTC' from dual
  union all select timestamp '1954-09-27 07:00:00 UTC' from dual
  --
  union all select timestamp '1955-04-24 07:59:59 UTC' from dual
  union all select timestamp '1955-04-24 08:00:00 UTC' from dual
  union all select timestamp '1955-10-30 06:59:59 UTC' from dual
  union all select timestamp '1955-10-30 07:00:00 UTC' from dual
  --
  union all select timestamp '1974-01-06 07:59:59 UTC' from dual
  union all select timestamp '1974-01-06 08:00:00 UTC' from dual
  union all select timestamp '1974-10-27 06:59:59 UTC' from dual
  union all select timestamp '1974-10-27 07:00:00 UTC' from dual
  --
  union all select timestamp '1975-02-23 07:59:59 UTC' from dual
  union all select timestamp '1975-02-23 08:00:00 UTC' from dual
  union all select timestamp '1975-10-26 06:59:59 UTC' from dual
  union all select timestamp '1975-10-26 07:00:00 UTC' from dual
  --
  union all select timestamp '1987-04-05 07:59:59 UTC' from dual
  union all select timestamp '1987-04-05 08:00:00 UTC' from dual
  union all select timestamp '1987-10-25 06:59:59 UTC' from dual
  union all select timestamp '1987-10-25 07:00:00 UTC' from dual
  --
  union all select timestamp '2007-03-11 07:59:59 UTC' from dual
  union all select timestamp '2007-03-11 08:00:00 UTC' from dual
  union all select timestamp '2007-11-04 06:59:59 UTC' from dual
  union all select timestamp '2007-11-04 07:00:00 UTC' from dual
)
select utc,
  utc at time zone 'America/Chicago' as chicago
from t;

给你:

UTC                        CHICAGO                   
-------------------------- --------------------------
1954-04-25 07:59:59 +00:00 1954-04-25 01:59:59 -06:00
1954-04-25 08:00:00 +00:00 1954-04-25 03:00:00 -05:00
1954-09-26 06:59:59 +00:00 1954-09-26 01:59:59 -05:00
1954-09-27 07:00:00 +00:00 1954-09-27 01:00:00 -06:00
1955-04-24 07:59:59 +00:00 1955-04-24 01:59:59 -06:00
1955-04-24 08:00:00 +00:00 1955-04-24 03:00:00 -05:00
1955-10-30 06:59:59 +00:00 1955-10-30 01:59:59 -05:00
1955-10-30 07:00:00 +00:00 1955-10-30 01:00:00 -06:00
1974-01-06 07:59:59 +00:00 1974-01-06 01:59:59 -06:00
1974-01-06 08:00:00 +00:00 1974-01-06 03:00:00 -05:00
1974-10-27 06:59:59 +00:00 1974-10-27 01:59:59 -05:00
1974-10-27 07:00:00 +00:00 1974-10-27 01:00:00 -06:00
1975-02-23 07:59:59 +00:00 1975-02-23 01:59:59 -06:00
1975-02-23 08:00:00 +00:00 1975-02-23 03:00:00 -05:00
1975-10-26 06:59:59 +00:00 1975-10-26 01:59:59 -05:00
1975-10-26 07:00:00 +00:00 1975-10-26 01:00:00 -06:00
1987-04-05 07:59:59 +00:00 1987-04-05 01:59:59 -06:00
1987-04-05 08:00:00 +00:00 1987-04-05 03:00:00 -05:00
1987-10-25 06:59:59 +00:00 1987-10-25 01:59:59 -05:00
1987-10-25 07:00:00 +00:00 1987-10-25 01:00:00 -06:00
2007-03-11 07:59:59 +00:00 2007-03-11 01:59:59 -06:00
2007-03-11 08:00:00 +00:00 2007-03-11 03:00:00 -05:00
2007-11-04 06:59:59 +00:00 2007-11-04 01:59:59 -05:00
2007-11-04 07:00:00 +00:00 2007-11-04 01:00:00 -06:00

您可以通过查询v$timezone_file 视图或最新版本的database_properties 视图来查看您正在使用哪个版本的时区数据文件。

您可以在Oracle Support Document 412160.1 (Updated DST Transitions and New Time Zones in Oracle RDBMS and OJVM Time Zone File Patches) 中阅读有关 Oracle 时区文件版本和补丁的更多信息。

特别是,请查看第 J 部分,“RDBMS DST 更新中的更新时区列表”,其中说:

所有时区文件更新都是累积的,这意味着较新的 ​​RDBMS DST 补丁具有先前更新的所有更改。
...
在下面的列表中,列出了在时区文件版本中更新的时区。还列出了该时区的时区规则更改的第一年,以及最后一年(如果适用)。

所以它也显示了历史日期。

【讨论】:

  • 好的,谢谢您的详细解答。 AnatolijsGorbunovs 对此没有说什么,我将您的评论复制到他的回答中:)
  • Alex,你能解释一下你的示例日期的选择吗?为什么 IANA 文件未提及 1956 年(夏令时结束于 11 月而不是 10 月)之后的规则变化? ftp.iana.org/tz/tz-how-to.html
  • @Tristan - 我最初只是从我链接到的网站的每一页日期中选择第一年,那里的规则似乎已经改变。我已经更新为更明确地显示 1954/1955,并在今年显示。中间更有趣。在那个网站上,将 1974 年和 1975 年视为怪事;然后从 1987 年和 2007 年开始进一步的规则变化。你刚刚链接到的页面确实显示了这些,在“更有趣的“美国”规则下。
  • 我的模糊理解,对于非美国公民来说并不明显的是,“美国/芝加哥”与各种规则相关联,其中一些特定于芝加哥,一些更全球化到美国,以及当芝加哥​​恢复“标准”时,将适用美国规则。我想我们只能希望所有这些对每个版本的 Oracle 和每个版本的 java 都一样。
  • 这与 Oracle 或 Java 无关,这就是 TZ 数据库的设置方式。在查看区域记录时,您提供的链接中已经涵盖了这一点 - 特别是关于区域和规则之间差异的部分。
【解决方案2】:

来自https://www.oracle.com/technetwork/java/javase/tzdata-versions-138805.html

此表显示了哪个版本的时区数据包含在 不同版本的 Java 开发工具包 (JDK) 软件和 TZUpdater 工具。有关时区内容的更多信息 数据发布包含在相关的增强请求中 (RFE) 用于该版本。发生重大时区变化的地方 包含在时区数据发布中,这在最后 列。

最新的 TZdata 版本可以从IANA TZdata page找到。

自 TZUpdater v2.0 发布以来,用户现在可以更新 tzdata JDK/JRE 中的版本,使用直接从 IANA 获得的数据 tzdata 发布。有关详细信息,请参阅 TZUpdater 自述文件。

如果您想了解 Java SE 中的时区数据更新 平台和 TZUpdater 工具一旦发生,订阅 时区数据版本 RSS 提要。

所以基本上如果您一直需要最新的时区数据,请使用 TZUpdater tool 升级 Java 时区信息。

Alex Poole 在评论中更新

Oracle/Java 将应用在 UTC 日期生效的适当规则 您正在尝试转换为特定时区。你不需要 明确地做任何事情 - 你只需要最新版本的 当前+历史规则

【讨论】:

  • 是的,但我不需要“一直都是最新的时区数据”,我还需要旧的时区规则。
  • 据我所知,tzdata 存储未来和历史时区信息。但是您可以用 Java 编写一个测试程序,如果您需要 100% 确定,请检查它。 “最新数据”是指时区更改的所有历史记录,包括最新的。
  • 是的,我知道 tzdata 存储什么,因为我在我的问题中引用了它们,以及您的 tzdata-versions 链接。问题是:如何使用这些历史数据?您如何参考历史时区/规则集?
  • @Tristan - “如何使用”是什么意思? Oracle/Java 将在您尝试转换为特定时区的 UTC 日期应用适当的有效规则。你不需要明确地做任何事情——你只需要当前+历史规则的最新版本。根据您的问题,“与根据需要应用自己的规则历史相关联的时区”是您自动获得的。
  • 好的,很好,这就是我正在寻找的关于 java 的信息!如果您有关于纯 Oracle SGBD 方法的答案,那将非常有用。
猜你喜欢
  • 2011-02-21
  • 2012-10-29
  • 1970-01-01
  • 2012-02-18
  • 2022-10-04
  • 2012-10-07
  • 1970-01-01
  • 2016-12-18
  • 2021-06-29
相关资源
最近更新 更多