Java 8 的时间日期 API
上一篇文章『Java 的时间日期 API』中,我们学习了由 Date、Calendar,DateFormat 等组成的「传统时间日期 API」,但是传统的处理接口设计并不是很友好,不易使用。终于,Java 8 借鉴第三方优秀开源库 Joda-time,重新设计了一套 API。
那么本篇文章就来简单学习一下新式的时间日期处理接口。
表示时刻的 Instant
Instant 和 Date 一样,表示一个时间戳,用于描述一个时刻,只不过它较 Date 而言,可以描述更加精确的时刻。并且 Instant 是时区无关的。
Date 最多可以表示毫秒级别的时刻,而 Instant 可以表示纳秒级别的时刻。例如:
- public static Instant now():根据系统当前时间创建一个 Instant 实例,表示当前时刻
- public static Instant ofEpochSecond(long epochSecond):通过传入一个标准时间的偏移值来构建一个 Instant 实例
- public static Instant ofEpochMilli(long epochMilli):通过毫秒数值直接构建一个 Instant 实例
看看代码:
public static void main(String[] args){
//创建 Instant 实例
Instant instant = Instant.now();
System.out.println(instant);
Instant instant1 = Instant.ofEpochSecond(20);
System.out.println(instant1);
Instant instant2 = Instant.ofEpochSecond(30,100);
System.out.println(instant2);
Instant instant3 = Instant.ofEpochMilli(1000);
System.out.println(instant3);
}
输出结果:
2018-04-23T02:43:10.973Z
1970-01-01T00:00:20Z
1970-01-01T00:00:30.000000100Z
1970-01-01T00:00:01Z
可以看到,Instant 和 Date 不同的是,它是时区无关的,始终是格林零时区相关的,也即是输出的结果始终格林零时区时间。
处理日期的 LocalDate
不同于 Calendar 既能处理日期又能处理时间,java.time 的新式 API 分离开日期和时间,用单独的类进行处理。LocalDate 专注于处理日期相关信息。
LocalDate 依然是一个不可变类,它关注时间中年月日部分,我们可以通过以下的方法构建和初始化一个 LocalDate 实例:
- public static LocalDate now():截断当前系统时间的年月日信息并初始化一个实例对象
- public static LocalDate of(int year, int month, int dayOfMonth):显式指定年月日信息
- public static LocalDate ofYearDay(int year, int dayOfYear):根据 dayOfYear 可以推出 month 和 dayOfMonth
- public static LocalDate ofEpochDay(long epochDay):相对于格林零时区时间的日偏移量
看看代码:
public static void main(String[] args){
//构建 LocalDate 实例
LocalDate localDate = LocalDate.now();
System.out.println(localDate);
LocalDate localDate1 = LocalDate.of(2017,7,22);
System.out.println(localDate1);
LocalDate localDate2 = LocalDate.ofYearDay(2018,100);
System.out.println(localDate2);
LocalDate localDate3 = LocalDate.ofEpochDay(10);
System.out.println(localDate3);
}
输出结果:
2018-04-23
2017-07-22
2018-04-10
1970-01-11
需要注意一点,LocalDate 会根据系统中当前时刻和默认时区计算出年月日的信息。
除此之外,LocalDate 中还有大量关于日期的常用方法:
- public int getYear():获取年份信息
- public int getMonthValue():获取月份信息
- public int getDayOfMonth():获取当前日是这个月的第几天
- public int getDayOfYear():获取当前日是这一年的第几天
- public boolean isLeapYear():是否是闰年
- public int lengthOfYear():获取这一年有多少天
- public DayOfWeek getDayOfWeek():返回星期信息
- 等等
这些方法都见名知意,此处不再赘述。
处理时间的 LocalTime
类似于 LocalDate,LocalTime 专注于时间的处理,它提供小时,分钟,秒,毫微秒的各种处理,我们依然可以通过类似的方式创建一个 LocalTime 实例。
- public static LocalTime now():根据系统当前时刻获取其中的时间部分内容
- public static LocalTime of(int hour, int minute):显式传入小时和分钟来构建一个实例对象
- public static LocalTime of(int hour, int minute, int second):通过传入时分秒构造实例
- public static LocalTime of(int hour, int minute, int second, int nanoOfSecond):传入时分秒和毫微秒构建一个实例
- public static LocalTime ofSecondOfDay(long secondOfDay):传入一个长整型数值代表当前日已经过去的秒数
- public static LocalTime ofNanoOfDay(long nanoOfDay):传入一个长整型代表当前日已经过去的毫微秒数
同样的,LocalTime 默认使用系统默认时区处理时间,看代码:
public static void main(String[] a){
LocalTime localTime = LocalTime.now();
System.out.println(localTime);
LocalTime localTime1 = LocalTime.of(23,59);
System.out.println(localTime1);
LocalTime localTime2 = LocalTime.ofSecondOfDay(10);
System.out.println(localTime2);
}
输出结果:
13:59:03.723
23:59
00:00:10
当然,LocalTime 中也同样封装了很多好用的工具方法,例如:
- public int getHour()
- public int getMinute()
- public int getSecond()
- public int getNano()
- public LocalTime withHour(int hour):修改当前 LocalTime 实例中的 hour 属性并重新返回一个新的实例
- public LocalTime withMinute(int minute):类似
- public LocalTime withSecond(int second)
- 等等
LocalDateTime 类则是集成了 LocalDate 和 LocalTime,它既能表示日期,又能表述时间信息,方法都类似,只是有一部分涉及时区的转换内容,我们待会说。
时区相关的日期时间处理 ZonedDateTime
无论是我们的 LocalDate,或是 LocalTime,甚至是 LocalDateTime,它们基本是时区无关的,内部并没有存储时区属性,而基本用的系统默认时区。往往有些场景之下,缺乏一定的灵活性。
ZonedDateTime 可以被理解为 LocalDateTime 的外层封装,它的内部存储了一个 LocalDateTime 的实例,专门用于普通的日期时间处理。此外,它还定义了 ZoneId 和 ZoneOffset 来描述时区的概念。
ZonedDateTime 和 LocalDateTime 的一个很大的不同点在于,后者内部并没有存储时区,所以对于系统的依赖性很强,往往换一个时区可能就会导致程序中的日期时间不一致。
而后者则可以通过传入时区的名称,使用 ZoneId 进行匹配存储,也可以通过传入与零时区的偏移量,使用 ZoneOffset 存储时区信息。
所以,构建一个 ZonedDateTime 实例有以下几种方式:
- public static ZonedDateTime now():系统将以默认时区计算并存储日期时间信息
- public static ZonedDateTime now(ZoneId zone):指定时区
- public static ZonedDateTime of(LocalDate date, LocalTime time, ZoneId zone):指定日期时间和时区
- public static ZonedDateTime of(LocalDateTime localDateTime, ZoneId zone)
- public static ZonedDateTime ofInstant(Instant instant, ZoneId zone):通过时刻和时区构建实例对象
- 等等
看代码:
public static void main(String[] a){
ZonedDateTime zonedDateTime = ZonedDateTime.now();
System.out.println(zonedDateTime);
LocalDateTime localDateTime = LocalDateTime.now();
ZoneId zoneId = ZoneId.of("America/Los_Angeles");
ZonedDateTime zonedDateTime1 = ZonedDateTime.of(localDateTime,zoneId);
System.out.println(zonedDateTime1);
Instant instant = Instant.now();
ZoneId zoneId1 = ZoneId.of("GMT");
ZonedDateTime zonedDateTime2 = ZonedDateTime.ofInstant(instant,zoneId1);
System.out.println(zonedDateTime2);
}
输出结果:
2018-04-23T16:10:29.510+08:00[Asia/Shanghai]
2018-04-23T16:10:29.511-07:00[America/Los_Angeles]
2018-04-23T08:10:29.532Z[GMT]
简单解释一下,首先第一个输出应该没什么问题,系统保存当前系统日期和时间以及默认的时区。
第二个小例子,LocalDateTime 实例保存了时区无关的当前日期时间信息,也就是这里的年月日时分秒,接着构建一个 ZonedDateTime 实例并传入一个美国时区(西七区)。你会发现输出的日期时间为西七区的 16 点 29 分。
像这种关联了时区的日期时间就很能够解决那种,换时区导致程序中时间错乱的问题。因为我关联了时区,无论你程序换到什么地方运行了,日期+时区 本就已经唯一确定了某个时刻,就相当于我在存储某个时刻的时候,我说明了这是某某时区的某某时间,即便你换了一个地区,你也不至于把这个时间按自己当前的时区进行解析并直接使用了吧。
第三个小例子就更加的直接明了了,构建 ZonedDateTime 实例的时候,给定一个时刻和一个时区,而这个时刻值就是相对于给定时区的标准时间所经过的毫秒数。
有关 ZonedDateTime 的其他日期时间的处理方法和 LocalDateTime 是一样的,因为 ZonedDateTime 是直接封装了一个 LocalDateTime 实例对象,所以所有相关日期时间的操作都会间接的调用 LocalDateTime 实例的方法,我们不再赘述。
格式化日期时间
Java 8 的新式日期时间 API 中,DateTimeFormatter 作为格式化日期时间的主要类,它与之前的 DateFormat 类最大的不同就在于它是线程安全的,其他的使用上的操作基本类似。我们看看:
public static void main(String[] a){
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss");
LocalDateTime localDateTime = LocalDateTime.now();
System.out.println(formatter.format(localDateTime));
String str = "2008年08月23日 23:59:59";
DateTimeFormatter formatter2 = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss");
LocalDateTime localDateTime2 = LocalDateTime.parse(str,formatter2);
System.out.println(localDateTime2);
}
输出结果:
2018年04月23日 17:27:24
2008-08-23T23:59:59
格式化主要有两种情况,一种是将日期时间格式化成字符串,另一种则是将格式化的字符串装换成日期时间对象。
DateTimeFormatter 提供将 format 方法将一个日期时间对象转换成格式化的字符串,但是反过来的操作却建议使用具体的日期时间类自己的 parse 方法,这样可以省去类型转换的步骤。
时间差
现实项目中,我们也经常会遇到计算两个时间点之间的差值的情况,最粗暴的办法是,全部幻化成毫秒数并进行减法运算,最后在转换回日期时间对象。
但是 java.time 包中提供了两个日期时间之间的差值的计算方法,我们一起看看。
关于时间差的计算,主要涉及到两个类:
- Period:处理两个日期之间的差值
- Duration:处理两个时间之间的差值
例如:
public static void main(String[] args){
LocalDate date = LocalDate.of(2017,7,22);
LocalDate date1 = LocalDate.now();
Period period = Period.between(date,date1);
System.out.println(period.getYears() + "年" +
period.getMonths() + "月" +
period.getDays() + "天");
LocalTime time = LocalTime.of(20,30);
LocalTime time1 = LocalTime.of(23,59);
Duration duration = Duration.between(time,time1);
System.out.println(duration.toMinutes() + "分钟");
}
输出结果:
0年9月1天
209分钟
显然,年月日的日期间差值的计算使用 Period 类足以,而时分秒毫秒的时间的差值计算则需要使用 Duration 类。
最后,关于 java.time 包下的新式日期时间 API,我们简单的学习了下,并没有深入到源码实现层次进行介绍,因为底层涉及大量的系统接口,涉及到大量的抽象类和实现类,有兴趣的朋友可以自行阅读 jdk 的源码深入学习。
文章中的所有代码、图片、文件都云存储在我的 GitHub 上:
(https://github.com/SingleYam/overview_java)
欢迎关注微信公众号:扑在代码上的高尔基,所有文章都将同步在公众号上。
Java 8 的时间日期 API的更多相关文章
- Java 中的时间日期 API
自从 14 年发布 Java 8 以后,我们古老 java.util.Date 终于不再是我们 Java 里操作日期时间的唯一的选择. 其实 Java 里的日期时间的相关 API 一直为世猿诟病,不仅 ...
- Spring Boot和Feign中使用Java 8时间日期API(LocalDate等)的序列化问题【转】
Spring Boot和Feign中使用Java 8时间日期API(LocalDate等)的序列化问题 http://blog.didispace.com/Spring-Boot-And-Feign- ...
- Spring Boot和Feign中使用Java 8时间日期API(LocalDate等)的序列化问题
LocalDate.LocalTime.LocalDateTime是Java 8开始提供的时间日期API,主要用来优化Java 8以前对于时间日期的处理操作.然而,我们在使用Spring Boot或使 ...
- Java 8 新的时间日期 API
1. 概述 1.1 简介 Java 8 引入了一套全新的时间日期API,操作起来更简便.简单介绍下,LocalDate和LocalTime和LocalDateTime的使用: java.util.Da ...
- JAVASE(十二) Java常用类: 包装类、String类、StringBuffer类、时间日期API、其他类
个人博客网:https://wushaopei.github.io/ (你想要这里多有) 1.包装类 1 .1 八个包装类 1. 2 基本数据类型,包装类,String者之间的转换 2. ...
- 深入理解Java常用类-----时间日期
除了String这个类在日常的项目中比较常用之外,有关时间和日期的操作也是经常遇到的,本篇就讲详细介绍下Java API中对时间和日期的支持.其实在Java 8之前时间日期的API并不是很好用,以至于 ...
- Java8新特性(三)——Optional类、接口方法与新时间日期API
一.Optional容器类 这是一个可以为null的容器对象.如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象. 查看结构图可以看到有如下常用方法: of(T)—— ...
- JAVA8学习——新的时间日期API&Java8总结
JAVA8-时间日期API java8之前用过的时间日期类. Date Calendar SimpleDateFormat 有很多致命的问题. 1.没有时区概念 2.计算麻烦,实现困难 3.类是可变的 ...
- Java中的时间日期处理
程序就是输入——>处理——>输出.对数据的处理是程序员需要着重注意的地方,快速.高效的对数据进行处理时我们的追求.其中,时间日期的处理又尤为重要和平凡,此次,我将把Java中的时间日期处理 ...
随机推荐
- JaveScript内置对象(JS知识点归纳八)
1)JS自身提供的方式 用于对数据进行简便的操作,根据方法可以操作的数据类型不同,形成了不同的对象--内置对象 2)数组 a)基本操作方法--对数组进行修改 从数组最后进行操作 1)数组.push ...
- centos7 安装docker
1.首先cent7 基本是在vm上完全安装'. 2.参考官方网站安装 1.https://wiki.centos.org/AdditionalResources/Repositories OS req ...
- 静态链表的C实现(基于数据结构 严蔚敏)
静态链表是利用一维数组实现逻辑上的单链表结构,结点的逻辑上相邻但物理位置上不一定相邻,因为内存分配上是一次性的,故称为静态. 特点: 预先需要一片连续的存储空间: 非随机存取: 无现成的"内 ...
- React Native学习(九)—— 使用Flexbox布局
本文基于React Native 0.52 Demo上传到Git了,有需要可以看看,写了新内容会上传的.Git地址 https://github.com/gingerJY/React-Native-D ...
- ELK学习总结(2-5)elk的版本控制
----------------------------------------------------------------- 1.悲观锁和乐观锁 悲观锁:假定会发生并发冲突,屏蔽一切可能违反数据 ...
- YML(2)yml 语法
YAML 语法 来源:yaml 这个页面提供一个正确的 YAML 语法的基本概述, 它被用来描述一个 playbooks(我们的配置管理语言). 我们使用 YAML 是因为它像 XML 或 JSON ...
- CentOS7从U盘中拷贝文件
1. 要想从U盘中拷贝文件,必须要将U盘挂载到一个目录中,所以必须新建一个目录,一般建在/mnt下.我们执行:mkdir /mnt/usb来新建一个目录. 2. 查看U盘是否已经被识别.执行:df - ...
- python 正则详解
正则表达式概述 正则表达式,又称正规表示式.正规表示法.正规表达式.规则表达式.常规表示法(英语:Regular Expression,在代码中常简写为regex.regexp或RE),是计算机科学的 ...
- 字符串分割方法split()函数
>>> data = '1000,小甲鱼,男'>>> data.split(',')['1000', '小甲鱼', '男'] str.split('以什么为标志进行 ...
- 极速下载百度网盘-吴水成老师的-dubbo课程
极速下载百度网盘-吴水成老师的-dubbo课程,极速下载百度网盘-吴水成老师的-dubbo课程,极速下载百度网盘-吴水成老师的-dubbo课程,极速下载百度网盘-吴水成老师的-dubbo课程 先看主目 ...