Java 8 时间 API 快速入门
Java 8 出来很久了,各位也可能已经在用了,不过其中新的时间日期 API 可能很少人用,甚至不知道怎么上手。本文快速介绍一下其中的主要的类的概念和用法。
一、时间戳 Instant
Instant
表示一个 EPOCH 时间戳(即以 0 表示 1970-01-01T00:00:00Z),精确到纳秒。 Instant
对象不包含时区信息,且值是不可变的。
虽然概念很简单,但是它可以很方便的和其他时间日期对象之间进行交互和转换。比如:
- 两个
Instant
可以用来构建一个时间段; - 一个
Instant
加上一个时长可以得到另一个Instant
; - 一个
Instant
加上一个时区可以得到一个ZonedDateTime
对象。
创建 Instant
首先 Instant 有下面几个常量:
-
Instant.EPOCH
表示 1970-01-01T00:00:00Z -
Instant.MIN
表示 Instant 可度量的最早时间,公元前十亿年 -
Instant.MAX
表示 Instant 可度量的最晚时间,公元十亿年
我们也可以通过一些静态方法来创建:
-
Instant.now()
表示当前时间戳 -
Instant.ofEpochMilli(longmilliSec)
通过现有的毫秒时间戳来创建 Instant 对象 -
Instant.ofEpochSecond(longseconds)
通过现有的秒时间戳来创建 Instant 对象
从 Instant 取值
Instant
对象包含两个值:秒数和纳秒数。其中秒数指的是 epoch 时间戳,而纳秒数指的是该秒内的纳秒时间。由此可知, Instant
对象的精确度比 System.currentTimeMillis()
高到不知道哪去了。
所以从 Instant 可以取到两个值: Instant.getEpochSecond()
获取秒数部分, Instant.getNano()
获取纳秒部分。
Instant 的操作
- 加减:
plus()
,minus()
; - 相互比较:
isAfter()
,isBefore()
; - 获得时间差:
until()
。
下面是几个例子:
Instant instant1 = Instant.now();
Instant instant2 = instant1.plus(Duration.ofSeconds(100)); // 添加 100 秒
System.out.println(instant2.isAfter(instant1)); // true
System.out.println(instant1.until(instant2, ChronoUnit.SECONDS)); // 100
将 Instant 转换成完整的时间
这部分将在后面介绍。
二、本地日期 / 本地时间 / 本地日期时间 (LocalDate/LocalTime/LocalDateTime)
LocalDate
表示年月日,其精确度到天。它是不包含时分秒的。
LocalTime
表示一天当中的时间,其精确度到纳秒。它是不包含年月日的。
LocalDateTime
既包含日期也包含时间,但是不包含时区。它实际上就是 LocalDate
和 LocalTime
的组合。
创建 LocalDate/LocalTime/LocalDateTime 对象
这三个类都有下面的几个静态方法来创建对象:
-
now()
表示当前时间或日期的对象; -
of()
使用指定的值来创建; -
parse()
通过解析字符串来创建。
此外一个 LocalDate
对象和一个 LocalTime
对象可以组合为一个 LocalDateTime
对象。
下面是几个例子:
LocalTime localTime = LocalTime.now();
LocalDate localDate = LocalDate.of(2018, 3, 5);
LocalDateTime localDateTime = LocalDateTime.parse("2018-03-05T12:34:56");
// 下面两句是等价的
LocalDateTime localDateTime1 = localDate.atTime(localTime);
LocalDateTime localDateTime2 = localTime.atDate(localDate);
此外它们还有各自的创建对象的静态方法,具体请参考 API 文档。
到了这里你可能发现 LocalDateTime
和 Instance
本质上是一样的,都表示一个全局跨度内的一个时间点。那么两者是否可以互换呢?很可惜,不能直接互换。
因为 LocalDateTime
没有带时区,而 Instance
的时间戳是统一以格林尼治时间为准的,所以相同的 LocalDateTime
在不同时区的 EPOCH 时间戳不同,转换的时候必须附加一个时区。下面是例子:
// LocalDateTime -> Instant
Instant instant = Instant
.from(LocalDateTime.now().atZone(ZoneId.systemDefault()));
// 或者
Instant instant = Instant.from(ZonedDateTime.now());
// Instant -> LocalDateTime
LocalDateTime localDateTime = LocalDateTime
.ofInstant(Instant.now(), ZoneId.systemDefault());
三、时长 Duration/Period
Duration 表示以秒为单位的时长,精确到纳秒。Period 表示以天为单位的时长,精确到天。
创建 Duration/Period
有三类方法可以创建时长对象:
-
of()
通过指定的值来创建; -
parse()
通过解析字符串来创建; -
between()
通过两个时间点来创建。
下面是几个例子:
Duration duration1 = Duration.between(Instant.EPOCH, Instant.now());
Duration duration2 = Duration.between(LocalTime.parse("00:00:01"), LocalTime.now());
Period period1 = Period.parse("P1Y2M3D"); // 表示一年两个月零三天
Period period2 = Period.of(1, 2, 3); // 同上
注意时长可以为负数。
之前说过,一个 Instant
加上一个时长可以得到另一个 Instant
。下面是个例子:
Instant then = Instant.now().plus(period);
时长的操作
- 时长与时长可以加减。例如
Periodperiod2=period1.plus(Period.ofDays(1));
表示period1
加上一天。 - 一个时间点加上一个时长可以得到另一个时间点。例如
LocalDateTimetime=LocalDateTime.now().plus(period);
。
时长的单位
这里必须注意的一点是, Duration
和 Period
的值不是单个数字,而是多个单位的组合,像 Period
是年月日的组合,比如 “1年零3个月零5天”,你不能把它看作是 (1 x 365 + 3 x 30 + 5) 天,因为这里可能有闰年和非闰年的区别。所以 Period.ofYears(1)
是无法转换为天数的。
四、时间单位转换
当我们要具体计算两个时间点之间的秒数或天数,该怎么办呢?这里有一个叫 ChronoUnit
的类。下面是几个例子:
// 离那个什么中华民族的伟大复兴还有多少天
long days = ChronoUnit.DAYS.between(LocalDate.now(), LocalDate.of(2049, 10, 1));
其实 Java 8 的这套时间 API 比之前的 Date 和 Calendar 都要好懂得多,稍微练习一下就可以运用自如。
觉得本文对你有帮助?请分享给更多人。
关注「程序员宝库」公众号,直接获取各种编程资料!
- 基于Nginx负载均衡方案
- Android 使用android-support-multidex解决Dex超出方法数的限制问题
- Netty 实现原理浅析
- 上海2017QCon个人分享总结
- 为最佳性能调优 Nginx
- 《微信小程序七日谈》- 第一天:人生若只如初见
- 类加载器详解
- 《微信小程序七日谈》- 第二天:你可能要抛弃原来的响应式开发思维
- 《微信小程序七日谈》- 第三天:玩转Page组件的生命周期
- 《微信小程序七日谈》- 第四天:页面路径最多五层?导航可以这么玩
- 《微信小程序七日谈》- 第五天:你可能要在登录功能上花费大力气
- 《微信小程序七日谈》- 第六天:小程序devtool隐藏的秘密
- boi剖析 - 基于webpack的css sprites实现方案
- 深入JDK源码之ThreadLocal类
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释