繁体   English   中英

Java - ZonedDateTime 没有正确转换为 Date 对象?

[英]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,请检查 通过 desugaringHow 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.

查看此代码在 IdeOne.com 上实时运行

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

Java 中的日期时间类型表,现代和传统

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM