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

Java 日期區間拆分實作:Calendar API 逐日迭代生成日期列表

     編輯:Java 相關知識

業務常見需求:給定起始與結束日期,生成區間內所有日期列表。本文示範使用 Calendar API 實現日期區間拆分,並說明現代 java.time 替代方案。

Calendar API 實作(Java 7 相容)

import java.util.*;
import java.util.Calendar;

public class DateRangeSplitter {
    public static List<Date> splitDateRange(Date startDate, Date endDate) {
        List<Date> result = new ArrayList<>();
        
        Calendar start = Calendar.getInstance();
        start.setTime(startDate);
        // 歸零時分秒毫秒,僅比較日期
        start.set(Calendar.HOUR_OF_DAY, 0);
        start.set(Calendar.MINUTE, 0);
        start.set(Calendar.SECOND, 0);
        start.set(Calendar.MILLISECOND, 0);
        
        Calendar end = Calendar.getInstance();
        end.setTime(endDate);
        end.set(Calendar.HOUR_OF_DAY, 0);
        end.set(Calendar.MINUTE, 0);
        end.set(Calendar.SECOND, 0);
        end.set(Calendar.MILLISECOND, 0);
        
        // 逐日迭代
        while (!start.after(end)) {
            result.add(start.getTime());
            start.add(Calendar.DATE, 1); // 增加一天
        }
        
        return result;
    }
    
    public static void main(String[] args) {
        // 範例:2024-06-01 至 2024-06-05
        Calendar cal = Calendar.getInstance();
        cal.set(2024, Calendar.JUNE, 1);
        Date start = cal.getTime();
        cal.set(2024, Calendar.JUNE, 5);
        Date end = cal.getTime();
        
        List<Date> dates = splitDateRange(start, end);
        SimpleDateFormat sdf = new SimpleDateFormat("MM-dd");
        for (Date d : dates) {
            System.out.println(sdf.format(d));
        }
        // 輸出:
        // 06-01
        // 06-02
        // 06-03
        // 06-04
        // 06-05
    }
}

關鍵細節

  • 歸零時間分量:避免時分秒差異導致比較錯誤
  • Calendar.DATE / Calendar.DAY_OF_MONTH 等價
  • add() 自動處理月份進位、閏年等邊界情況
  • 使用 !start.after(end) 而非 before,包含結束日期

Java 8+ 現代寫法:java.time API

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

public class ModernDateRangeSplitter {
    public static List<LocalDate> splitDateRange(LocalDate start, LocalDate end) {
        return start.datesUntil(end.plusDays(1))
                    .collect(Collectors.toList());
    }
    
    public static void main(String[] args) {
        List<LocalDate> dates = splitDateRange(
            LocalDate.of(2024, 6, 1),
            LocalDate.of(2024, 6, 5)
        );
        DateTimeFormatter fmt = DateTimeFormatter.ofPattern("MM-dd");
        dates.forEach(d -> System.out.println(d.format(fmt)));
    }
}

優勢:不可變、線程安全、流式 API、時區處理清晰、無需手動歸零。

效能與記憶體考量

場景建議
短區間(< 1 年)直接收集為 List
長區間 / 串流處理返回 Stream<LocalDate> 惰性處理
極大區間(年級)分批處理,避免 OOM

常見陷阱

  • Date 可變性導致非預期修改
  • 跨時區場景直接使用 Date 產生偏差
  • 閏秒、夏令時切換日邊界條件
  • 舊 API Calendar.MONTH 從 0 開始(1月=0)

工具類封裝建議

public final class DateUtils {
    private DateUtils() {}
    
    public static List<LocalDate> getDateRange(LocalDate start, LocalDate end) {
        if (start.isAfter(end)) throw new IllegalArgumentException("起始日期不可晚於結束日期");
        return start.datesUntil(end.plusDays(1)).collect(toList());
    }
    
    public static Stream<LocalDate> dateRangeStream(LocalDate start, LocalDate end) {
        return start.datesUntil(end.plusDays(1));
    }
}

日期區間拆分看似簡單,邊界條件與時區處理卻暗藏坑點。新專案強烈建議使用 java.time,舊專案維護時以 Calendar 歸零時間分量為關鍵防禦點。

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