首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 日期時間加減運算:Calendar 實戰與現代 java.time 替代

     編輯:Java 相關知識

業務場景

問卷發布後 30 天自動失效,需計算結束時間。

舊 API 實現 (Calendar)

import java.util.Calendar;
import java.util.Date;

public class DateCalcWithCalendar {
    public static void main(String[] args) {
        Calendar cal = Calendar.getInstance(); // 當前時間
        Date start = cal.getTime();            // 發布時間
        System.out.println("開始: " + start);

        // 核心:直接操作 DAY_OF_YEAR 自動跨月跨年
        int dayOfYear = cal.get(Calendar.DAY_OF_YEAR);
        cal.set(Calendar.DAY_OF_YEAR, dayOfYear + 30);
        Date end = cal.getTime();              // 30 天后
        System.out.println("結束: " + end);

        // 其他常用操作
        cal.add(Calendar.MONTH, 3);   // 加 3 月
        cal.add(Calendar.YEAR, -1);   // 減 1 年
        cal.add(Calendar.HOUR, 12);   // 加 12 小時
    }
}

Calendar 關鍵字段常量

常量含義
ERA紀元 (BC/AD)
YEAR年
MONTH月 (0=1月, 11=12月)
WEEK_OF_YEAR年中第幾週
DAY_OF_MONTH / DATE月內第幾天
DAY_OF_YEAR年內第幾天
DAY_OF_WEEK週幾 (1=星期日)
HOUR / HOUR_OF_DAY12/24 小時制
MINUTE / SECOND / MILLISECOND分/秒/毫秒

⚠️ Calendar 易踩坑點

  • MONTH 從 0 開始:cal.set(Calendar.MONTH, 11) 才是 12 月。
  • 可變性:cal.add() 修改原對象,非線程安全。
  • 時區依賴:getInstance() 使用默認時區,跨時區部署易出錯。
  • 效能:較重,高併發建議用 ThreadLocal 復用或遷移新 API。

現代最佳實踐:java.time (Java 8+)

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

public class DateCalcWithJavaTime {
    public static void main(String[] args) {
        // 不可變、線程安全、清晰語義
        LocalDateTime now = LocalDateTime.now();           // 當前日期時間
        LocalDateTime start = now;                         // 發布時間
        LocalDateTime end = start.plusDays(30);            // +30 天
        System.out.println("開始: " + start.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
        System.out.println("結束: " + end.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));

        // 豐富運算
        end = start.plusMonths(3).minusYears(1).plusHours(12);
        // 精確到納秒、支援時區
        ZonedDateTime zdt = ZonedDateTime.now(ZoneId.of("Asia/Shanghai"));
        // 期間計算
        Period p = Period.between(start.toLocalDate(), end.toLocalDate());
        Duration d = Duration.between(start, end);
    }
}

新舊 API 對比

維度Calendarjava.time (LocalDateTime 等)
線程安全否 (可變)是 (不可變)
API 設計get/set/add 混雜plus/minus/with 流暢
時區處理隱式、易錯顯式 ZoneId/ZoneOffset
日期時間分離無 (Date 混雜)LocalDate / LocalTime / LocalDateTime
格式化SimpleDateFormat (非線程安全)DateTimeFormatter (線程安全)
空值處理null 滿天飛Optional / 明確非空

遷移建議

  1. 新專案強制使用 java.time。
  2. 存量代碼:邊界層 (Controller、DAO) 統一轉換,內部業務邏輯漸進式重構。
  3. 轉換橋樑:
    
    // Calendar → LocalDateTime
    LocalDateTime ldt = calendar.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
    
    // LocalDateTime → Calendar
    Calendar cal = Calendar.from(ldt.atZone(ZoneId.systemDefault()).toInstant());
    
  4. 資料庫交互:JDBC 4.2+ 直接支援 setObject/getObject 操作 LocalDateTime、LocalDate、Instant。

總結

Calendar 曾是 Java 日期運算的主力,但其可變性、0 基月、時區隱式等設計缺陷在高併發、分布式系統中頻發事故。**Java 8 java.time 包 (JSR-310) 以不可變、領域驅動設計徹底解決這些問題**,是現代 Java 日期時間處理的唯一標準選擇。理解 Calendar 的歷史包袱,更能體會新 API 的優雅。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved