420. Java 日期时间 API - 简介

1. 为什么要有 Date-Time API?

时间,看起来很简单,对吧?随便一个手表都能告诉你当前的日期和时间。
但当你仔细研究,就会发现时间系统其实非常复杂:

  • 📅 月份差异:把 1 月 31 日加上 1 个月,在闰年和非闰年结果是不同的。
  • 🌍 时区问题:不同国家可能会突然修改夏令时(Daylight Saving Time),有的年份甚至会跳过夏令时。
  • 🕒 全球一致性:不同文化和日历系统(公历、伊斯兰历、佛历等)会带来更多差异。

为了解决这些问题,Java 在 Java 8 中引入了全新的 Date-Time API(java.time 包)


2. Date-Time API 的核心特点 ✨

2.1 ISO-8601 标准

默认情况下,Java 使用 ISO-8601(基于公历 Gregorian calendar),这是国际通用的日期时间标准。

常用类包括:

  • LocalDateTime → 不带时区的日期和时间
  • ZonedDateTime → 带时区的日期和时间
  • OffsetDateTime → 带时区偏移量(例如 UTC+8)的日期和时间

👉 如果你想使用其他日历(如伊斯兰历 Hijrah 或泰国佛历 Thai Buddhist),可以通过 java.time.chrono来实现。

示例:

// 使用 ISO-8601 公历
LocalDateTime now = LocalDateTime.now();
System.out.println("当前时间: " + now);

// 使用 Hijrah(伊斯兰历)
HijrahDate hijrahDate = HijrahDate.now();
System.out.println("伊斯兰历日期: " + hijrahDate);

2.2 Locale 与时区支持 🌍

  • Java 使用 CLDR (Unicode Common Locale Data Repository) → 提供多语言的日期时间格式。
  • 使用 TZDB (Time-Zone Database) → 全球时区变化记录,从 1970 年起的历史数据都能处理。

示例:

ZonedDateTime tokyoTime = ZonedDateTime.now(ZoneId.of("Asia/Tokyo"));
ZonedDateTime newYorkTime = ZonedDateTime.now(ZoneId.of("America/New_York"));

System.out.println("东京时间: " + tokyoTime);
System.out.println("纽约时间: " + newYorkTime);

3. Date-Time API 的设计原则 🎯

3.1 Clear(清晰)

API 的方法行为明确。例如,如果你传入 null 参数,通常会抛出 NullPointerException


3.2 Fluent(流式调用)

大部分方法返回的对象都不是 null,所以可以方便地 链式调用
这让代码既简洁又直观。

示例:

LocalDate today = LocalDate.now();
LocalDate payday = today
        .with(TemporalAdjusters.lastDayOfMonth()) // 找到当月最后一天
        .minusDays(2);  // 提前两天作为发薪日

System.out.println("发薪日: " + payday);

3.3 Immutable(不可变)

Date-Time API 中的大多数类都是 不可变对象

  • 对象一旦创建就不能修改。
  • 修改时间时,返回的是一个新的对象。
  • 因此,API 是 线程安全的,可以放心在并发环境中使用。

示例:

LocalDate birthday = LocalDate.of(2024, Month.DECEMBER, 29);
LocalDate firstBirthday = birthday.plusYears(1);

System.out.println("出生日期: " + birthday);
System.out.println("一周岁生日: " + firstBirthday);

注意:birthday 不会被修改,而是新生成了 firstBirthday


3.4 Extensible(可扩展)

你可以自定义:

  • 时间调整器(Time Adjusters)
  • 时间查询(Queries)
  • 甚至自定义日历系统

示例:自定义一个“下一个工作日”的调整器

LocalDate today = LocalDate.now();
TemporalAdjuster nextWorkdayAdjuster = temporal -> {
    DayOfWeek dow = DayOfWeek.from(temporal);
    int days = (dow == DayOfWeek.FRIDAY) ? 3 :
    (dow == DayOfWeek.SATURDAY) ? 2 : 1;
    return temporal.plus(days, java.time.temporal.ChronoUnit.DAYS);
};

LocalDate nextWorkday = today.with(nextWorkdayAdjuster);
System.out.println("下一个工作日: " + nextWorkday);

总结 ✅

Java 的 Date-Time API 相比旧的 java.util.DateCalendar

  • 清晰API 行为明确
  • 流畅:支持链式调用
  • 安全:不可变 & 线程安全
  • 强大:支持多语言、多日历系统和全世界的时区规则

👉 在实际开发中,推荐优先使用 java.time 包,而不是旧的 Date/Calendar

更多推荐