JAVA之日期与时间

在 Java 中,日期和时间的处理有不同的 API 和工具类。在早期的 Java 版本中,主要依赖于 java.util.Datejava.util.Calendar,但它们有一些设计上的缺陷。为了更好地处理日期和时间,Java 8 引入了全新的 java.time 包,这个包提供了更为强大和直观的日期时间处理工具。

1. java.util.Date

  • Date 类表示一个具体的时间点,精确到毫秒。

  • 缺点:Date 类的设计有一些不便之处,如月份从 0 开始、年是从 1900 开始计算的,以及很多方法已经被废弃。

  • 示例:

    1
    2
    Date now = new Date();
    System.out.println(now);

2. java.util.Calendar

  • Calendar 类是对 Date 的增强,提供了更复杂的时间操作功能,例如日期的加减操作。

  • 不直观:设置和读取 Calendar 中的时间字段时,必须使用常量(如 Calendar.MONTH)。

  • 示例:

    1
    2
    3
    4
    Calendar cal = Calendar.getInstance();
    cal.set(2020, Calendar.JANUARY, 1);
    Date date = cal.getTime();
    System.out.println(date);

3. java.time 包(Java 8 引入)

java.time 包为日期和时间的处理提供了现代化的 API。以下是一些主要的类:

#### 3.1 LocalDate

  • LocalDate 表示不带时间的日期,例如 2023-09-15

  • 它只包含日期部分,不包括时间或时区信息。

  • 用于表示特定的日期(例如,生日、纪念日)。

  • 示例:

    1
    2
    3
    4
    LocalDate date = LocalDate.now(); // 获取当前日期
    LocalDate specificDate = LocalDate.of(2020, 1, 1); // 指定日期
    System.out.println(date);
    System.out.println(specificDate);

#### 3.2 LocalTime

  • LocalTime 表示不带日期的时间,例如 12:30:59

  • 它只包含时间部分,不包括日期和时区。

  • 示例:

    1
    2
    3
    4
    LocalTime time = LocalTime.now(); // 获取当前时间
    LocalTime specificTime = LocalTime.of(12, 30, 45); // 指定时间
    System.out.println(time);
    System.out.println(specificTime);

#### 3.3 LocalDateTime

  • LocalDateTime 表示不带时区的日期和时间,例如 2020-01-01 12:30:59

  • 它结合了 LocalDateLocalTime 的功能。

  • 示例:

    1
    2
    3
    4
    LocalDateTime dateTime = LocalDateTime.now(); // 获取当前日期和时间
    LocalDateTime specificDateTime = LocalDateTime.of(2020, 1, 1, 12, 30, 59);
    System.out.println(dateTime);
    System.out.println(specificDateTime);

#### 3.4 ZonedDateTime

  • ZonedDateTime 表示带有时区的日期和时间,例如 2020-01-01T12:30:59+08:00[Asia/Shanghai]

  • 适用于需要处理不同地区、时区的日期和时间情况。

  • 示例:

    1
    2
    3
    4
    ZonedDateTime zonedDateTime = ZonedDateTime.now(); // 当前时区的日期和时间
    ZonedDateTime specificZonedDateTime = ZonedDateTime.of(2020, 1, 1, 12, 30, 0, 0, ZoneId.of("Asia/Shanghai"));
    System.out.println(zonedDateTime);
    System.out.println(specificZonedDateTime);

#### 3.5 Instant

  • Instant 表示时间线上的一个点,精确到纳秒。

  • 它是从 1970-01-01T00:00:00Z 开始的纪元时间,通常用于时间戳或高精度计时。

  • 示例:

    1
    2
    Instant now = Instant.now();
    System.out.println(now);

4. 时区 (ZoneIdZoneOffset)

  • ZoneId 表示时区,如 Asia/Shanghai

  • ZoneOffset 表示 UTC 偏移,例如 +08:00

  • 示例:

    1
    2
    3
    ZoneId zone = ZoneId.of("Asia/Shanghai");
    ZonedDateTime zonedDateTime = ZonedDateTime.now(zone);
    System.out.println(zonedDateTime);

5. 日期与时间的操作

  • 可以对日期和时间进行加减、比较等操作。例如,LocalDate 提供了 plusDays()minusDays()isAfter() 等方法。

  • 示例:

    1
    2
    3
    4
    5
    LocalDate today = LocalDate.now();
    LocalDate tomorrow = today.plusDays(1);
    LocalDate yesterday = today.minusDays(1);
    System.out.println(tomorrow);
    System.out.println(yesterday);

6. 日期格式化 (DateTimeFormatter)

  • DateTimeFormatter 用于将日期和时间格式化为字符串,或从字符串解析日期和时间。

  • 示例:

    1
    2
    3
    4
    5
    6
    7
    8
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    LocalDateTime dateTime = LocalDateTime.now();
    String formattedDateTime = dateTime.format(formatter);
    System.out.println(formattedDateTime);

    // 解析日期时间字符串
    LocalDateTime parsedDateTime = LocalDateTime.parse("2020-01-01 12:30:59", formatter);
    System.out.println(parsedDateTime);

7. 与旧 API 的兼容性

  • 可以通过 Date.from(Instant instant)Calendar.toInstant() 方法实现与 java.util.Datejava.util.Calendar 的互操作。

  • 示例:

    1
    2
    3
    4
    5
    6
    // Date 转换为 Instant
    Date date = new Date();
    Instant instant = date.toInstant();

    // Instant 转换为 Date
    Date newDate = Date.from(instant);

8. 夏令时处理

  • ZonedDateTime 可以自动处理夏令时的转换。通过时区 ID ZoneId,你可以获取正确的时间,甚至考虑到夏令时。

  • 示例:

    1
    2
    3
    4
    5
    ZoneId newYorkZone = ZoneId.of("America/New_York");
    ZonedDateTime summerTime = ZonedDateTime.of(2020, 6, 20, 12, 0, 0, 0, newYorkZone); // 夏令时
    ZonedDateTime winterTime = ZonedDateTime.of(2020, 11, 20, 12, 0, 0, 0, newYorkZone); // 冬令时
    System.out.println(summerTime);
    System.out.println(winterTime);