Java - ZonedDateTime不能正确转换为Date对象?

6

我有以下Java代码:

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

我遇到的问题是convertedDate与zonedDateTime对象相比不正确。
例如,当我有一个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 时区比 BST 提前 2 小时,该如何解决?

6
“由于非洲/阿比让时区比英国夏令时提前2小时。” <- 您确定吗?科特迪瓦的时区是UTC + 0,而英国夏令时是UTC +1。因此,非洲/阿比让时区应该比英国夏令时晚1小时,这就是在显示英国夏令时时间时为什么会增加1小时的原因。 - user6073886
那么在这种情况下,我的代码是正确的吗? - java12399900
1
在我看来是正确的。2021年9月16日12:00在Africa/Abidjan时区将是2021年9月16日13:00:00 BST。 - user6073886
2个回答

5

java.time

java.util日期时间API及其格式化API SimpleDateFormat已过时且容易出错。建议完全停止使用它们并切换到现代日期时间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是表示零时区偏移的时区指示器。它代表Zulu并指定了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,请查看通过解糖使用Java 8+ API如何在Android项目中使用ThreeTenABP


3

Avinash的回答是正确的。以下是一些额外的想法。

时区名称

BST不是一个真正的时区名。也许你指的是Europe/London。而那并不是GMT/UTC。伦敦时区的偏移量可能会因为夏令时(DST)和其他原因而有所变化。

UTC

让我们分别查看你在三个不同时区的时间。

首先,我们将你的输入解析为一个缺少时区或从UTC偏移量的上下文的LocalDateTime对象。然后,我们为阿比让分配一个时区作为上下文以生成一个ZonedDateTime对象。我们进行调整以适应另一个时区,得到第二个ZonedDateTime对象,它代表了相同的瞬间、时间线上的同一点,但是在不同的挂钟时间上。最后,我们提取一个Instant对象,以实际调整为UTC。一个Instant始终表示UTC中的一个瞬间。保留HTML标记。

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”。因此,我们可以看到科特迪瓦的那个九月日子中午的时间与UTC相同,具有零偏移量。相比之下, +01:00 告诉我们伦敦时间比UTC快一小时。所以时钟显示的是下午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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接