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

问题描述

我有以下 Java 代码

Date convertedDate = Date.from(zoneddatetime.toInstant());

我遇到的问题是 convertedDatezoneddatetime 对象相比不正确。

例如,当我有一个 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.time

java.util 日期时间 API 及其格式化 API SimpleDateFormat 已过时且容易出错。建议完全停止使用它们并切换到 modern Date-Time API*

使用 java.time(现代日期时间 API)的解决方案:

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]

ONLINE DEMO

  • 输出中的 Z 是零时区偏移的 timezone designator。它代表祖鲁语并指定 Etc/UTC 时区(时区偏移为 +00:00 小时)。

  • 从输出中可以明显看出,2021-09-16T12:00Z[Africa/Abidjan] 等于 2021-09-16T13:00+01:00[Europe/London]。

Trail: Date Time 了解有关现代 Date-Time API 的更多信息。


* 出于任何原因,如果您必须坚持使用 Java 6 或 Java 7,您可以使用 ThreeTen-Backport,它将大部分 java.time 功能向后移植到 Java 6 & 7. 如果您正在为 Android 项目工作并且您的 Android API 级别仍然不符合 Java-8,请检查 Java 8+ APIs available through desugaringHow to use ThreeTenABP in Android Project

,

Answer by Avinash 是正确的。这里还有一些想法。

时区名称

BST 不是 real time zone name。也许你的意思是Europe/London。那是不是 GMT/UTC。由于 Daylight Saving Time (DST) 和其他原因,伦敦时区的偏移量可能会有所不同。

UTC

让我们看看您在三个不同时区中的每一个时刻。

首先,我们将您的输入解析为 LocalDateTime,缺少时区上下文或 UTC 偏移量。然后我们为 Abidjan 分配一个时区作为上下文来生成一个 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.

看到这个code run live at 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: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

Table of date-time types in Java,both modern and legacy

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...