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

Java 日期時間處理實戰:Calendar 與 SimpleDateFormat 完整指南

     編輯:Java 相關知識

核心類速查

類用途線程安全
java.util.Calendar日期運算 (增減年月日、取欄位)❌ (需自行同步或用 ThreadLocal)
java.text.SimpleDateFormat格式化/解析 字串↔Date❌ (極不安全,必須每線程一實例)
java.util.Date時間戳載體 (毫秒精度)✅ (不可變)

常用操作範例

public class DateTimeUtils {

    // 線程安全的格式化器持有者
    private static final ThreadLocal<SimpleDateFormat> FMT_YMD_HMS = 
        ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
    private static final ThreadLocal<SimpleDateFormat> FMT_YMD = 
        ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyyMMdd"));

    /** 當前時間格式化 */
    public static String now(String pattern) {
        return new SimpleDateFormat(pattern).format(new Date());
    }

    /** 字串解析為 Date */
    public static Date parse(String str, String pattern) throws ParseException {
        return new SimpleDateFormat(pattern).parse(str);
    }

    /** 日期加減 (天/月/年) */
    public static Date addDays(Date date, int days) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        c.add(Calendar.DAY_OF_MONTH, days);
        return c.getTime();
    }

    /** 設定時分秒為 00:00:00 (取日期起始) */
    public static Date startOfDay(Date date) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        c.set(Calendar.HOUR_OF_DAY, 0);
        c.set(Calendar.MINUTE, 0);
        c.set(Calendar.SECOND, 0);
        c.set(Calendar.MILLISECOND, 0);
        return c.getTime();
    }

    /** 取指定欄位值 (年/月/日/時/分/秒) */
    public static int getField(Date date, int field) {
        Calendar c = Calendar.getInstance();
        c.setTime(date);
        return c.get(field);
    }

    /** 兩日期相差天數 */
    public static long daysBetween(Date d1, Date d2) {
        long diff = Math.abs(d1.getTime() - d2.getTime());
        return TimeUnit.DAYS.convert(diff, TimeUnit.MILLISECONDS);
    }
}

實戰範例

public static void main(String[] args) throws ParseException {
    // 1. 格式化
    System.out.println("現在: " + DateTimeUtils.now("yyyy-MM-dd HH:mm:ss"));

    // 2. 解析
    Date d = DateTimeUtils.parse("2024-12-25 08:30:00", "yyyy-MM-dd HH:mm:ss");

    // 3. 日期運算
    Date before100 = DateTimeUtils.addDays(d, -100);
    Date after100 = DateTimeUtils.addDays(d, 100);
    System.out.println("100天前: " + FMT_YMD_HMS.get().format(before100));
    System.out.println("100天后: " + FMT_YMD_HMS.get().format(after100));

    // 4. 截取日期部分
    Date midnight = DateTimeUtils.startOfDay(new Date());
    System.out.println("今日零點: " + FMT_YMD_HMS.get().format(midnight));

    // 5. 差值
    System.out.println("相差天數: " + DateTimeUtils.daysBetween(before100, after100)); // 200
}

避坑指南

  • 月份從 0 開始:Calendar.JANUARY == 0,Calendar.DECEMBER == 11。設定月份時務必用常量。
  • SimpleDateFormat 非線程安全:並發環境下共用實例會導致數據錯亂或拋 NumberFormatException。解決:ThreadLocal、每次新建、或用 DateTimeFormatter (Java 8+)。
  • Date 無時區概念:只存毫秒數。格式化/解析時才套用預設時區,跨時區業務請顯式設定 TimeZone。
  • Calendar.getInstance() 返回的是具體子類 (GregorianCalendar),直接轉型安全。

結語

雖然 Java 8+ 推薦使用 java.time 包,但大量存量系統仍依賴 Calendar/SimpleDateFormat。掌握其「月份偏移、線程不安全、時區隱性」三大特性,並配合 ThreadLocal 封裝工具類,即可在舊代碼庫中穩健處理日期業務。

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