Java 8新增的日期、时间格式器
在计算机中,应该如何表示日期和时间呢?
我们经常看到的日期和时间表示方式如下:
- 2019-11-20 0:15:00 GMT+00:00
- 2019年11月20日8:15:00
- 11/19/2019 19:15:00 America/New_York
如果直接以字符串的形式存储,那么不同的格式,不同的语言会让表示方式非常繁琐。
它们实际上是数据的展示格式,分别按英国时区、中国时区、纽约时区对同一个时刻进行展示。而这个“同一个时刻”在计算机中存储的本质上只是一个整数,我们称它为Epoch Time
。
Epoch Time(新纪元时间):
是计算从1970年1月1日零点(格林威治时区/GMT+00:00)到现在所经历的秒数,例如:
1574208900
表示从从1970年1月1日零点GMT时区到该时刻一共经历了1574208900秒,换算成伦敦、北京和纽约时间分别是:
1574208900 = 北京时间2019-11-20 8:15:00 = 伦敦时间2019-11-20 0:15:00 = 纽约时间2019-11-19 19:15:00
因此,在计算机中,只需要存储一个整数1574208900
表示某一时刻。当需要显示为某一地区的当地时间时,我们就把它格式化为一个字符串:
String displayDateTime(int n, String timezone) { ... }
Epoch Time
又称为时间戳,在不同的编程语言中,会有几种存储方式:
- 以秒为单位的整数:1574208900,缺点是精度只能到秒;
- 以毫秒为单位的整数:1574208900123,最后3位表示毫秒数;
- 以秒为单位的浮点数:1574208900.123,小数点后面表示零点几秒。
它们之间转换非常简单。而在Java程序中,时间戳通常是用long
表示的毫秒数,即:
long t = 1574208900123L;
转换成北京时间就是2019-11-20T8:15:00.123
。要获取当前时间戳,可以使用System.currentTimeMillis()
,这是Java程序获取时间戳最常用的方法。
java8出的新的时间日期API都是线程安全的,并且性能更好,代码更简洁!
Java 8引入了新的日期和时间API,它们是不变类,默认按ISO 8601标准格式化和解析;
使用LocalDateTime
可以非常方便地对日期和时间进行加减,或者调整日期和时间,它总是返回新对象;
使用isBefore()
和isAfter()
可以判断日期和时间的先后;
使用Duration
和Period
可以表示两个日期和时间的“区间间隔”。
新时间日期API常用、重要对象介绍
- ZoneId: 时区ID,用来确定Instant和LocalDateTime互相转换的规则
- Instant: 用来表示时间线上的一个点(瞬时)
- LocalDate: 表示没有时区的日期, LocalDate是不可变并且线程安全的
- LocalTime: 表示没有时区的时间, LocalTime是不可变并且线程安全的
- LocalDateTime: 表示没有时区的日期时间, LocalDateTime是不可变并且线程安全的
- Clock: 用于访问当前时刻、日期、时间,用到时区
- Duration: 用秒和纳秒表示时间的数量(长短),用于计算两个日期的“时间”间隔
- Period: 用于计算两个“日期”间隔
其中,LocalDate、LocalTime、LocalDateTime是新API里的基础对象,绝大多数操作都是围绕这几个对象来进行的,有必要搞清楚:
LocalDate : 只含年月日的日期对象
LocalTime :只含时分秒的时间对象
LocalDateTime : 同时含有年月日时分秒的日期对象
本文将以实例讲解日常开发中常用到的时间日期操作,如:
获取当前日期、时间
指定时间日期创建对应的对象
计算两个时间点的间隔
判断两个时间的前后
时间日期的格式化
获取时间戳
时间、日期相加减
获取给定时间点的年份、月份、周、星期等
JDBC
最新JDBC映射将把数据库的日期类型和Java 8的新类型关联起来:
SQL -> Java
--------------------------
date -> LocalDate
time -> LocalTime
timestamp -> LocalDateTime
再也不会出现映射到java.util.Date
其中日期或时间某些部分为0
的情况了。
一 获取DateTimeFormatter对象的三种方式
- 直接使用静态常量创建DateTimeFormatter格式器
- 使用代码不同风格的枚举值来创建DateTimeFormatter格式器
- 根据模式字符串来创建DateTimeFormatter格式器
二 DateTimeFormatter完成格式化
1 代码示例
package com.sf.code.concurrent; import java.time.*; import java.time.format.*; public class NewFormatterTest { public static void main(String[] args) { DateTimeFormatter[] formatters = new DateTimeFormatter[] { // 直接使用常量创建DateTimeFormatter格式器 DateTimeFormatter.ISO_LOCAL_DATE, DateTimeFormatter.ISO_LOCAL_TIME, DateTimeFormatter.ISO_LOCAL_DATE_TIME, // 使用本地化的不同风格来创建DateTimeFormatter格式器 DateTimeFormatter.ofLocalizedDateTime(FormatStyle.FULL, FormatStyle.MEDIUM), DateTimeFormatter.ofLocalizedTime(FormatStyle.LONG), // 根据模式字符串来创建DateTimeFormatter格式器 DateTimeFormatter.ofPattern("Gyyyy%%MMM%%dd HH:mm:ss"), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss") }; LocalDateTime date = LocalDateTime.now(); // 依次使用不同的格式器对LocalDateTime进行格式化 for (int i = 0; i < formatters.length; i++) { // 下面两行代码的作用相同 System.out.println(date.format(formatters[i])); // System.out.println(formatters[i].format(date)); } } }
2017-03-30
16:14:41.748
2017-03-30T16:14:41.748
2017年3月30日 星期四 16:14:41
下午04时14分41秒
公元2017%%三月%%30 16:14:41
2017-03-30 16:14:41
3 代码说明
上面代码使用3种方式创建了6个DateTimeFormatter对象,然后程序中使用不同方式来格式化日期。
三 DateTimeFormatter解析字符串
1 代码示例
package com.sf.code.concurrent; import java.time.*; import java.time.format.*; public class NewFormatterParse { public static void main(String[] args) { // 定义一个任意格式的日期时间字符串 String str1 = "2014==04==12 01时06分09秒"; // 根据需要解析的日期、时间字符串定义解析所用的格式器 DateTimeFormatter fomatter1 = DateTimeFormatter.ofPattern("yyyy==MM==dd HH时mm分ss秒"); // 执行解析 LocalDateTime dt1 = LocalDateTime.parse(str1, fomatter1); System.out.println(dt1); // 输出 2014-04-12T01:06:09 // ---下面代码再次解析另一个字符串--- String str2 = "2014$$$四月$$$13 20小时"; DateTimeFormatter fomatter2 = DateTimeFormatter.ofPattern("yyy$$$MMM$$$dd HH小时"); LocalDateTime dt2 = LocalDateTime.parse(str2, fomatter2); System.out.println(dt2); // 输出 2014-04-13T20:00 } }
2 运行结果
2014-04-12T01:06:09
2014-04-13T20:00
3 代码说明
上面代码定义了两个不同格式日期、时间字符串。为了解析他们,代码分别使用对应的格式字符串创建了DateTimeFormatter对象,这样DateTimeFormatter即可按照格式化字符串将日期、时间字符串解析成LocalDateTime对象。