• Java8中的日期时间API


    背景

    Java8 以前,我们使用、操作时间基本都是通过 java.util.Date 类来实现,或许我们已经习惯了 new Date(),创建出一个表示系统当前时间的对象,但是,这个自从 java 1.0 版本开始就已经提供的类存在着很多问题:

    1. 这个类无法表示日期,只能以毫秒的精度表示时间;
    2. 易用性很差,比如年份的起始是1900年,月份是从0开始,这意味着,我们要创建出表示2022-08-07 这个日期,需要执行下面这样晦涩的代码:
      Date date = new Date(122, 7, 7);
      
      • 1
    3. Date类是可变的,我们可以直接操作将对象变量的值进行调整,这也就导致了函数式编程中可能出现各种各样的操作问题;
    4. 用于格式化或解析时间的DateFormat类并不是线程安全的。多个线程同时使用DateFormat对象时,会产生无法预期的结果。

    为了解决以上问题,Java8中新引入了 java.time 包,以解决上述问题。

    日期时间API

    面向人类的日期或时间

    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);
    
    • 1
    • 2

    值得注意的是,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);
    
    • 1
    • 2

    这样生成的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()));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    也可以通过比较两个时间之间的Duration来获取具体的时间间隔进行判断。

    小结

    本篇总结了Java8中提供的日期、时间相关的类及常用的操作,其主要分为面向人类编程使用的Local开头相关类及面向机器使用的Instant类;表示时间区间、间隔用的Duration、Period类;附加了时区信息的ZonedDateTime类。可以看到这里提供的相关API已经足够全面和简单易用。同时,这些类都是不可变的类型,这对我们在并发变成场景,以及函数式编程的过程中提供了更友好的支持。

  • 相关阅读:
    武汉新时标文化传媒有限公司短视频创业是一个趋势
    C语言——程序环境和预处理
    【农业生产系统模型】基于R语言APSIM模型进阶应用与参数优化、批量模拟实践技术
    微服务项目部署-POS收银系统
    BPA、BPM、BPR傻傻分不清楚?与RPA又有何关系?
    Three.js-着色器加工材质及材质着色器详解
    Ansys Lumerical|菲涅尔透镜设计
    我们距离“裸眼3D自由”,还有多远?
    优秀程序员是怎么思考的?
    catkin_make文件更新经验
  • 原文地址:https://blog.csdn.net/lyg673770712/article/details/126218804