【问题标题】:How to manually set the Daylight Saving (DST) shift date in Java如何在 Java 中手动设置夏令时 (DST) 班次日期
【发布时间】:2019-03-07 22:03:05
【问题描述】:

我国将夏令时班次日期从“10 月 21 日”更改为“11 月 4 日”,我们需要在后端应用此设置。

适当的解决方案是更新操作系统配置,但我们有这样做的限制(遗留依赖项)。我们正在寻找解决方法。

是否可以使用代码并以编程方式更改 DST 班次日期?

GregorianCalendar gc = new GregorianCalendar();
gc.setTimeInMillis(0);
gc.set(2018, Calendar.OCTOBER, 21, 0, 0, 0);
gc.setTimeZone(TimeZone.getTimeZone("Brazil/East"));
XMLGregorianCalendar xml = DatatypeFactory.newInstance().newXMLGregorianCalendar(gc);
System.out.println("XML Date: " + xml.toString());

输出必须是-03:00:

XML Date: 2018-10-21T01:00:00.000-02:00

【问题讨论】:

  • 如果一切都失败了,您可以为此编写自己的逻辑。
  • “操作系统配置”是指服务器或 JRE 的时区数据(tzdata:oracle.com/technetwork/java/javase/tzdata-versions-138805.html
  • @everton 我想我对 Java 会从操作系统获取 DST 转换日期的理解不正确?
  • @BonanzaOne 是的,这是不正确的......控制它的是 tzdata,您需要随时更新新的变化,正如 BasilBourque 的回答所完美展示的那样

标签: java dst


【解决方案1】:

操作系统无关

您的操作系统配置无关紧要。默认情况下,大多数 Java 实现会在启动时从主机操作系统中获取其初始默认时区。但是时区的定义存储在 Java 实现中。

Java 时区更新程序

因此,您需要在 Java 实现中更新时区定义。大多数实现使用tz database,也称为tzdata

对于 Oracle 品牌的 Java 实施,Oracle 提供了Timezone Updater Tool。该着陆页的截止日期为 2018-08,因此您的时区更改可能已包含在内。但我建议您更仔细地调查以验证。

对于其他实现,请咨询供应商。他们可能已经提供了 JVM 的更新版本以包含新的 tzdata。或者他们也提供了一个更新工具。或者您可以手动替换 tzdata 文件。

避免使用代码破坏区域

我强烈建议您避免尝试自己在代码中对偏移量进行人为调整。 你可能会弄错。日期时间工作非常棘手和混乱。

但如果你坚持,首先要避免可怕的旧日期时间类,例如GregorianCalendar & Calendar & Date。这些在几年前被 JSR 310 取代。如果您必须与尚未更新到 java.time 的旧代码进行互操作,请在现代类中完成您的工作,然后最后通过添加到旧课程。

使用现代的 java.time 类,具体来说:

  • Instant(暂时以 UTC 为准)
  • OffsetDateTime(暂时与 UTC 的偏移量为小时-分钟-秒,但没有时区)
  • ZonedDateTime(特定时区的片刻)

您可以使用这些类在 Stack Overflow 上搜索许多现有示例和说明。你应该关注OffsetDateTimeZoneOffset(而不是ZoneId)和Instant,因为如果你知道你的tzdata文件已经过时,你必须避免ZonedDateTime

同一时刻,不同的挂钟时间

OffsetDateTime::withOffsetSameInstant​

OffsetDateTime odt = OffsetDateTime.parse( "2018-10-21T01:00:00.000-02:00" ) ;
ZoneOffset offset = ZoneOffset.ofHours( -3 ) ;
OffsetDateTime odt2 = odt.withOffsetSameInstant​( offset ) ;  // Same moment, same point on the timeline, different wall-clock time.

odt.toString(): 2018-10-21T01:00-02:00

odt2.toString(): 2018-10-21T00:00-03:00

在该示例中,odtodt2 都表示同一时刻,时间轴上的同一点。如果您提取Instant(UTC 值),您的结果将是同一时刻。只是他们的挂钟时间不同。

Instant instant1 = odt.toInstant() ;  // Adjust to UTC.
Instant instant2 = odt2.toInstant() ;
boolean sameMoment = instant1.equals( instant2 ) ; 

instant1.toString(): 2018-10-21T03:00:00Z

instant2.toString(): 2018-10-21T03:00:00Z

sameMoment = true

末尾的 Z 表示 UTC,与 UTC 的偏移量为零,+00:00Z 发音为“祖鲁语”。由ISO 8601 标准定义。

不同的时刻,相同的挂钟时间

OffsetDateTime::withOffsetSameLocal​

相比之下,您可能想要强制使用时间,从而代表一个不同的时刻。为此,请使用withOffsetSameLocal 方法。请注意,您正在改变数据的含义,您正在移动到时间轴上的另一个点。

OffsetDateTime differentMomentButSameTimeOfDay = odt. withOffsetSameLocal( offset ) ;

differentMomentButSameTimeOfDay.toString(): 2018-10-21T01:00-03:00

提取瞬间,看看我们有不同的瞬间。

Instant differentInstant = differentMomentButSameTimeOfDay.toInstant() ;

不同的Instant.toString(): 2018-10-21T04:00:00Z

请注意上面看到的 4 AM UTC 与 3 AM UTC。这里的这一时刻发生在上述时刻之后的一个小时。时间线上的两个不同点。

在您完全理解时间轴上的点的概念之前不要尝试这项工作,并且点之间的变化与调整偏移完全不同。在做实际工作之前广泛练习。三心二意的猜测会让你陷入痛苦和头痛的世界。

而且,正如我上面所建议的,您最好花时间安装更新的 tzdata 文件,而不是破解这些偏移量。

实时代码

查看以上所有代码run live at IdeOne.com

到处更新tzdata

为了获得最佳效果,您应该在所有这些不同的地方更新 tzdata(或等效的):

  • 您的操作系统
  • 您的 JVM
  • 您的数据库引擎,例如Postgres
  • 任何捆绑了自己的时区信息的库(例如:Joda-Time

关于java.time

java.time 框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧 legacy 日期时间类,例如 java.util.DateCalendarSimpleDateFormat

要了解更多信息,请参阅Oracle Tutorial。并在 Stack Overflow 上搜索许多示例和解释。规格为JSR 310

Joda-Time 项目现在位于maintenance mode,建议迁移到java.time 类。

您可以直接与您的数据库交换 java.time 对象。使用符合JDBC 4.2 或更高版本的JDBC driver。不需要字符串,不需要java.sql.* 类。 Hibernate 5 & JPA 2.2 支持 java.time

从哪里获取 java.time 类?

ThreeTen-Extra 项目通过附加类扩展了 java.time。该项目是未来可能添加到 java.time 的试验场。您可以在这里找到一些有用的类,例如IntervalYearWeekYearQuartermore

【讨论】:

  • 罗勒这是一个很好的答案。不幸的是,我们正在使用 Java 6 运行非常陈旧的遗留代码,我会尽我所能在您的帮助下解决这个问题。
  • @BonanzaOne 重读我的答案,其中包含 Java 6 和 ThreeTen-Backport 的项目符号。
  • 只是一次我希望看到问题得到回答,而不是建议把所有东西都扔掉重新开始。
猜你喜欢
  • 2019-04-09
  • 2018-03-14
  • 2019-02-27
  • 2010-11-06
  • 2012-12-21
  • 1970-01-01
  • 2019-12-30
  • 2012-06-01
  • 2016-03-22
相关资源
最近更新 更多