Saul's blog Saul's blog
首页
后端
分布式
前端
更多
分类
标签
归档
友情链接
关于
GitHub (opens new window)

Saul.J.Wu

立身之本,不在高低。
首页
后端
分布式
前端
更多
分类
标签
归档
友情链接
关于
GitHub (opens new window)
  • Java入门基础

  • Java核心基础

    • 多线程

    • Java常用类

      • 字符串相关的类
      • JDK8之前日期时间API
      • JDK8中新日期时间API
        • 背景
        • 新时间日期API
        • LocalXXX
          • now()
          • of()
          • getXxx()
          • withXxx()
          • plusXxx()
          • minusXxx()
        • 瞬时:Instant
        • DateTimeFormatter类
        • 其它API
        • 与传统日期处理的转换
      • Java比较器
      • 其他类
      • Java随机数
    • 枚举类与注解

    • Java集合

    • 数据结构与算法

    • 泛型

    • IO流

    • 网络编程

    • 反射

    • 函数式编程

  • 设计模式

  • Web开发

  • SpringBoot

  • 微服务

  • Elasticsearch

  • 运维

  • 后端
  • Java核心基础
  • Java常用类
SaulJWu
2020-12-23

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日历系统是国际标准化组织制定的现代公民的日期和时间的表示法,也就是公历。

image-20201223201403561

黄色:实例化方法

橙色: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);
}
1
2
3
4
5
6
7
8
9

输出结果:

localDate = 2020-12-23
localTime = 22:38:22.287
localDateTime = 2020-12-23T22:38:22.287
1
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);
}
1
2
3
4
5
6

输出结果:

localDateTime = 2020-10-06T13:23:43
1

# 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());
}
1
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
1
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);
}
1
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
1
2
3

# plusXxx()

向当前对象添加几天、几周、几个月、几年、几小时。

image-20201223224926867

@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);
}
1
2
3
4
5
6
7

输出结果:

localDateTime = 2020-10-06T13:23:43
localDateTime1 = 2021-01-06T13:23:43
1
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);
}
1
2
3
4
5
6
7

输出结果:

localDateTime = 2020-10-06T13:23:43
localDateTime1 = 2020-09-30T13:23:43
1
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纳秒
1

image-20201223201858576

时间戳是指格林威治时间1970年01月01日00时00分00秒(北京时间1970年01月01日08时00分00秒)起至现在的总秒数。

image-20201223201940732

@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);
}
1
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”)

常用方法:

image-20201223230245267

方式一:预定义的标准格式

@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);
}
1
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);
}
1
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
1
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);
}
1
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);
}
1
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
1
2

# 其它API

  • ZoneId:该类中包含了所有的时区信息,一个时区的ID,如Europe/Paris
  • ZonedDateTime:一个在ISO-8601日历系统时区的日期时间,如2007-12-03T10:15:30+01:00Europe/Paris。
    • 其中每个时区都对应着ID,地区ID都为“{区域}/{城市}”的格式,例如:Asia/Shanghai等Clock:使用时区提供对当前即时、日期和时间的访问的时钟。
  • 持续时间:Duration,用于计算两个“时间”间隔
  • 日期间隔:Period,用于计算两个“日期”间隔
  • TemporalAdjuster : 时间校正器。有时我们可能需要获取例如:将日期调整到“下一个工作日”等操作。
  • TemporalAdjusters : 该类通过静态方法(firstDayOfXxx()/lastDayOfXxx()/nextXxx())提供了大量的常用TemporalAdjuster 的实现。

# 与传统日期处理的转换

image-20201223204626707

帮我改善此页面 (opens new window)
#LocalDate#LocalTime#LocalDateTime#Instant#DateTimeFormatter
上次更新: 2020/12/24, 03:21:34
JDK8之前日期时间API
Java比较器

← JDK8之前日期时间API Java比较器→

最近更新
01
zabbix学习笔记二
02-28
02
zabbix学习笔记一
02-10
03
Linux访问不了github
12-08
更多文章>
Theme by Vdoing | Copyright © 2020-2022 Saul.J.Wu | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式