Java8 Time包浅析

  • 本文时对Java8 Time包中做一个简单的解析,适用于对Time包不甚了解/快速上手的人。

1. 从api上理解

说明
java.time 核心时间类
java.time.chrono 其他地方的纪年法
java.time.format 时间格式化相关的类
java.time.temporal 定义时间的基础接口
java.time.zone 时区相关的类
  • 基类:
说明
Duration 表示持续时间,从一个时间点持续到另一个时间点,比如:数据结构课从8:00上到10:00
Instant 时间点
LocalDate 本地日期,默认时区,精确到日
LocalTime 本地时间,默认时区,精确到秒
LocalDateTime 本地日期时间,默认时区,上二者相加
MonthDay 月份中的日期,不存年, 例如:123
OffsetDateTime ISO-8601日历系统中的UTC /格林威治偏移的日期时间,如2007-12-03T10:15:30+01:00。 旨在使用ZonedDateTimeInstant在较简单的应用中对数据进行建模。 当更详细地建模日期时间概念时,或者当与数据库或网络协议进行通信时,可以使用此类。
OffsetTime 同上,但仅是时间:如10:15:30+01:00
Period 表示时间段,最小单位是天,开始结束时间点不确定,比如:国庆放7天假
Year
YearMonth 一年中的月,不存日, 例如:20223
ZonedDateTime 时区的日期时间,精度为纳秒,
ZoneId 时区ID,比如Asia/Shanghai
DayOfWeek 一周的天,枚举类
Month 月,枚举类
DateTimeFormatter 日期格式化

2. 具体使用场景

2.1 创建时间及查询
  • 创建年月日
1
2
3
4
LocalDate now = LocalDate.now();
//2022-10-27
LocalDate birthday = LocalDate.of(2008,8,12);
//2008-05-12
  • 创建时分秒
1
2
3
4
5
6
7
LocalTime nowTime = LocalTime.now();
//10:55:02.057948
LocalTime workTime = LocalTime.of(8,30);
//08:30
LocalTime lunchTime = LocalTime.of(12,1,21,999999);
//12:01:21.000999999
//ps:最后一位单位为纳秒,九位小数
  • 创建完整体
1
2
3
4
5
6
LocalDateTime nowDateTime = LocalDateTime.now();
//2022-10-27T11:15:35.839724
LocalDateTime cakeTime = LocalDateTime.of(birthday,lunchTime);
//2008-08-12T12:01:21.000999999
LocalDateTime supperTime = LocalDateTime.of(2022,10,27,13,10,10,1);
//2022-10-27T13:10:10.000000001
  • 查询
1
2
3
4
//可以查的非常细致,这里举例几个常用的
nowDateTime.getDayOfMonth();
nowDateTime.getDayOfWeek();
nowDateTime.getYear();
2.2 时间比较
  • 相同格式时间比较
1
2
3
4
5
6
7
now.isAfter(birthday);
//true
LocalTime workTime1 = LocalTime.of(8,30);
workTime.equals(workTime1);
//true
nowDateTime.isBefore(cakeTime);
//false
  • 不同格式时间转化比较

    LocalDate/LocalTime/LocalDateTime三者不能相互直接比较。
    其中LocalDateTime可以通过toLocalDate()/toLocalTime()进行转化再进行比较。

1
2
nowDateTime.isAfter(ChronoLocalDateTime.from(now));
//Error
  • 与1.7用的时间java.util.Date进行比较
1
2
3
4
5
6
7
8
Calendar calendar = Calendar.getInstance();
Date nowOldDate = calendar.getTime();
//Thu Oct 27 14:44:25 CST 2022
//需要将nowOldDate转化为LocalDateTime才能比
Instant startTime = nowOldDate.toInstant();
ZoneId zoneId = ZoneId.systemDefault();
LocalDateTime nowNewDate = LocalDateTime.ofInstant(startTime, zoneId);
//2022-10-27T14:47:56.468
2.3 时间转化
  • 本包内互转

    • ZonedDateTimeLocalDateTime互转

      ZonedDateTime相对与后者多表示时区,所以:

    1
    2
    3
    4
    ZonedDateTime BeijingTime = nowDateTime.atZone(ZoneId.of("Asia/Shanghai"));
    //2022-10-27T15:11:41.466572+08:00[Asia/Shanghai]
    nowDateTime = BeijingTime.toLocalDateTime();
    //2022-10-27T15:12:05.377544
    • OffsetDateTimeLocalDateTime互转

      OffsetDateTime相对后者多表示偏移量,偏移量(ZoneOffset) 的意思是时间相对与 UTC 标准时区的偏移的时间。

      UTC 偏移量 仅仅只记录了时分秒而已,除此之外没有任何其他信息。举个例子 ,+08:00 的意思时超前于 UTC 八个小时,而 -05:45 意思是落后于 UTC 五小时四十五分钟,偏移量最大+18:00,最小-18:00

      偏移量和时区的关系。Asia/Shanghai,也称东8区 +08:00。但是在某些时间场景下时区有时会对应着与之前不同的偏移量。时区跟人类社会有关,比如说以后曹县很牛,可能就会有个Asia/Caoxian,对应的偏移量可能就是+07:40

    1
    2
    3
    4
    OffsetDateTime offsetDateTime = nowDateTime.atOffset(ZoneOffset.MIN);
    //2022-10-27T15:55:09.871589-18:00
    nowDateTime = offsetDateTime.toLocalDateTime();
    //2022-10-27T15:55:09.871589
  • 转其他格式

    • 与字符串互转之格式化

      • 转时间戳
      1
      2
      3
      4
      Timestamp timestamp = Timestamp.valueOf(nowDateTime);
      //时间戳转LocalDateTime
      nowDateTime = timestamp.toLocalDateTime();
      //2022-11-13T13:46:47.851677
      • 转时间点
      1
      Instant point = nowDateTime.toInstant(ZoneOffset.ofHours(8));
2.4 时间调整
  • 加减天/周/月/年/秒/分/时

    1
    2
    3
    4
    5
    nowDateTime.minusDays(1);
    nowDateTime.minusWeeks(1);
    nowDateTime.plusHours(1);
    nowDateTime.plusMinutes(1);
    //..
  • 加减 另一个时间

    1
    2
    3
    4
    nowDateTime = nowDateTime.plus(Period.of(10,1,1));
    //-before-plus: 2022-10-27T17:08:29
    //--after-plus: 2032-11-28T17:08:29
    //同理有minus()方法。
  • 最后放一张图总结一下

  • 缺陷

    笔者在使用过程中发现新的时间包缺少对季节的相关处理:比如说查询当前时间在是哪个季节。

    这里可以自己写一个简易的方法,示例如下。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    /**
    * 查询当前月份所在季节code
    * @param month (1~12)
    * @return (1~4)
    */
    int getSeasonValueByMonth(int month){
    if (month == 1) {
    return 1;
    }
    return (month -1) /3 + 1;
    }
  • 参考文章

    java 8 中的 ZoneOffsetZoneId

    LocalDateTimeOffsetDateTimeZonedDateTime互转