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 年 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"));
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) | 明確 ZoneId | IANA 時區資料庫,歷史夏令時準確 | 不可變,安全 |
TimeZone.getDefault() 確認 JVM 時區。c.getTimeZone() 確認 Calendar 使用時區。