雖然 Java 8+ 推薦使用 java.time 套件,但大量存量專案仍使用 SimpleDateFormat + Calendar。本文示範如何將字串 "2015-07-18" 解析為日期、加 8 個月得到 "2016-03-18",並格式化輸出。
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
public class DateCalcDemo {
public static void main(String[] args) {
String str = "2015-07-18";
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
try {
Date myDate = formatter.parse(str);
Calendar c = Calendar.getInstance();
c.setTime(myDate);
c.add(Calendar.MONTH, 8); // 加 8 個月
myDate = c.getTime();
System.out.println(formatter.format(myDate)); // 2016-03-18
} catch (ParseException e) {
e.printStackTrace();
}
}
}
SimpleDateFormat 定義輸入/輸出格式 yyyy-MM-dd。formatter.parse(str) 將字串轉為 Date 物件(代表 UTC 時間點)。Calendar.getInstance() 取得預設時區/語系的日曆實例。c.setTime(myDate) 將日曆設定為該日期。c.add(Calendar.MONTH, 8) 執行日期運算:月份 +8,自動處理跨年、月份天數差異(7/31 +1月 → 8/31)。c.getTime() 取回運算後的 Date。formatter.format() 輸出指定格式字串。SimpleDateFormat 非執行緒安全,多執行緒環境需用 ThreadLocal 或每次新建實例。Calendar.getInstance() 使用 JVM 預設時區,跨時區部署需顯式設定 c.setTimeZone(TimeZone.getTimeZone("UTC"))。add() vs roll():add 會改變較大單位(月份加到 13 月會進位年份),roll 不進位(12 月 roll +1 → 1 月,年份不變)。import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
public class ModernDateCalc {
public static void main(String[] args) {
String str = "2015-07-18";
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd");
LocalDate date = LocalDate.parse(str, fmt);
LocalDate result = date.plusMonths(8);
System.out.println(result.format(fmt)); // 2016-03-18
}
}
優點:不可變物件、執行緒安全、API 直觀、無需處理 Date/Calendar 互轉。
| 需求 | Calendar | java.time |
|---|---|---|
| 加 N 天 | c.add(Calendar.DAY_OF_MONTH, N) | date.plusDays(N) |
| 加 N 月 | c.add(Calendar.MONTH, N) | date.plusMonths(N) |
| 加 N 年 | c.add(Calendar.YEAR, N) | date.plusYears(N) |
| 兩日期差天數 | (d2.getTime()-d1.getTime())/(1000*3600*24) | ChronoUnit.DAYS.between(d1, d2) |