Federico klez Culloca的回答是正确的,而且有历史意义。
此外,我想指出你正在使用过时的日期时间类,这些类已经被现代的JSR 310中定义的java.time类取代多年了。我们可以使用java.time来查看在其他答案中解释的偏移量变化。
![Table of date-time types in Java, both modern and legacy](https://istack.dev59.com/yciGt.webp)
这是您的代码重写,以避免使用那些过时的类。
首先,确定日期。
int year = 1947;
int month = 2;
int day = 23;
LocalDate localDate = LocalDate.of(year,month,day);
接下来,选择一些时间值。凌晨1点是在凌晨2点跳到凌晨3点之前,而凌晨4点是在跳之后。让我们一起看看。
LocalTime beforeJump = LocalTime.of( 1 , 0 ) ;
LocalTime afterJump = LocalTime.of( 4 , 0 ) ;
将时区定义为 ZoneId
。
ZoneId zoneId = ZoneId.of( "Europe/Prague" ) ;
结合以确定一个时刻,得到一个ZonedDateTime
对象。
ZonedDateTime zdtBeforeJump = ZonedDateTime.of( localDate , beforeJump , z );
ZonedDateTime zdtAfterJump = ZonedDateTime.of( localDate , afterJump , z );
当运行时:
zdtBeforeJump.toString() = 1947-02-23T01:00Z[Europe/Prague]
zdtAfterJump.toString() = 1947-02-23T04:00+01:00[Europe/Prague]
我们可以看到在生成的文本中,偏移量从零小时分钟秒(由
Z
表示为Zulu时间)变为比UTC提前1小时的偏移量。
我们可以通过代码查询偏移量。从
ZoneId
对象中获取区域规则作为
ZoneRules
对象。这提供了该特定地区人民过去、现在和未来使用的偏移量的历史记录。
将我们的时区调整为零偏移量,生成Instant
对象,该对象是ZoneRules#getOffset
所需的。然后询问规则,在该时区的该时刻实际生效的UTC偏移量。我们得到一个ZoneOffset
对象作为结果。
ZoneRules rules = z.getRules();
ZoneOffset offsetBeforeJump = rules.getOffset( zdtBeforeJump.toInstant() );
ZoneOffset offsetAfterJump = rules.getOffset( zdtAfterJump.toInstant() );
运行时。
offsetBeforeJump.toString() = Z
offsetAfterJump.toString() = +01:00
你可以在
IdeOne.com上实时运行查看所有代码。
➥ 与生成的文本相同的结果:跳跃前为零偏移,跳跃后为+01:00。
关于java.time
java.time框架内置于Java 8及更高版本中。这些类取代了麻烦的旧遗留日期时间类,如java.util.Date
, Calendar
, 和 SimpleDateFormat
。
要了解更多信息,请查看Oracle教程。并在Stack Overflow上搜索许多示例和解释。规范是JSR 310。
Joda-Time项目现在处于维护模式,建议迁移到java.time类。
您可以直接使用数据库交换java.time对象。使用符合JDBC 4.2或更高版本的JDBC驱动程序。无需字符串,也不需要java.sql.*
类。Hibernate 5和JPA 2.2支持java.time。
如何获取java.time类?
TimeZone
和Calendar
。这些类设计得很差且过时了。相反,请使用ZonedDateTime
和ZoneId
,或者对于日期,请使用LocalDate
。所有这些都来自于Java时间和日期API(java.time)。 - Ole V.V.Calendar
类设计得很差且过时,而且代码本身也有缺陷。将区域偏移量(字段15)设置为原始偏移量是错误的,可能是你所询问问题的根源。很可能最初的程序员无法正确使用Calendar
,正是因为它的设计如此混乱和繁琐。 - Ole V.V.