[英]Java - ZonedDateTime does not correctly convert to Date object?
我有以下 Java 代码:
Date convertedDate = Date.from(zonedDateTime.toInstant());
我遇到的问题是,与 zonedDateTime 对象相比, convertedDate
不正确。
例如,当我有一个 zonedDateTime 对象时:
2021-09-16T12:00
带区域:
Africa/Abidjan
上面的代码将其转换为:
Thu Sep 16 13:00:00 BST 2021
我在这里期待的是
Thu Sep 16 10:00:00 BST 2021
由于Africa/Abidjan
时区比英国夏令时早 2 小时。
我该如何解决这个问题?
java.util
Date-Time API 及其格式化 API SimpleDateFormat
已过时且容易出错。 建议完全停止使用它们并切换到现代 Date-Time API * 。
使用现代日期时间 API java.time
解决方案:
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
public class Main {
public static void main(String[] args) {
// The given ZonedDateTime
ZonedDateTime zdtAbidjan = ZonedDateTime.of(
LocalDateTime.of(LocalDate.of(2021, 9, 16),
LocalTime.of(12, 0)),
ZoneId.of("Africa/Abidjan")
);
System.out.println(zdtAbidjan);
ZonedDateTime zdtLondon = zdtAbidjan.withZoneSameInstant(ZoneId.of("Europe/London"));
System.out.println(zdtLondon);
}
}
输出:
2021-09-16T12:00Z[Africa/Abidjan]
2021-09-16T13:00+01:00[Europe/London]
输出中的Z
是零时区偏移的时区指示符。 它代表祖鲁语并指定Etc/UTC
时区(时区偏移为+00:00
小时)。
从输出中可以清楚地看出 2021-09-16T12:00Z[Africa/Abidjan] 等于 2021-09-16T13:00+01:00[Europe/London]。
从Trail: Date Time 中了解有关现代日期时间 API 的更多信息。
* 出于任何原因,如果您必须坚持使用 Java 6 或 Java 7,您可以使用ThreeTen-Backport,它将大部分java.time功能向后移植到 Java 6 和 7。如果您正在为 Android 项目和您的 Android API 工作级别仍然不符合 Java-8,请检查 通过 desugaring和How to use ThreeTenABP in Android Project 可用的 Java 8+ APIs 。
Avinash 的回答是正确的。 这里还有一些想法。
BST
不是真正的时区名称。 也许你的意思是Europe/London
。 这不是GMT/UTC。 由于夏令时 (DST)和其他原因,伦敦时区的偏移量可能会有所不同。
让我们来看看您在三个不同时区中的每一个时刻。
首先,我们将您的输入解析为LocalDateTime
,缺少时区或UTC 偏移量的上下文。 然后我们为阿比让分配一个时区作为上下文来生成一个ZonedDateTime
对象。 我们调整到另一个时区,导致第二个ZonedDateTime
代表同一时刻,时间线上的同一点,但不同的挂钟时间。 最后,我们提取一个Instant
来有效地调整为 UTC。 Instant
表示 UTC 中的一个时刻,始终为 UTC。
LocalDateTime ldt = LocalDateTime.parse( "2021-09-16T12:00" ) ;
ZonedDateTime zdtAbidjan = ldt.atZone( ZoneId.of( "Africa/Abidjan" ) ) ;
ZonedDateTime zdtLondon = zdtAbidjan.withZoneSameInstant( ZoneId.of( "Europe/London" ) ) ;
Instant instant = zdtAbidjan.toInstant() ; // Adjust to UTC by extracting an `Instant` object.
ldt: 2021-09-16T12:00
zdtAbidjan: 2021-09-16T12:00Z[Africa/Abidjan]
zdtLondon: 2021-09-16T13:00+01:00[Europe/London]
instant: 2021-09-16T12:00:00Z
末尾的Z
表示零时分秒的偏移量,发音为“Zulu”。 所以我们可以看到,科特迪瓦 9 月那一天的中午与 UTC 相同,偏移为零。 相比之下,+01 +01:00
告诉我们伦敦时间提前了一个小时。 所以时钟显示的是下午 1 点( 13:00
)而不是中午。
您可以通过ZoneRules
类确定特定时刻有效的偏移量。 偏移量信息由ZoneOffset
类表示。
ZoneId z = ZoneId.of( "Africa/Abidjan" ) ;
ZoneRules rules = z.getRules() ;
ZoneOffset offset = rules.getOffset( LocalDateTime.parse( "2021-09-16T12:00" ) ) ;
int offsetInSeconds = offset.getTotalSeconds() ;
或者将其浓缩为:
ZoneId
.of( "Africa/Abidjan" )
.getRules()
.getOffset( LocalDateTime.parse( "2021-09-16T12:00" ) )
.getTotalSeconds()
运行时,我们再次看到科特迪瓦在该日期时间使用零偏移量。
rules: ZoneRules[currentStandardOffset=Z]
offset: Z
offsetInSeconds: 0
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.