zoukankan      html  css  js  c++  java
  • Java8 日期与时间 API

    在 Java 中,想处理日期和时间时,通常都会选用 java.util.Date 这个类进行处理。不过不知道是设计者在当时没想好还是其它原因,在 Java 1.0 中引入的这个类,大部分的 API 在 Java 1.1 中就被标记为了 Deprecated(已过时),而这些标记为已过时的接口大部分都是一些 getter 和 setter,它们被移到了 java.util.Calendarjava.text.DateFormat 这些类里面。这样就出现了我想操作日期和时间,结果需要同时操作好几个类,给编程带来了麻烦。除此之外,java.util.Date 本身还有设计上的缺陷。诸如月份从 0 开始啦、年份从 1900 年开始推算(JavaScript 也是这个尿性),外部可以随意更改等。为了解决这些痛点,也出现了一些第三方的工具包帮助开发者,在 Java 8 中,一组新的日期与时间 API (JSR-310)被引入进来,解决了上面的种种问题。接下来,将简要介绍这一组 API,并给出我自己的一些使用建议。

    JSR-310(日期与时间 API)简介

    Java 8 中引入的这一套新的 API 位于 java.base 模块,java.time 包下。官方文档对这一组 API 的描述如下:

    The main API for dates, times, instants, and durations.

    The classes defined here represent the principle date-time concepts, including instants, durations, dates, times, time-zones and periods. They are based on the ISO calendar system, which is the de facto world calendar following the proleptic Gregorian rules. All the classes are immutable and thread-safe.

    简单地说,就是把我们能想到的所有对时间的相关操作都包含进来了。这些日期/时间/时刻/时段类的实体都是不可改变(immutable)的,对它们的任何修改都将产生一个新的对象。因此也是线程安全的。

    在这个包下常用的一些类/枚举列举如下

    class/enum 描述
    Instant 表示时间轴上的一个时刻。与 java.util.Date 可以通过 Date.toInstant()Date.from(Instant) 进行互相转化。
    LocalDateTime/LocalDate/LocalTime 表示(不带时区的)日期/时间
    DayOfWeek 定义了一组表示星期几的常量(e.g. TUESDAY
    Month 定义了一组表示月份的常量(e.g. JULY

    在 API 的命名上,该包下的 API 命名遵循如下规则:

    • of - static factory method
    • parse - static factory method focussed on parsing
    • get - gets the value of something
    • is - checks if something is true
    • with - the immutable equivalent of a setter
    • plus - adds an amount to an object
    • minus - subtracts an amount from an object
    • to - converts this object to another type
    • at - combines this object with another, such as date.atTime(time)

    另外,根据 MyBatis 文档的说明,从 3.4.5 开始,MyBatis 默认支持 JSR-310(日期和时间 API),所以用上述的日期与时间 API 也是可以用来操作数据库中的时间数据的。其它的 ORM 框架(Hibernate 等)应该也提供了对这一套 API 的支持。

    对于 Android 开发者来说,印象中是直到 API Level 28 才能够使用 JSR-310 这一套 API,所以对于 Android 开发者来说,使用第三方的日期时间库可能是更妥当的选择(出于应用程序的向下兼容)

    使用例子

    这里举一个我在开发考试系统过程中的例子。读者也可以通过阅读这篇文章获取更加完整的 API 使用的示例。

    在考生登录考试系统中,需要设定他的考试开始时间和结束时间,其中开始时间默认为现在,结束时间由开始时间加上试卷上的考试时间(以分钟为单位)得到。

    考试记录的实体类的部分代码如下:

    @TableName("t_exam_record")
    public class ExamRecordEntity implements Serializable {
        private static final long serialVersionUID = 1L;
    
        /**
         * 考试记录ID
         */
        @TableId("id")
        private Long examRecordId;
    
        /**
         * 计划开始时间
         */
        @TableField("plan_start_time")
        private Instant planStartTime;
    
        /**
         * 计划结束时间
         */
        @TableField("plan_end_time")
        private Instant planEndTime;
    
        /**
         * 实际开始时间
         */
        @TableField("actual_start_time")
        private Instant actualStartTime;
    
        /**
         * 实际结束时间
         */
        @TableField("actual_end_time")
        private Instant actualEndTime;
        
        // 省略 getter、setter
    }
    

    其中当考生开始考试后,需要设置 planStartTimeplanEndTimeactualStartTime 为相应的值。如果这里使用 java.util.Date,那么除了直接用 new 创建一个实体会比较方便以外,其它的操作就变得相当麻烦了。而如果用上新式 API,只要以下几行代码即可完成:

    /**
     * 考试开始,保存考试记录
     * @param limitTime 考试时长(分钟为单位)
     * @return 考试记录的 DTO,用于后续处理
     */
    private MobilePaperDTO saveNewRecord(int limitTime) {
        ExamRecordEntity entity = new ExamRecordEntity();
    
        Instant currentTime = Instant.now();
        entity.setPlanStartTime(currentTime);
        entity.setActualStartTime(currentTime);
        entity.setPlanEndTime(currentTime.add(limitTime, ChronoUnit.MINUTES));
    
        // 省略其它操作
    }
    

    其中 ChronoUnit 是预先定义好的一组时间单位。由于 Instant 代表的是时间轴上的一个点,只能加减上一个“时间段”(在 java.time.temporal 包下有相关定义)。如果这里选择使用 LocalDateTime 保存日期和时间,则可直接使用 LocalDateTime.plusMinutes() 方法。Java 并不支持运算符重载,不然在某些支持运算符重载的语言(例如 Kotlin)上,这套 API 可以表现的更优雅一些。

    开发建议

    就我个人的使用见解来说,这部分新的 API 肯定是越早引入越好。如果是老旧系统或者和别的不熟悉这套 API 的开发者协同开发,建议直接使用 Instant,因为这个就是官方用来取代 Date 的类,并且与 Date 间可以相互转化,之后再慢慢引入其它 API。

  • 相关阅读:
    【五一qbxt】day7-1 引水入城
    【五一qbxt】day6 OI中的stl
    【五一qbxt】test2
    ASCII码
    深入浅出Redis04使用Redis数据库(lists类型)
    深入浅出Redis03 使用Redis数据库(hashes类型)
    深入浅出Redis01安装
    FireFox & Chrome 使用技巧
    Android学习笔记03-搭建Win8下的Android开发环境
    java + jquery + ajax + json 交互
  • 原文地址:https://www.cnblogs.com/Downstream-1998/p/11627364.html
Copyright © 2011-2022 走看看