簡體   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