在 Java 8 引入 java.time 之前,JDK 內建 Date/Calendar API 設計缺陷眾多:不可變性差、執行緒不安全、月份 0-based、時區處理繁瑣。Joda-Time 成為事實標準,提供:
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>2.12.7</version> <!-- 建議使用最新穩定版 -->
</dependency>
| 類別 | 用途 | 關鍵特性 |
|---|---|---|
| DateTime | 完整日期時間 (含時區) | 不可變、最常用 |
| LocalDate | 僅日期 (無時間、無時區) | 適合生日、紀念日 |
| LocalTime | 僅時間 (無日期、無時區) | 適合鬧鐘、營業時間 |
| LocalDateTime | 日期時間 (無時區) | 本地時區應用 |
| DateTimeFormatter | 格式化/解析 | 執行緒安全、預定義格式豐富 |
| Period | 日期間隔 (年/月/日) | 人類認知的間隔 |
| Duration | 時間間隔 (毫秒/秒/分/時) | 機器精確的間隔 |
| Days/Hours/Minutes/Seconds | 單一單位間隔 | 便利計算 |
// 建立特定時間
DateTime dt1 = new DateTime(2024, 7, 15, 14, 30, 0);
DateTime dt2 = new DateTime(2024, 7, 15, 14, 30, 0, 123); // 含毫秒
// 當前時間
DateTime now = DateTime.now();
DateTime utcNow = DateTime.now(DateTimeZone.UTC);
// 字串解析
DateTimeFormatter fmt = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss");
DateTime parsed = fmt.parseDateTime("2024-07-15 14:30:00");
// 從 JDK 物件轉換
DateTime fromJdkDate = new DateTime(new java.util.Date());
DateTime fromCalendar = new DateTime(Calendar.getInstance());
DateTime fromMillis = new DateTime(System.currentTimeMillis());
DateTime dt = new DateTime(2024, 7, 15, 14, 30, 0);
System.out.println(dt.toString("yyyy-MM-dd HH:mm:ss")); // 2024-07-15 14:30:00
System.out.println(dt.toString("yyyy年MM月dd日 HH時mm分ss秒", Locale.TRADITIONAL_CHINESE)); // 中文
System.out.println(dt.toString("EEEE, MMMM dd, yyyy")); // Monday, July 15, 2024
System.out.println(dt.toString("yyyy/MM/dd HH:mm Z")); // 含時區偏移
DateTime dt = new DateTime(2024, 7, 15, 14, 30, 0); // 加減運算 DateTime future = dt.plusYears(1).plusMonths(2).plusDays(10).plusHours(3); DateTime past = dt.minusWeeks(2).minusMinutes(30); // 精確到欄位操作 DateTime firstDayOfMonth = dt.dayOfMonth().withMinimumValue(); DateTime lastDayOfMonth = dt.dayOfMonth().withMaximumValue(); DateTime nextFriday = dt.dayOfWeek().setCopy(5); // 5=Friday
LocalDate start = new LocalDate(2024, 1, 1); LocalDate end = new LocalDate(2024, 12, 31); // 天數差 int days = Days.daysBetween(start, end).getDays(); // 精確間隔 (含時間) DateTime dtStart = new DateTime(2024, 1, 1, 0, 0, 0); DateTime dtEnd = new DateTime(2024, 12, 31, 23, 59, 59); Duration duration = new Duration(dtStart, dtEnd); long hours = duration.getStandardHours(); long minutes = duration.getStandardMinutes();
DateTime dt = new DateTime(2024, 2, 1); boolean isLeapYear = dt.year().isLeap(); // true boolean isLeapMonth = dt.monthOfYear().isLeap(); // false (Joda 無閏月概念,僅支援儒略/格里高利曆)
// Joda → JDK java.util.Date jdkDate = dateTime.toDate(); Calendar cal = dateTime.toCalendar(Locale.getDefault()); long millis = dateTime.getMillis(); // JDK → Joda DateTime fromDate = new DateTime(jdkDate); DateTime fromCal = new DateTime(cal); DateTime fromMillis = new DateTime(millis);
public class BabyAgeCalculator {
private static final DateTimeFormatter FMT_SEC = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss");
private static final DateTimeFormatter FMT_DAY = DateTimeFormat.forPattern("yyyy-MM-dd");
private static final String BIRTHDAY = "2020-03-10 08:20:55";
public static void main(String[] args) {
DateTime birth = FMT_SEC.parseDateTime(BIRTHDAY);
DateTime now = DateTime.now();
printAge(birth, now);
// 模擬指定日期
DateTime target = FMT_DAY.parseDateTime("2024-07-15").toDateTimeAtStartOfDay();
printAge(birth, target);
}
static void printAge(DateTime start, DateTime end) {
// 日期部分差異
LocalDate s = start.toLocalDate();
LocalDate e = end.toLocalDate();
int days = Days.daysBetween(s, e).getDays();
// 時間部分差異 (需處理借位)
int hours = end.getHourOfDay() - start.getHourOfDay();
int mins = end.getMinuteOfHour() - start.getMinuteOfHour();
int secs = end.getSecondOfMinute() - start.getSecondOfMinute();
if (secs < 0) { secs += 60; mins--; }
if (mins < 0) { mins += 60; hours--; }
if (hours < 0) { hours += 24; days--; }
System.out.printf("已出生 %d天 %d時 %d分 %d秒%n", days, hours, mins, secs);
}
}
Joda-Time 作者 Stephen Colebourne 參與設計了 JSR-310 (java.time),兩者 API 高度相似。對照表:
| Joda-Time | java.time (JDK 8+) |
|---|---|
| DateTime | ZonedDateTime / OffsetDateTime |
| LocalDate | LocalDate |
| LocalTime | LocalTime |
| LocalDateTime | LocalDateTime |
| DateTimeFormatter | DateTimeFormatter |
| Period | Period |
| Duration | Duration |
| DateTimeZone | ZoneId / ZoneOffset |
新專案請直接使用 java.time;維護舊專案時 Joda-Time 仍是優秀選擇。