首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

Java 日期時間加 1 小時異常:夏令時切換導致時間重複

     編輯:程式設計綜合問答

現象

Date d = format.parse("1986-09-13 21:00:00");
for (int i=0; i<5; i++) {
    c.setTime(d);
    c.add(Calendar.HOUR_OF_DAY, 1);
    d = c.getTime();
    System.out.println(d);
}
// 輸出:
// 1986-09-13 22:00:00
// 1986-09-13 23:00:00
// 1986-09-13 23:00:00  <-- 重複!
// 1986-09-14 00:00:00
// 1986-09-14 01:00:00

原因:1986 年中國夏令時結束

1986 年 9 月 14 日 00:00 中國結束夏令時,時鐘撥回 1 小時。Calendar.add(HOUR_OF_DAY, 1) 在夏令時結束點前後各加 1 小時,導致 23:00 出現兩次。

解決方案:明確設定時區

SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
format.setTimeZone(TimeZone.getTimeZone("GMT+8")); // 關鍵:固定東八區,忽略夏令時
// 或使用 "Asia/Shanghai" (ICU 時區資料庫含歷史夏令時規則)
format.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));

最佳實務:改用 java.time (Java 8+)

import java.time.*;
import java.time.format.DateTimeFormatter;

DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
ZoneId zone = ZoneId.of("Asia/Shanghai");
LocalDateTime ldt = LocalDateTime.parse("1986-09-13 21:00:00", fmt);
ZonedDateTime zdt = ldt.atZone(zone);

for (int i=0; i<5; i++) {
    zdt = zdt.plusHours(1);
    System.out.println(zdt.format(fmt)); // 正確處理夏令時轉換
}

關鍵差異

API時區處理夏令時執行緒安全
SimpleDateFormat + Calendar預設 JVM 時區,易受環境影響依賴 JDK 時區資料,歷史規則可能不準非安全
java.time (ZonedDateTime)明確 ZoneIdIANA 時區資料庫,歷史夏令時準確不可變,安全

排查技巧

  • 輸出 TimeZone.getDefault() 確認 JVM 時區。
  • 列印 c.getTimeZone() 確認 Calendar 使用時區。
  • 測試已知夏令時切換點 (如 1986/1987/1988 年中國、現行美歐規則)。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved