Java8 以前,我们使用、操作时间基本都是通过 java.util.Date 类来实现,或许我们已经习惯了 new Date(),创建出一个表示系统当前时间的对象,但是,这个自从 java 1.0 版本开始就已经提供的类存在着很多问题:
Date date = new Date(122, 7, 7);
为了解决以上问题,Java8中新引入了 java.time 包,以解决上述问题。
java.time 包中的核心接口是 Temporal,表示一个瞬时的时间对象,我们日常使用的LocalDate、LocalTime 等等都实现了该接口。这里提到的LocalDate,实际上解决了Date类无法表示日期的问题,LocalDate 表示了一个指定的日期对象。其提供了of、now等静态工厂方法来直接创建日期对象。
与之对应的,LocalTime表示的是一个时间对象,其提供的方法、创建方式与LocalDate类似,可以与LocalDate进行整合,生成表示日期与时间的 LocalDateTime 对象。这里起始可以对应到原来的 Date 类了,但它比Date对象要好用的多……
首先,其提供了简单、直接的创建方式,可以通过LocalDate.atTime,或者localTime.atDate来创建,也可以通过其自身的静态工厂方法 of 来创建。其次,我们可以轻易获得独立的日期或时间单独的信息。在格式化、解析时间方面,也提供了对应的DateTimeFormatter类来进行操作:
LocalDate date1 = LocalDate.parse("20140318", DateTimeFormatter.BASIC_ISO_DATE);
LocalDate date2 = LocalDate.parse("2014-03-18", DateTimeFormatter.ISO_LOCAL_DATE);
值得注意的是,java8中的这些类,都是不可变的类,也就以为着我们在并发场景中、函数式编程方式中,可以安全的共享使用它们。
另外,以上这些时间相关的类,其实都是主要为了适用于我们人类进行阅读和创建的方式,如果我们想直接创建面对计算机使用的时间类型,可以使用java8中提供的 Instant 类,其本质就是一个通过秒和纳秒的数值表示的一个时间,它无法处理我们容易理解的那些单位,比如 get(ChronoField.DAY_OF_MONTH) 执行时会直接抛出异常。
以上都是Temporal的实现类,定义了如何读取和操作为时间对象建模的值。如果我们要表示时间段或者日期区间的话,可以使用Duration、Period两个类,同样,可以通过between、from、of等静态方法来创建,同时其提供了对应的一些操作的方法。
虽然LocalDate、LocalTime等日期时间对象提供了一些基本的操作方法,用来调整、生成新的对象,但是对于一些复杂的调整操作,比如将日期调整到下个周日、下个工作日,或者是本月的最后一天。这时,你可以使用重载版本的with方法,向其传递一个提供了更多定制化选择的TemporalAdjuster对象,TemporalAdjuster也提供了一些基本的静态工厂方法来支持常见操作,通知支持自定义。
以上日期、时间对象都不包括时区,如果我们要想在某一具体时区内进行操作可以通过 java.time.ZoneId,及其子类 java.time.ZoneOffset 类来实现:
ZoneId zoneId = ZoneId.of("Asia/Shanghai");
ZonedDateTime zdt = Instant.now().atZone(zoneId);
这样生成的ZonedDateTime对象,就是在LocalDateTime的基础上,附加了时区的信息。
计算两个时间是否为同一天的方法:
LocalDateTime curStartTime = LocalDateTime.of(2022, 8, 7, 0, 1);
ZoneId zoneId = ZoneId.of("Asia/Shanghai");
ZonedDateTime zonCurStartTime = curStartTime.atZone(zoneId);
LocalDate curDate = Instant.now().atZone(zoneId).toLocalDate();
assertTrue(curDate.isEqual(zonCurStartTime.toLocalDate()));
LocalDateTime lastDayTime = curStartTime.minusMinutes(2L);
ZonedDateTime zonedLastDayTime = lastDayTime.atZone(zoneId);
assertFalse(curDate.isEqual(zonedLastDayTime.toLocalDate()));
也可以通过比较两个时间之间的Duration来获取具体的时间间隔进行判断。
本篇总结了Java8中提供的日期、时间相关的类及常用的操作,其主要分为面向人类编程使用的Local开头相关类及面向机器使用的Instant类;表示时间区间、间隔用的Duration、Period类;附加了时区信息的ZonedDateTime类。可以看到这里提供的相关API已经足够全面和简单易用。同时,这些类都是不可变的类型,这对我们在并发变成场景,以及函数式编程的过程中提供了更友好的支持。