在 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. Mac下Homebrew将程序文件存在什么位置

    一般情况是这么操作的: 1.通过brew install安装应用最先是放在/usr/local/Cellar/目录下. 2.有些应用会自动创建软链接放在/usr/bin或者/usr/sbin,同时也会 ...

  2. redis集群cluster简单设置

    环境: 这里参考官方使用一台服务器:Centos 7  redis-5.0.4    192.168.10.10 redis集群cluster最少要3个主节点,所以本次需要创建6个实例:3个主节点,3 ...

  3. [快捷键的使用] IntelliJ IDEA 将数据库里面的表转化为对象

    本文讲述IntelliJ IDEA 多行编辑快捷键的使用,希望能帮到新人提高效率. 注意:在笔记本键盘上操作的方法. 数据库连接工具使用SQLyog 第一步: 从数据里面将文本拷贝到User类里面. ...

  4. English--辅音

    English|辅音 英语中的辅音,按照发音的松紧,唇形舌位,划分为七大类.需要好好地体会具体的发音部位与口型. 前言 目前所有的文章思想格式都是:知识+情感. 知识:对于所有的知识点的描述.力求不含 ...

  5. 双栈(Dual Stack)

    参考博客: 双栈数据结构: https://blog.csdn.net/hebtu666/article/details/83011115 https://blog.csdn.net/cainv89/ ...

  6. Android源码分析(十二)-----Android源码中如何自定义TextView实现滚动效果

    一:如何自定义TextView实现滚动效果 继承TextView基类 重写构造方法 修改isFocused()方法,获取焦点. /* * Copyright (C) 2015 The Android ...

  7. elasticsearch regexp查询特殊字符处理

    regexp表面意思就是正则查询,但是如果遇到,查询条件中包含特殊的字符串, 就会发现,需要进行相应的转义处理 需要处理Lucene regexps即可: /** * 转义字符串中的特殊字符 * 仅过 ...

  8. c#执行sql超时

    超时分为多种,SqlConnection有超时选项, SqlDataAdapter也有超时选项设置如下: SqlConnection:就用链接字符串给予的Timeout设置就行单位秒: SqlData ...

  9. VSCode在Ubuntu下快捷键和Windows下不一致的解决办法

    Windows下切换前一次和后一次光标位置,用的快捷键是Alt+<-和Alt+->.很遗憾,Ubuntu下并不是这个快捷键.不清楚为什么VSCode不提供统一的快捷键,但对于我来说,我很想 ...

  10. Nginx应用详解及配置

    一.Nginx简介 概述:Nginx是一款由俄罗斯开发的开源的高性能HTTP服务器和反向代理服务器,同时支持IMAP/POP3/SMTP代理服务,其性能优势着为显著,官网上称:单台nginx服务器可以 ...