業務常需「以天為單位」處理日期(如日曆展示、統計周期),卻受困於 Date 含時間、時區偏移導致跨天誤差。本工具類將日期統一折算為「自 1970-01-01 以來的天數」,屏蔽時間與時區影響。
private static final long MSEC_EVERYDAY = 86400000L; // 24*60*60*1000
private static final int rawOffset = TimeZone.getDefault().getRawOffset(); // 本地時區偏移(毫秒)
關鍵公式:day = (date.getTime() + rawOffset) / MSEC_EVERYDAY。加上偏移量後再除,確保同一「自然日」在不同時區得到相同天數。
| 方法 | 說明 |
|---|---|
dateToDay(Date) | Date → 天數 |
dayToDate(int) | 天數 → Date(時間為當地午夜 00:00) |
toDay() | 今日天數 |
getYMD(int) | 天數 → "YY/MM/DD" |
getYM(int) | 天數 → "YYYY/MM" |
getMD(int) | 天數 → "MM/DD" |
getMonthFirstDay(int) | 該月 1 號對應天數 |
getYear/Month/Week(int) | 提取年/月/周序號(以 1971-01-03 為第一周週日) |
int today = DateUtil.toDay(); // 如 19823
String ymd = DateUtil.getYMD(today); // "24/05/15"
int firstDay = DateUtil.getMonthFirstDay(today); // 月初天數
ThreadLocal<Calendar> 或 Java 8+ LocalDate。Calendar / java.time。java.time.ZoneId 處理。Java 8+ 推薦使用 LocalDate + ChronoUnit.DAYS.between(EPOCH, localDate),天然無時區、不可變、線程安全,代碼更簡潔:
long days = ChronoUnit.DAYS.between(LocalDate.ofEpochDay(0), LocalDate.now(ZoneId.systemDefault()));