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 既包含日期也包含时间,但是不包含时区。它实际上就是 LocalDateLocalTime 的组合。

创建 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 文档。

到了这里你可能发现 LocalDateTimeInstance 本质上是一样的,都表示一个全局跨度内的一个时间点。那么两者是否可以互换呢?很可惜,不能直接互换。

因为 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);
时长的单位

这里必须注意的一点是, DurationPeriod 的值不是单个数字,而是多个单位的组合,像 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 都要好懂得多,稍微练习一下就可以运用自如。

觉得本文对你有帮助?请分享给更多人。

关注「程序员宝库」公众号,直接获取各种编程资料!

原文发布于微信公众号 - 程序员宝库(chengxuyuanbaoku)

原文发表时间:2018-03-07

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏函数式编程语言及工具

Akka(23): Stream:自定义流构件功能-Custom defined stream processing stages

    从总体上看:akka-stream是由数据源头Source,流通节点Flow和数据流终点Sink三个框架性的流构件(stream components)...

46180
来自专栏GIS讲堂

geotools获取给定点的DEM高程值

1、在web端绘制一条曲线; 2、获取各节点处的高程值; 3、根据高程值绘制高程堆积图。

21750
来自专栏Clive的技术分享

代码重构的方法

21340
来自专栏小樱的经验随笔

Codeforces 725B Food on the Plane

B. Food on the Plane time limit per test:2 seconds memory limit per test:256 meg...

37380
来自专栏张善友的专栏

如何结合IbatisNet的LIST遍历实现模糊查询

我仿照Java的Spring+Ibatis+Struct用Castle+IBatisNet+Asp.net的开发框架的DAO的基类:BaseSqlMapDao内...

25390
来自专栏函数式编程语言及工具

SDP(6):分布式数据库运算环境- Cassandra-Engine

    现代信息系统应该是避不开大数据处理的。作为一个通用的系统集成工具也必须具备大数据存储和读取能力。cassandra是一种分布式的数据库,具备了分布式数据...

35140
来自专栏码匠的流水账

聊聊flink的RichParallelSourceFunction

flink-streaming-java_2.11-1.6.2-sources.jar!/org/apache/flink/streaming/api/func...

34310
来自专栏积累沉淀

研究MapReduce源码之实现自定义LineRecordReader完成多行读取文件内容

TextInputFormat是Hadoop默认的数据输入格式,但是它只能一行一行的读记录,如果要读取多行怎么办? 很简单 自己写一个输入格式,然后写一个对...

23090
来自专栏Java成长之路

Java中的时间和日期处理

本文主要讲解Java 8的时间处理方式和Java8之前版本的时间处理方式的区别。笔者将Java8之前的jdk版本统称为旧版本。

35540
来自专栏码匠的流水账

聊聊jump consistent hash

jump consistent hash是一致性哈希的一种实现,论文见A Fast, Minimal Memory, Consistent Hash Algor...

32320

扫码关注云+社区

领取腾讯云代金券