简体   繁体   English

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

[英]Java - ZonedDateTime does not correctly convert to Date object?

I have the following Java code:我有以下 Java 代码:

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

The Issue I am having is that convertedDate is not correct in comparison to the zonedDateTime object.我遇到的问题是,与 zonedDateTime 对象相比, convertedDate不正确。

For Example when I have a zonedDateTime object of:例如,当我有一个 zonedDateTime 对象时:

2021-09-16T12:00

with zone:带区域:

Africa/Abidjan

The code above converts this to:上面的代码将其转换为:

Thu Sep 16 13:00:00 BST 2021

What I would be expecting here is我在这里期待的是

 Thu Sep 16 10:00:00 BST 2021

As the Africa/Abidjan timezone is 2 hours ahead of BST.由于Africa/Abidjan时区比英国夏令时早 2 小时。

How can I solve this?我该如何解决这个问题?

java.time时间

The java.util Date-Time API and their formatting API, SimpleDateFormat are outdated and error-prone. java.util Date-Time API 及其格式化 API SimpleDateFormat已过时且容易出错。 It is recommended to stop using them completely and switch to the modern Date-Time API * .建议完全停止使用它们并切换到现代 Date-Time API *

Solution using java.time , the modern 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);
    }
}

Output:输出:

2021-09-16T12:00Z[Africa/Abidjan]
2021-09-16T13:00+01:00[Europe/London]

ONLINE DEMO在线演示

  • The Z in the output is the timezone designator for zero-timezone offset.输出中的Z是零时区偏移的时区指示符 It stands for Zulu and specifies the Etc/UTC timezone (which has the timezone offset of +00:00 hours).它代表祖鲁语并指定Etc/UTC时区(时区偏移为+00:00小时)。

  • From the output, it is clear that 2021-09-16T12:00Z[Africa/Abidjan] is equal to 2021-09-16T13:00+01:00[Europe/London].从输出中可以清楚地看出 2021-09-16T12:00Z[Africa/Abidjan] 等于 2021-09-16T13:00+01:00[Europe/London]。

Learn more about the modern Date-Time API from Trail: Date Time .Trail: Date Time 中了解有关现代日期时间 API 的更多信息。


* For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project . * 出于任何原因,如果您必须坚持使用 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

Answer by Avinash is correct. Avinash 的回答是正确的。 Here are a few more thoughts.这里还有一些想法。

Time zone names时区名称

BST is not a real time zone name . BST不是真正的时区名称 Perhaps you meant Europe/London .也许你的意思是Europe/London And that is not GMT/UTC.不是GMT/UTC。 The London time zone can vary in its offset, because of Daylight Saving Time (DST) and perhaps other reasons.由于夏令时 (DST)和其他原因,伦敦时区的偏移量可能会有所不同。

UTC世界标准时间

Let's look at your moment in each of the three different time zones.让我们来看看您在三个不同时区中的每一个时刻。

First we parse your input as a LocalDateTime , lacking the context of a time zone or offset-from-UTC.首先,我们将您的输入解析为LocalDateTime ,缺少时区或UTC 偏移量的上下文。 Then we assign a time zone for Abidjan as the context to produce a ZonedDateTime object.然后我们为阿比让分配一个时区作为上下文来生成一个ZonedDateTime对象。 We adjust to another time zone, resulting in a second ZonedDateTime that represents the same moment, the same point on the timeline, but a different wall-clock time.我们调整到另一个时区,导致第二个ZonedDateTime代表同一时刻,时间线上的同一点,但不同的挂钟时间。 Lastly, we extract a Instant to effectively adjust into UTC.最后,我们提取一个Instant来有效地调整为 UTC。 A Instant represents a moment in UTC, always in 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.

See this code run live at IdeOne.com .查看此代码在 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

The Z at the end means an offset of zero hours-minutes-seconds, pronounced “Zulu”.末尾的Z表示零时分秒的偏移量,发音为“Zulu”。 So we can zee that noon on that September day in Côte d'Ivoire is the same as in UTC, having an offset of zero.所以我们可以看到,科特迪瓦 9 月那一天的中午与 UTC 相同,偏移为零。 In contrast, the +01:00 tells us that London time is an hour ahead.相比之下,+01 +01:00告诉我们伦敦时间提前了一个小时。 So the clock reads 1 PM ( 13:00 ) rather than noon.所以时钟显示的是下午 1 点( 13:00 )而不是中午。

Fetch the offset获取偏移量

You can determine the offset in effect at a particular moment via the ZoneRules class.您可以通过ZoneRules类确定特定时刻有效的偏移量。 The offset info is represented by the ZoneOffset class.偏移量信息由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() ;

Or condense that to:或者将其浓缩为:

ZoneId
.of( "Africa/Abidjan" )
.getRules()
.getOffset( LocalDateTime.parse( "2021-09-16T12:00" ) )
.getTotalSeconds()

When run we see again that Côte d'Ivoire is using an offset of zero at that date-time.运行时,我们再次看到科特迪瓦在该日期时间使用零偏移量。

rules: ZoneRules[currentStandardOffset=Z]
offset: Z
offsetInSeconds: 0

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

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

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