基本概念

常用类

java.time包包含处理日期时间所需的类。常用的类有:

  • Instant: An instantaneous point on the time-line.
  • LocalDateTime: A date-time without a time-zone in the ISO-8601 calendar system, such as 2007-12-03T10:15:30.
  • ZonedDateTime: A date-time with a time-zone in the ISO-8601 calendar system, such as 2007-12-03T10:15:30+01:00 Europe/Paris.

时间戳与时间的区别

任意时刻,全球只有一个时间戳Instant;但每个地点的本地时间LocalDateTime可能不同。
举例:时间戳1688871330,对应北京时间2023-07-09T10:55:30,对应伦敦时间2023-07-09T03:55:30。

@Test
public void convertEpochSecondToLocalDateTimeTest() {
    System.out.println(Instant.ofEpochSecond(1688871330).atZone(ZoneId.of("Asia/Shanghai")).toLocalDateTime());
    System.out.println(Instant.ofEpochSecond(1688871330).atZone(ZoneId.of("Europe/London")).toLocalDateTime());
}

反过来也是一样。不同地点的LocalDateTime相同,对应的Instant很可能不同。因此,在将LocalDateTime转换为Instant时,一定要带上准确的时区信息。
举例:本地时间2023-07-09T10:55:30,按北京时间转换得到时间戳1688871330,按伦敦时间转换得到时间戳1688896530。

@Test
public void convertLocalDateTimeToEpochSecondTest() {
    System.out.println(LocalDateTime.of(2023, 7, 9, 10, 55, 30).atZone(ZoneId.of("Asia/Shanghai")).toEpochSecond());
    System.out.println(LocalDateTime.of(2023, 7, 9, 10, 55, 30).atZone(ZoneId.of("Europe/London")).toEpochSecond());
}

反例:获取本地时间后使用UTC时区转换为时间戳。如果本地时间不是UTC时区,那么这样拿到的时间戳会存在偏移。

@Test
public void wrongUsageOfLocalDateTimeTest() {
    System.out.println(LocalDateTime.now().toEpochSecond(ZoneOffset.UTC));
}

最佳实践

获取当前时间戳

ZonedDateTime和Instant都可以拿到当前时间戳。语义上Instant更合适。

@Test
public void getEpochSecondTest() {
    System.out.println(ZonedDateTime.now().toEpochSecond());
    System.out.println(Instant.now().getEpochSecond());
}

获取指定格式时间字符串

@Test
public void getISOFormatTest() {
    System.out.println(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
}