在 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。

Java8 日期与时间 API的更多相关文章

  1. Java8 日期和时间API

    LocalDate.LocalTime.Instant.Duration.Period 1.1使用LocalDate和LocalTime 1.1.1LocalDate的创建方式和相关方法使用示例 @T ...

  2. Java8系列 (六) 新的日期和时间API

    概述 在Java8之前, 我们一般都是使用 SimpleDateFormat 来解析和格式化日期时间, 但它是线程不安全的. @Test public void test() { SimpleDate ...

  3. 详解Java8的日期和时间API

    详解Java8的日期和时间API 在JDK1.0的时候,Java引入了java.util.Date来处理日期和时间:在JDK1.1的时候又引入了功能更强大的java.util.Calendar,但是C ...

  4. 计算机程序的思维逻辑 (95) - Java 8的日期和时间API

    ​本节继续探讨Java 8的新特性,主要是介绍Java 8对日期和时间API的增强,关于日期和时间,我们在之前已经介绍过两节了,32节介绍了Java 1.8以前的日期和时间API,主要的类是Date和 ...

  5. Java编程的逻辑 (95) - Java 8的日期和时间API

    ​本系列文章经补充和完善,已修订整理成书<Java编程的逻辑>,由机械工业出版社华章分社出版,于2018年1月上市热销,读者好评如潮!各大网店和书店有售,欢迎购买,京东自营链接:http: ...

  6. 《Java 8 in Action》Chapter 12:新的日期和时间API

    在Java 1.0中,对日期和时间的支持只能依赖java.util.Date类.同时这个类还有两个很大的缺点:年份的起始选择是1900年,月份的起始从0开始. 在Java 1.1中,Date类中的很多 ...

  7. Java 8 (11) 新的日期和时间API

    在Java 1.0中,对日期和时间的支持只能依赖java.util.Date类.这个类只能以毫秒的精度表示时间.这个类还有很多糟糕的问题,比如年份的起始选择是1900年,月份的起始从0开始.这意味着你 ...

  8. java 8中新的日期和时间API

    java 8中新的日期和时间API 使用LocalDate和LocalTime LocalDate的实例是一个不可变对象,它只提供了简单的日期,并不含当天的时间信息.另外,它也不附带任何与时区相关的信 ...

  9. Java8 日期和时间类

    新的日期和时间API 新的日期和时间类解决了Date和Calendar类出现的问题 浅尝 LocalDate 日期类 LocalDate of = LocalDate.of(2018, 7, 13); ...

随机推荐

  1. 我是如何一步步编码完成万仓网ERP系统的(四)登录的具体实现

    https://www.cnblogs.com/smh188/p/11533668.html(我是如何一步步编码完成万仓网ERP系统的(一)系统架构) https://www.cnblogs.com/ ...

  2. RabbitMQ如何实现高可用

    RabbitMQ一共具有三种模式:单机.普通集群.镜像集群 单机模式 单机模式,就是我们平常玩的demo,生产上肯定不能用.具体安装部署过程可以参考我的这篇文章:CentsOS原生RabbitMQ安装 ...

  3. i春秋——“百度杯”CTF比赛 九月场——Test(海洋cms / seacms 任意代码执行漏洞)

    打开发现是海洋cms,那就搜索相关漏洞 找到一篇介绍海洋cms的命令执行漏洞的文章:https://www.jianshu.com/p/ebf156afda49 直接利用其中给出的poc /searc ...

  4. 批量部署SSH基于key的验证脚本

    工作中,使用ansible等自动化运维工具实现服务器批量自动化运维管理,需要先解决管理端和被管理端的免密码登录,可以脚本实现ssh基于key的验证,代码如下: #!/bin/bash PASS=123 ...

  5. xadmin引入django-rest-framework

    一.安装: pip install djangorestframework 安装djangorestframework库 https://github.com/encode/django-rest-f ...

  6. python基本数据类型的时间复杂度

    1.list 内部实现是数组 2.dict 内部实现是hash函数+哈希桶.一个好的hash函数使到哈希桶中的值只有一个,若多个key hash到了同一个哈希桶中,称之为哈希冲突. 3.set 内部实 ...

  7. Nginx下HTML页面POST请求静态JSON数据返回405状态

    在浏览器访问HTML页面,发现一些静态JSON数据没有显示,F12查看,如下图所示: 可以看到请求方式为POST 将请求链接复制在浏览器地址栏访问,可以正常请求到数据 F12查看,可以看到请求方式为G ...

  8. POJ2536-Gopher II-(匈牙利算法)

    题意:n只老鼠,m个洞,s秒逃命,逃命速度为v,一个洞只能保住一只老鼠,最少多少只老鼠会被老鹰抓到. 题解:找出每只老鼠有哪些洞可以保命,建立二分图,算出最大匹配,不是求保住命的老鼠,而是求被抓住的老 ...

  9. 【java】定时任务停止时间设置

    我的需求:每天9点至20点运行 解决办法:@Scheduled(cron = "0 * 9,10,11,12,13,14,15,16,17,18,19 * * ?") 解释:  逗 ...

  10. [BZOJ2667][cqoi2012][kcoj]模拟工厂

    题目描述 Description 有一个称为“模拟工厂”的游戏是这样的:在时刻0,工厂的生产力等于1.在每个时刻,你可以提高生产力或者生产商品.如果选择提高生产力,在下一个时刻时工厂的生产力加1:如果 ...