[英]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,請檢查 通過 desugaring和How 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.
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
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.