Java8 时间处理

Table of Contents

  1. 前言
  2. 时间单位和时区
  3. 时间点
  4. 时间段
  5. 时间的解析和格式化
  6. 时区时间
  7. 兼容旧接口
  8. 结语

前言

时间处理是一个经常会用到但又不那么好用的功能,其中的主要问题在于对人友好的时间格式的处理上。

在这一点上,Java8 提供了方便我们的使用的新的日期和时间接口。

……

当然了,Java8 出来都这么久了,这接口也不算新了 @[email protected]

时间单位和时区

时间是我们每天都在接触的东西,但我并不是很清楚和它的相关的一些概念,借着这次机会,去了解了时间处理中常用的两个概念:时间单位和时区。

首先是时间单位,通过 维基百科 可以发现时间单位有很多,在 Java 中是通过枚举 ChronoUnit 来表示时间单位的,这里列出其中常用的一部分:

时间单位 大小 java.time.temporal.ChronoUnit
纳秒 10-9 s ChronoUnit.NANOS
毫秒 10-3 s ChronoUnit.MILLIS
1 s ChronoUnit.SECONDS
60 s ChronoUnit.MINUTES
3600 s ChronoUnit.HOURS
24 时 ChronoUnit.DAYS
7 日 ChronoUnit.WEEKS
28-31 日 ChronoUnit.MONTHS
12 月 ChronoUnit.YEARS

然后是时区这个有些复杂的概念,时区的理解需要区分 本地时间UTC 偏移量.

比如说时间 2019-04-19T14:31:09.764+08:00[Asia/Shanghai], 这个时间表示 Asia/Shanghai 时区的 本地时间2019-04-19T14:31:09.764, 而它的 UTC 偏移量+08:00, 即:时区 Asia/Shanghai 的的本地时间比世界标准时间(本初子午线处的本地时间)快 8 个小时。

在计算两个时区之间的时间差时,不能直接用本地时间进行计算,而应该综合本地时间和 UTC 偏移量。

最直接的方式便是将两个时区的时间都转换为 UTC 世界标准时间然后在进行计算。

时间点

对时间的处理可以粗略的划分为三个部分:时间点、时间段和时间的解析与格式化。

在 Java8 中表示时间点的对象都实现了接口 java.time.temporal,其中,常用的时间点对象有:Instant、LocalDate、LocalTime 和 LocalDateTime。

这几个时间点对象中比较特殊的是 Instant 对象,这个对象表示的时间是世界标准时间,而不是本地时间。

尝试执行下面这一行代码你就会发现,它的输出结果和你电脑上显示的时间是不一样的,如果是在国内,那么它的结果会比你电脑上的时间慢 8 个小时:

System.out.println(Instant.now());

这些时间点对象都提供了可以根据当前时间创建相应时间点对象的静态工厂方法 now, 除了 Instant 以外也提供了静态工厂方法 of 允许你指定参数创建时间点对象:

LocalDate date = LocalDate.of(2019, 4, 19);                  // 2019-04-15
LocalTime time = LocalTime.of(15, 0, 0);                     // 15:00:00
LocalDateTime dt = LocalDateTime.of(2019, 4, 19, 15, 0, 0);  // 2019-04-15 15:00:00

和旧的接口不一样的一点是,这些对象都是 不可变 对象,这意味着修改这些对象的属性时会返回创建的新对象。

修改这些对象的方法有很多,通用的便是在 Temporal 接口中定义的一些方法:

minus(long amountToSubtract, TemporalUnit unit);  // - amountToSubtract * unit
minus(TemporalAmount amount);                     // - amount

plus(long amountToAdd, TemporalUnit unit);        // + amountToSubtract * unit
plus(TemporalAmount amount);                      // + amount

with(TemporalAdjuster adjuster);
with(TemporalField field, long newValue);

当然了,这些对象也提供了更多的方便使用的接口,可以很方便的在相应的时间单位上进行修改。

这里比较特殊的是通过 TemporalAdjuster 对时间进行调整,它的伴随类 TemporalAdjusters 提供了一些现成的工厂方法,方便我们使用:

// 将日期调整到该月的最后一天
LocalDate.now().with(TemporalAdjusters.lastDayOfMonth());

时间段

时间段对应的接口是 java.time.temporal,这个接口的实现只有两个:Duration 和 Period。

Duration 可以通过两个 LocalDateTime、LocalTime 和 Instant 对象创建:

Duration.between(time1, time2);

而 Period 对象可以通过两个 LocalDate 对象进行创建:

Period.between(date1, date2);

除了通过两个时间点对象以外,Duration 和 Period 对象也提供了一些静态工厂方法创建实例:

Duration.of(3, ChronoUnit.MILLIS);  // 3 Millis
Period.of(0, 0, 1);                 // 1 day

Duration 和 Period 对象都提供了相应的 get 方法用于获取它们支持的时间单位的长度(好像是病句 QAQ):

Duration.ofDays(1).getSeconds();  // 86400
Period.of(1, 2, 3).getDays();     // 3

时间的解析和格式化

时间的解析和格式化相关的对象是 DateTimeFormatter, 这个类提供了很多默认的格式器,也可以自己创建格式器。

时间点对象都可以通过静态方法 parse 解析字符串创建实例,除了 Instant 对象以外还支持提供一个 DateTimeFormatter 参数解析特定格式的时间字符串:

Instant.parse('2007-12-03T10:15:30.00Z')
LocalDateTime.parse('2017-12-3T09:32:00', DateTimeFormatter.ISO_LOCAL_DATE_TIME)

虽然 DateTimeFormatter 提供了很多的默认格式器,但是这些格式器有时并不能满足我们的需求,这时可以通过自定义格式器完成相关的时间解析工作:

LocalDateTime.parse('17-12-03 09:32:00', DateTimeFormatter.ofPattern("yy-MM-dd HH:mm:ss"))

下面是常用的日期/时间格式的格式化符号:

时间与或目的 示例
YEAR yy: 69, yyyy: 1969
MONTH M: 7, MM: 07, MMM: Jul, MMMM: July, MMMMM: J
DAY d: 6, dd: 06
WEEK e: 3, E: Wed, EEE: Wednesday, EEEE: W
HOUR H: 9, HH: 09
MINUTE mm: 02
SECOND ss: 00

时间字符串反过来便是时间的格式化了,我们可以通过格式器来格式化时间:

DateTimeFormatter.ofPattern("yy-MM-dd HH:mm:ss").format(LocalDateTime.now());  // 19-04-19 20:53:49
DateTimeFormatter.BASIC_ISO_DATE.format(LocalDateTime.now());                  // 20190419

时区时间

时区时间同样也是时间点对象,实现了 Temporal 接口,相较于 LocalDateTime, 时区时间多了 时区信息:

ZonedDateTime: 2019-04-20T10:14:44.396+08:00[Asia/Shanghai]
LocalDateTime: 2019-04-20T10:14:44.396
LocalDate:     2019-04-20
LocalTime:     14:44.396

时区信息可以通过 ZoneId 标识,LocalDateTime 对象可以通过 ZoneId 对象添加时区信息(不会修改本地时间的值):

LocalDateTime.now().atZone(ZoneId.of('Europe/London'));  // 2019-04-20T10:19:30.461+01:00[Europe/London]

如果不想直接用时区 ID,那么可以选择使用 UTC 时间偏差:

LocalDateTime.now().atOffset(ZoneOffset.of("+01:00"));  // 2019-04-20T10:25:14.496+01:00

而且使用 ZoneOffset 可以转换 LocalDateTime 和 Instant:

LocalDateTime.now().toInstant(ZoneOffset.of("+01:00"));           // 2019-04-20T09:34:59.110Z
LocalDateTime.ofInstant(Instant.now(), ZoneOffset.of("+01:00"));  // 2019-04-20T03:35:51.980

兼容旧接口

Java8 提供了一些方法允许新的日期时间后旧的日期时间进行转换,下面列举出了一部分:

转换到旧的对象 转换到新的对象
Instant - java.util.Date Date.from(instant) date.toInstant()
LocalDate - java.sql.Date Date.valueOf(localDate) date.toLocalDate()
LocalTime - java.sql.Time Time.valueOf(localTime) date.toLocalTime()
ZoneId - java.util.TimeZone TimeZone.getTimeZone(id) timeZone.toZoneId()

可以说,Java 8 不仅提供了新的接口,还提供了能够很方便的兼容旧的接口的方式,真的很棒!

结语

这篇博客的内容不怎么详细,基本上只是简单的提了一下各个接口可以做什么,更多的使用还是需要翻文档。

但是不得不说,Java8 的日期和时间接口提供了很多方便我们使用的功能,而且接口的设计也很 Beautiful!

Nice!!!

……

这篇博客的编写主要参考了两本书:《Java8 实战》和《Java 核心技术卷卷二》。

然后就不得不吐槽《Java8 实战》这本书了,关于时间处理的这一章节勘误一大堆,内容也不是很清楚。

而《Java 核心技术卷卷二》就写的很清楚,不知道是不是翻译的锅……

原文地址:https://www.cnblogs.com/rgbit/p/10740317.html

时间: 2024-10-02 14:05:10

Java8 时间处理的相关文章

java8 时间使用

为什么需要新的时间API 文章来源:https://www.cnblogs.com/guozp/p/10342775.html 在Java 8之前的日期/时间API之前,现有的与日期和时间相关的类存在诸多问题,其中主要有: Java的日期/时间类的定义并不一致,在java.util和java.sql的包中都有日期类,此外用于格式化和解析的类在java.text包中定义 java.util.Date同时包含日期和时间,而java.sql.Date仅包含日期,将其纳入java.sql包并不合理.另外

Java8 时间日期类操作

Java8 时间日期类操作 Java8的时间类有两个重要的特性 线程安全 不可变类,返回的都是新的对象 显然,该特性解决了原来java.util.Date类与SimpleDateFormat线程不安全的问题.同时Java8的时间类提供了诸多内置方法,方便了对时间进行相应的操作. 上图为Java8时间类的覆盖范围 相关的类有 LocalDate LocalTime LocalDateTime ZoneId ZonedDateTime Instant Instant类 Instant类用来表示格林威

Java8 时间处理类的使用实践(LocalDate...)

有了它,谁还在用Date?Calendar? 其实也不能这么绝对,毕竟还没到那个程度上.Java8 新增了处理时间的一组类(LocalDate.LocalDateTime.LocalTime),刚开始使用时觉得非常费劲,没有Calendar好用,但是真的使用之后觉得还是比较好用的啊.建议大家以后多多使用.废话少说,看代码~ 1.Date与LocalDate的互转 Date转LocalDate: Date date = new Date(); LocalDate localDate = date.

Java8 时间 API

前言 Java8 中最为人津津乐道的新改变恐怕当属函数式 API 的加入.但实际上,Java8 所加入的新功能远不止这个. 本文将基于<Java SE8 for the Really Impatient>的第 5 章,归纳一下 Java8 加入的位于java.time包下的日期和时间 API. 时间点与时间间隔 在我们常说的四维空间体系中,时间轴往往作为除长宽高三轴以外的第四轴.时间轴由无穷多个时间点组成,而两个时间点之间的距离组成一个时间间隔.相较于我们常说的日期.时间,时间点本身所携带的信

java8时间使用小结

//LocalDate代表一个IOS格式(yyyy-MM-dd)的日期 获取当前的日期: LocalDate localDate = LocalDate.now();//LocalDate: 表示没有时区的日期, LocalDate是不可变并且线程安全的 System.out.println("localDate: " + localDate);//localDate: 2017-08-24 //LocalDate可以指定特定的日期,调用of或parse方法返回该实例: System.

Java8时间的简单时间

package com.java8.date; import org.junit.Test; import java.text.SimpleDateFormat; import java.time.*; import java.time.format.DateTimeFormatter; import java.time.temporal.*; public class DateTest { @Test public void LocalDateTest() { // of方法获取一个指定日期的

Java8时间处理

Java时间处理 Java8新增的时间处理API 常用时间处理方法的问题 java.util.Date和java.util.Calendar不是线程安全的类 SimpleDateFormat也是非线程安全的类 Calendar获取月份时需要计算,因为月份从0开始 日期/时间类 LocalDate与LocalTime LocalDate类表示一个具体的日期,但不包含具体时间,也不包含时区信息,LocalTime表示一个具体的时间 LocalDate localDate = LocalDate.of

java8 时间矫正器

private static void test5(){ //当前日期 LocalDateTime ldt=LocalDateTime.now(); System.out.println(ldt);//2017-11-04T13:46:39.537 //把日期调整为这月的10号,使用with来设置日 LocalDateTime ldt2=ldt.withDayOfMonth(10);//2017-11-04T13:46:39.537 System.out.println(ldt2); //下一个

java8时间搓计算代码运行时间

Instant start = Instant.now(); // XXXXXXXX(你的代码) Instant end = Instant.now(); //时间搓对象 Duration timeElapsed = Duration.between(start, end); //不同格式展示,下面是分钟和秒的样子,还有小时天这些 long l = timeElapsed.toMinutes(); long ls = timeElapsed.toMillis(); System.out.prin