JDK8中新日期时间API
# 背景
新日期时间API出现的背景:
如果我们可以跟别人说:“我们在1502643933071见面,别晚了!”那么就再简单不过了。但是我们希望时间与昼夜和四季有关,于是事情就变复杂了。JDK 1.0中包含了一个java.util.Date类,但是它的大多数方法已经在JDK 1.1引入Calendar类之后被弃用了。而Calendar
并不比Date
好多少。它们面临的问题是:
- 可变性:像日期和时间这样的类应该是不可变的。
- 偏移性:
Date
中的年份是从1900开始的,而月份都从0开始。 - 格式化:格式化只对
Date
有用,Calendar
则不行。 - 此外,它们也不是线程安全的;不能处理闰秒等。
- 闰秒,是指为保持协调世界时接近于世界时时刻,由国际计量局统一规定在年底或年中(也可能在季末)对协调世界时增加或减少1秒的调整。
总结:对日期和时间的操作一直是Java程序员最痛苦的地方之一。
# 新时间日期API
第三次引入的API是成功的,并且Java 8中引入的java.time API 已经纠正了过去的缺陷,将来很长一段时间内它都会为我们服务。
Java 8 吸收了Joda-Time
的精华,以一个新的开始为Java 创建优秀的API。**新的java.time
中包含了所有关于本地日期(LocalDate
)、本地时间(LocalTime
)、本地日期时间(LocalDateTime
)、时区(ZonedDateTime
)和持续时间(Duration
)的类。**历史悠久的Date 类新增了toInstant()
方法,用于把Date 转换成新的表示形式。这些新增的本地化时间日期API 大大简化了日期时间和本地化的管理。
java.time
–包含值对象的基础包java.time.chrono
–提供对不同的日历系统的访问java.time.format
–格式化和解析时间和日期java.time.temporal
–包括底层框架和扩展特性java.time.zone
–包含时区支持的类
说明:大多数开发者只会用到基础包和format包,也可能会用到temporal包。因此,尽管有68个新的公开类型,大多数开发者,大概将只会用到其中的三分之一。
# LocalXXX
LocalDate
、LocalTime
、LocalDateTime
类是其中较重要的几个类,它们的实例是不可变的对象,分别表示使用ISO-8601日历系统的日期、时间、日期和时间。它们提供了简单的本地日期或时间,并不包含当前的时间信息,也不包含与时区相关的信息。
LocalDate
代表IOS格式(yyyy-MM-dd)的日期,可以存储生日、纪念日等日期。LocalTime
表示一个时间,而不是日期。LocalDateTime
是用来表示日期和时间的,这是一个最常用的类之一。
注:ISO-8601日历系统是国际标准化组织制定的现代公民的日期和时间的表示法,也就是公历。
黄色:实例化方法
橙色:get方法
白色:set操作
灰色:加减操作
# now()
@Test
public void test1() {
LocalDate localDate = LocalDate.now();
LocalTime localTime = LocalTime.now();
LocalDateTime localDateTime = LocalDateTime.now();
System.out.println("localDate = " + localDate);
System.out.println("localTime = " + localTime);
System.out.println("localDateTime = " + localDateTime);
}
2
3
4
5
6
7
8
9
输出结果:
localDate = 2020-12-23
localTime = 22:38:22.287
localDateTime = 2020-12-23T22:38:22.287
2
3
LocalDateTime相较于LocalDate和LocalTime是使用频率最高的。
# of()
@Test
public void test2() {
//of():设置指定年月日时分秒,是没有偏移量的。
LocalDateTime localDateTime = LocalDateTime.of(2020, 10, 6, 13, 23, 43);
System.out.println("localDateTime = " + localDateTime);
}
2
3
4
5
6
输出结果:
localDateTime = 2020-10-06T13:23:43
# getXxx()
@Test
public void test2() {
//of():设置指定年月日时分秒,是没有偏移量的。
LocalDateTime localDateTime = LocalDateTime.of(2020, 10, 6, 13, 23, 43);
System.out.println("localDateTime.getDayOfMonth() = " + localDateTime.getDayOfMonth());
System.out.println("localDateTime.getDayOfWeek() = " + localDateTime.getDayOfWeek());
System.out.println("localDateTime.getMonth() = " + localDateTime.getMonth());
System.out.println("localDateTime.getMonthValue() = " + localDateTime.getMonthValue());
System.out.println("localDateTime.getMinute() = " + localDateTime.getMinute());
}
2
3
4
5
6
7
8
9
10
输出结果:
localDateTime = 2020-10-06T13:23:43
localDateTime.getDayOfMonth() = 6
localDateTime.getDayOfWeek() = TUESDAY
localDateTime.getMonth() = OCTOBER
localDateTime.getMonthValue() = 10
localDateTime.getMinute() = 23
2
3
4
5
6
# withXxx()
LocalXXX都是不可变对象,修改了时间,原来的时间也不会发生改变。
withXxx()都是直接设置时间。
@Test
public void test3() {
LocalDateTime localDateTime = LocalDateTime.of(2020, 10, 6, 13, 23, 43);
LocalDateTime localDateTime1 = localDateTime.withDayOfMonth(22);
LocalDateTime localDateTime2 = localDateTime.withHour(4);
System.out.println("localDateTime = " + localDateTime);
System.out.println("localDateTime1 = " + localDateTime1);
System.out.println("localDateTime2 = " + localDateTime2);
}
2
3
4
5
6
7
8
9
10
输出结果:
localDateTime = 2020-10-06T13:23:43
localDateTime1 = 2020-10-22T13:23:43
localDateTime2 = 2020-10-06T04:23:43
2
3
# plusXxx()
向当前对象添加几天、几周、几个月、几年、几小时。
@Test
public void test4() {
LocalDateTime localDateTime = LocalDateTime.of(2020, 10, 6, 13, 23, 43);
LocalDateTime localDateTime1 = localDateTime.plusMonths(3);
System.out.println("localDateTime = " + localDateTime);
System.out.println("localDateTime1 = " + localDateTime1);
}
2
3
4
5
6
7
输出结果:
localDateTime = 2020-10-06T13:23:43
localDateTime1 = 2021-01-06T13:23:43
2
# minusXxx()
从当前对象减去几月、几周、几天、几年、几小时
@Test
public void test5() {
LocalDateTime localDateTime = LocalDateTime.of(2020, 10, 6, 13, 23, 43);
LocalDateTime localDateTime1 = localDateTime.minusDays(6);
System.out.println("localDateTime = " + localDateTime);
System.out.println("localDateTime1 = " + localDateTime1);
}
2
3
4
5
6
7
输出结果:
localDateTime = 2020-10-06T13:23:43
localDateTime1 = 2020-09-30T13:23:43
2
# 瞬时:Instant
Instant
:时间线上的一个瞬时点。这可能被用来记录应用程序中的事件时间戳。
在处理时间和日期的时候,我们通常会想到年,月,日,时,分,秒。然而,这只是时间的一个模型,是面向人类的。第二种通用模型是面向机器的,或者说是连续的。在此模型中,时间线中的一个点表示为一个很大的数,这有利于计算机处理。在UNIX中,这个数从1970年开始,以秒为的单位;同样的,在Java中,也是从1970年开始,但以毫秒为单位。
**java.time
包通过值类型Instant
提供机器视图,不提供处理人类意义上的时间单位。**Instant表示时间线上的一点,而不需要任何上下文信息,例如,时区。概念上讲,**它只是简单的表示自1970年1月1日0时0分0秒(UTC)开始的秒数。**因为java.time包是基于纳秒计算的,所以Instant
的精度可以达到纳秒级。
(1 ns = 10-9s) 1秒= 1000毫秒=10^6微秒=10^9纳秒
时间戳是指格林威治时间1970年01月01日00时00分00秒(北京时间1970年01月01日08时00分00秒)起至现在的总秒数。
@Test
public void test1() {
// 获取UTC时间
Instant instant = Instant.now();
System.out.println("instant = " + instant);
//偏移8个小时
OffsetDateTime offsetDateTime = instant.atOffset(ZoneOffset.ofHours(8));
System.out.println("offsetDateTime = " + offsetDateTime);
//获取毫秒数
long milli = instant.toEpochMilli();
System.out.println("milli = " + milli);
//通过毫秒数创建Instant对象
Instant instant1 = Instant.ofEpochMilli(milli);
System.out.println("instant1 = " + instant1);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# DateTimeFormatter类
java.time.format.DateTimeFormatter
类用来格式化与解析日期或时间。
该类提供了三种格式化方法:
- 1、预定义的标准格式。
- 如:
ISO_LOCAL_DATE_TIME
;ISO_LOCAL_DATE
;ISO_LOCAL_TIME
- 如:
- 2、本地化相关的格式。
- 如:
ofLocalizedDateTime(FormatStyle.LONG)
FormatStyle
格式有:FULL
,LONG
,MEDIUM
,SHORT
- 如:
- 3、自定义的格式。
- 如:
ofPattern(“yyyy-MM-dd hh:mm:ss”)
- 如:
常用方法:
方式一:预定义的标准格式
@Test
public void test2() {
//方式一:预定义的标准格式
DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
//格式化:日期->字符串
LocalDateTime now = LocalDateTime.now();
String str = formatter.format(now);
System.out.println("now = " + now);
System.out.println("str = " + str);
//解析:字符串->日期
TemporalAccessor parse = formatter.parse(str);
System.out.println("parse = " + parse);
}
2
3
4
5
6
7
8
9
10
11
12
13
方式二:本地化相关的格式
@Test
public void test3() {
//方式二:本地化相关的格式
// DateTimeFormatter formatter1 = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.FULL);
DateTimeFormatter formatter2 = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG);
DateTimeFormatter formatter3 = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM);
DateTimeFormatter formatter4 = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT);
//定义一个时间
LocalDateTime now = LocalDateTime.now();
//格式化
// String fullStyle = formatter1.format(now);
String longStyle = formatter2.format(now);
String mediumStyle = formatter3.format(now);
String shortStyle = formatter4.format(now);
//输出
// System.out.println("fullStyle = " + fullStyle);
System.out.println("longStyle = " + longStyle);
System.out.println("mediumStyle = " + mediumStyle);
System.out.println("shortStyle = " + shortStyle);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
输出结果:
longStyle = 2020年12月23日 下午11时16分48秒
mediumStyle = 2020-12-23 23:16:48
shortStyle = 20-12-23 下午11:16
2
3
方式三:自定义的格式
一般开发的时候我们都是选择自定义格式。
@Test
public void test4() {
//方式三:自定义格式
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss");
String str = formatter.format(LocalDateTime.now());
System.out.println("str = " + str);
}
2
3
4
5
6
7
解析
@Test
public void test4() {
//方式三:自定义格式
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss");
String str = formatter.format(LocalDateTime.now());
System.out.println("str = " + str);
TemporalAccessor parse = formatter.parse(str);
System.out.println("parse = " + parse);
}
2
3
4
5
6
7
8
9
str = 2020-12-23 11:19:29
parse = {MicroOfSecond=0, NanoOfSecond=0, SecondOfMinute=29, HourOfAmPm=11, MilliOfSecond=0, MinuteOfHour=19},ISO resolved to 2020-12-23
2
# 其它API
ZoneId
:该类中包含了所有的时区信息,一个时区的ID,如Europe/ParisZonedDateTime
:一个在ISO-8601日历系统时区的日期时间,如2007-12-03T10:15:30+01:00Europe/Paris。- 其中每个时区都对应着ID,地区ID都为“{区域}/{城市}”的格式,例如:Asia/Shanghai等Clock:使用时区提供对当前即时、日期和时间的访问的时钟。
- 持续时间:
Duration
,用于计算两个“时间”间隔 - 日期间隔:
Period
,用于计算两个“日期”间隔 TemporalAdjuster
: 时间校正器。有时我们可能需要获取例如:将日期调整到“下一个工作日”等操作。TemporalAdjusters
: 该类通过静态方法(firstDayOfXxx()/lastDayOfXxx()/nextXxx())提供了大量的常用TemporalAdjuster 的实现。