编程语言
首页 > 编程语言> > Java基础篇之——第三版时间API

Java基础篇之——第三版时间API

作者:互联网

jdk1.8之后Java终于迎来了全新的时间API,摒弃了以往Date类中的难用,死板的模板,我们可以使用全新的API更加方便地去使用时间:

JDK 1.0 java.util.Date 第一版 时间API

JDK 1.1 Calendar       第二版 时间API

 

缺点:可变性差,偏移性差,年份从1900年开始,月份从0开始,格式化能力差,Calendar就不支持格式化。

在我们使用jdk 1.8的情况下,你会发现 Date 类中有太多太多已被弃用的方法,所以更新新的时间API是非常明智的!

 

这次我们讨论内容有三个部分:

  1. 如何使用新API
  2. 从旧API过渡到新API
  3. 所有方法总结

第一节:新API使用

首先介绍三种时间对象:LocalDate,LocalTime,LocalDateTime。

顾名思义,他们表示:本地日期,本地时间,本地日期+时间。

何为本地?就是当前的世界时钟+当前时区,例如我现在的时区就是上海,也就是UTC + 8 时区。

 

还有另外三种时间对象:OffsetDateTime(携带时区的LocalDateTime),ZonedDateTime(携带时区+地区的 LocalDateTime),Instant(机器时间)。这三种对象比较特殊,我们在之后会好好认识它们。

 

现在,让我们先从简单的练练手:

LocalDate date = LocalDate.now();
// 2021-11-19

LocalTime time = LocalTime.now();
// 21:31:54.533170600

LocalDateTime dateTime = LocalDateTime.now();
// 2022-02-12T10:30:19.831515600

LocalTime是可以精确到纳秒的,还是比较精确的,现在我们已经知道获取当前时间的方法: now(),那么我们还有其他方法可以使用吗?当然有,而且非常丰富!

方法我规划成以下三类:

1.生成时间的方法

2.时间口语化的方法

3.时间计算的方法

1.1 生成时间的方法

不单单是now(),你还可以通过其他方式来定制化时间,请看实例:

 

1).使用of工厂方法通过int值生成时间

LocalDate date = LocalDate.of(2022,1,1);
// 2022-01-01

LocalTime date = LocalTime.of(10,1,1);
// 10:10:01
    
LocalDateTime date = LocalDateTime.of(2022,1,1,10,1,1);
// 2022-01-01T10:10:01
LocalDateTime dateTime = LocalDateTime.of(2022, Month.FEBRUARY, 22,22,22,22);
// 2022-02-22T22:22:22 (通过 Month 枚举类)

//date 和 time 合成 dateTime
LocalDate date = LocalDate.now();
LocalTime time = LocalTime.now();
LocalDateTime dateTime = LocalDateTime.of(date,time);
// 2022-01-01T10:10:01

2).parse方法通过Stings生成时间

//第一种方式使用parse方法,通过字符串创建时间对象
LocalDate parse = LocalDate.parse("2022-01-01");
// 2022-01-01
LocalTime parse = LocalTime.parse("18:10:10");
// 18:10:10
LocalDateTime parse = LocalDateTime.parse("2022-01-01T18:10:10");
// 2022-01-01T18:10:10

//parse方法故名思意是一种格式化字符串输出日期的方式,我们可以传入日期的字符串格式来输出日期

//第二种方式使用parse方法,传入字符串以及自定义日期格式
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
//日期格式,我们自定义了日期格式
LocalDateTime parse = LocalDateTime.parse("2022/01/01 18:10:10",formatter);
//传入自定义日期格式和符合格式的字符串


//第三种方式使用parse方法,传入字符串以及JDK提供的日期格式
LocalDateTime parse = LocalDateTime.parse("2022-01-01T18:10:10",DateTimeFormatter.ISO_LOCAL_DATE_TIME);
// 2022-01-01T18:10:10
LocalDate parse = LocalDate.parse("20220212",DateTimeFormatter.BASIC_ISO_DATE);
// 2022-01-01

 3).通过from方法,完成LocalDate,LocalTime,LocaldDateTime之间的互相转化:

//实例1:dateTime转date
LocalDateTime dateTime = LocalDateTime.now();
//2022-02-22T16:00:00
LocalDate date = LocalDate.from(dateTime);
//2022-02-22

//实例2:dateTime转Time
 LocalDateTime dateTime = LocalDateTime.now();
//2022-02-22T16:00:00
LocalTime date = LocalTime.from(dateTime);
//16:00:00.944884500

//date和time是没有办法转化为LocalDateTime的,因为缺少信息(除非传入的对象既可以转化为date也可以转化为time,这是博主还不知道的例外情况)

//data对象补全time合成dateTime
LocalDate date = LocalDate.now();
LocalDateTime dateTime = date.atTime(10, 10, 10);
//2022-01-01T10:10:10

//time对象补全data合成datetime
LocalTime time = LocalTime.now();
LocalDateTime dateTime1 = time.atDate(LocalDate.of(2022,2,22));
//2022-02-22T10:10:10

//但是OffsetDateTime和ZonedDateTime携带的信息比LocalDateTime还要详细,所以可以向下转换为LocalDateTime
//实例3:ZonedDateTime转LocalDateTime
ZonedDateTime zonedDateTime = ZonedDateTime.now();
LocalDateTime from = LocalDateTime.from(zonedDateTime);

 时间类的都实现了接口Temporal(它继承了TemporalAccessor),所以它们都实现了四种可以生成自己的工厂方法:from,now,of,parse

1.2 口语化时间的方法

所谓口语化时间,这是我自己想出来的,因为实在想不到用什么词了,大体意思就是,我可以获取时间中的年、月、日、时、分、秒、周几。

//1.获取年:
LocalDateTime now = LocalDateTime.now();
System.out.println(now.getYear());
//2022

//2.获取月
LocalDateTime now = LocalDateTime.now();
System.out.println(now.getMonth());
//MARCH 
System.out.println(now.getMonth());
//3

//3.来点特别的,今年的第几天
LocalDateTime now = LocalDateTime.now();
System.out.println(now.getDayOfYear());
//77,今天是2022年的3月18日

//4.这个月的第几天
System.out.println(now.getDayOfMonth());
//18

//5.今天是本周几
System.out.println(now.getDayOfWeek());
//FRIDAY


//6.ChronoField 枚举来指定获取的信息
System.out.println(now.get(ChronoField.DAY_OF_MONTH));
//3

我们能从LocalDateTime 中获取如此多的信息,除此之外我们还能获得当前的时分秒,纳秒,如果是LocalTime和LocalDate,它们只能获得自己相应的部分,例如LocalTime只能知道当前的时分秒,而不能知道当前是本月的第几天。

最后,ChronoField枚举类是非常重要的时间API枚举类之一,我们会在之后的with方法中再次遇见它。

 

1.3 时间计算的方法

本小节介绍时间的修改,时间的计算,那么我们来了解下

 

1).时间的加减

//当前时间:2022-02-12 11:32:35

//1.通过ChronoUnit枚举来演示 时间加法
LocalDateTime date1 = now.plus(6, ChronoUnit.DAYS);
//2022-02-18 11:32:35

//2.通过ChronoUnit枚举来演示 时间减法
LocalDateTime date2 = now.minus(1,ChronoUnit.MONTHS);
//2022-01-12 11:32:35

//3.直接调用的月份减法,当然还有减去日,减去秒等等,不重复演示
LocalDateTime date3 = now.minusMonths(1);
//2022-01-12 11:32:35

//4.加上一段时期,Preiod.of([年],[月],[日])
Period period = Period.of(1, 0, 0);
LocalDateTime date1 = now.plus(period);
//2023-02-12 11:32:35

//5.一个小补充,两个时间之间的加减演示,得到两个时间之间相差多少天
LocalDateTime dateTime1 = LocalDateTime.now();
LocalDateTime dateTime2 = LocalDateTime.now().plusDays(10);
//当前时间加10天
long days = dateTime1.until(dateTime2, ChronoUnit.DAYS);
//10
//之后我们还会接触到两种可以得到时间差额的方法

时间加减方法可以传入一个Period对象来表示加上/减少多少时间之后我们会介绍到它。现在我们通过 ChronoUnit 枚举 来表示对该时间的操控,最简单的还是直接使用minusDay、plusHours这些方法,从名字上就能表达出你需要对时间做什么。

 

2.时间的修改

//实例1:修改年份
LocalDateTime dateTime2 = dateTime1.withYear(2010);
//2010-01-11T10:20:30

//实例2:修改月份
LocalDateTime dateTime2 = dateTime1.withDayOfMonth(10);
//2022-10-11T10:20:30

//实例3:通过ChronoField枚举修改,可玩性更高!
LocalDateTime dateTime2 = dateTime1.with(ChronoField.DAY_OF_MONTH,11);
//2022-01-11T10:20:30

是原本的对象并不会被修改,它会创造一个副本,也就是原本对象的修改版! 同样的,再次强调唯二的两个时间枚举工具 ChronoField 和 ChronoUnit

 

3.时区偏移

时区是按照一定的规则将区域划分成的标准时间相同的区间。在 ZoneRules 这个类中包含 了 40 个这样的实例。你可以简单地通过调用 ZoneId 的 getRules()得到指定时区的规则。每个特定的 ZoneId 对象都由一个地区 ID 标识,比如:

ZoneId romeZone = ZoneId.of("Asia/Shanghai");

 记得我们之前说过date和不能转化为dateTime么?现在添加时区后它就变成更加详细的ZonedDateTime!

ZoneId romeZone = ZoneId.of("Asia/Shanghai");
//时区建立好了!

//LocalDate转ZonedDateTime
LocalDate date = LocalDate.of(2014, Month.MARCH, 18);
ZonedDateTime zdt1 = date.atStartOfDay(romeZone);
//2014-03-18T00:00+08:00[Asia/Shanghai]

//LocalDateTime转ZonedDateTime
LocalDateTime dateTime = LocalDateTime.of(2014, Month.MARCH, 18, 13, 45);
ZonedDateTime zdt2 = dateTime.atZone(romeZone);
//2014-03-18T13:45+08:00[Asia/Shanghai]

//Instant转ZonedDateTime
Instant instant = Instant.now();
ZonedDateTime zdt3 = instant.atZone(romeZone);
//2022-02-12T15:33:43.468020900+08:00[Asia/Shanghai]

 这种方式是通过ZoneId定义的地区名称来进行时区偏移:

但是如果说我们不知道当前的时区属于何种时区该怎么办?

我们要使用数字的方式来进行时区偏差:

ZoneOffset shanghai = ZoneOffset.of("+08:00");
//上海,北京时间偏差+8
LocalDateTime dateTime1 = LocalDateTime.ofInstant(Instant.now(), shanghai);
//还不清楚Instant是什么?别担心,第二节就会介绍它,它其实就代表伦敦当地时间,时区是+00:00

 最后,就是时间格式化输出成字符串,所有的功课都掌握好了,相信你也可以随心所欲的操纵全新的时间API了,那么输出成字符串,在页面上展现我们的成果:

//实例1:自定义格式化输出形式
DateTimeFormatter date = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
//自定义建立格式化输出形式

String format = LocalDateTime.now().format(formatter);
System.out.println(format);
//2022-03-18 20:19:02

//实例2:JDK原生时间格式化形式
String format = LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
System.out.println(format);
//2022-03-18T20:20:53.0526567

String format = LocalDateTime.now().format(DateTimeFormatter.BASIC_ISO_DATE);
System.out.println(format);
//20220318 (这种格式似乎不是给人类看的)

//实例3:(复杂的)高细粒度 时间格式化
DateTimeFormatter italianFormatter = new DateTimeFormatterBuilder()
        .appendText(ChronoField.YEAR)
        .appendLiteral("年")
        .appendValue(ChronoField.MONTH_OF_YEAR, 2)
        .appendLiteral("月")
        .appendText(ChronoField.DAY_OF_MONTH)
        .appendLiteral("日 ")
        .appendText(ChronoField.HOUR_OF_DAY)
        .appendLiteral("点")
        .appendText(ChronoField.MINUTE_OF_HOUR)
        .appendLiteral("分")
        .appendText(ChronoField.SECOND_OF_MINUTE)
        .appendLiteral("秒")
        .parseCaseInsensitive()
        .toFormatter();
String format = LocalDateTime.now().format(italianFormatter);
//2022年02月22日 22点22分22秒

第二节:旧API过渡

 Java最讲究的就是向前兼容了,不然JDK1.8 之前的Java代码可能就无法使用或者没办法互相调用了!别担心,Java还是留有让我们从旧时代过渡到新时代的路子的!

 1.Instant

LocalDateTime 和 Instant 是为不同的目的而设计的,一个是为了便于人阅读使用, 另一个是为了便于机器处理,因此不能将二者混用。

Instant和LocalDateTime、LocalDate、LocalTime等一样,都继承了Temporal,所以它也有from,parse,now方法,但是没有format方法,它可以帮助我们从旧API:java.util.Date来过渡到我们崭新的时代:

Date date = new Date();
//假设获取了一个Date对象

Instant instant = Instant.ofEpochMilli(date.getTime());
//将Date转化为纳秒形式注入到Instant中

ZoneId zoneId = TimeZone.getDefault().toZoneId();
//将旧时区转化为新时区

LocalDateTime dateTime = LocalDateTime.ofInstant(instant, zoneId);
//给机器阅读的时间 转化 为给人类阅读的时间

System.out.println(dateTime);
//2022-03-18T21:11:36.938

2. 时间间隔对象:Duration和Period

我们先了解下这两个对象,这两者都可以运用于时间相隔运算,它们都有between方法,但是不同的是:

Duration 类主要用于以秒和纳秒衡量时间的长短,可以得到两个时间相差多少秒,时,分,天等,也可以在此基础上加上\减去一定的时间,获取它的信息需要使用to方法来转化

Period 类主要是年月日之间的时间值它通过get方法获得年月日

LocalDateTime now1 = LocalDateTime.now();
LocalDateTime now2 = now1.plusDays(10);
//在now2的基础上又加了10天

Duration between = Duration.between(now1, now2);
System.out.println(between.minusDays(1).toDays());
//计算两个时间之间相隔多少天,减去1天获取结果:9

Period between1 = Period.between(now1.toLocalDate(), now2.toLocalDate());
System.out.println(between1.plusDays(10).getDays());
//计算两个时间之间相隔多少天,再加上10天:20

第三节:总结

我们介绍了 时间API通过实现父类Temporal(继承TemporalAccessor)来实现 对时间的操纵:

时间类通用方法

方法

静态方法

方法描述

返回值

from

yes

传入Temporal对象创建对象实例

Temporal

now

yes

依据系统时间创建Temporal对象

Temporal

of

yes

传入Temporal对象的部分创建Temporal

Temporal

parse

yes

传入字符串创建Temporal对象

Temporal

atOffset

no

Temporal时区偏移

Temporal

atZone

no

Temporal时区设定

Temporal

format

no

Temporal格式化输出

String

get

no

读取Temporal部分值

int

minus

no

Temporal减去一定的时长

Temporal

plus

no

Temporal加上一定的时长

Temporal

with

no

返回Temporal修改后的副本

Temporal

 

而时间间隔对象 Duration 和 Period 来对时间对象的计算进行补全:

时间间隔通用方法

方法

静态方法

方法描述

返回值

between

yes

创建两个时间点的时间间隔

interval

from

yes

由一个临时时间点创建时间间隔l

interval

of

yes

由它组成部分创建时间间隔

interval

parse

yes

由字符串创建时间间隔

interval

addTo

no

时间间隔叠加到temporal上

temporal

get

no

读取时间间隔状态

Long

isNegative

no

时间间隔是否为负值

boolean

isZero

no

时间间隔是否为0

boolean

minus

no

时间间隔之间相减

interval

multipliedBy

no

时间间隔乘以某个量标

interval

negated

no

忽略某个时长

interval

plus

no

时间间隔之间相加

interval

subtractFrom

no

temporal减去该时间间隔

Temporal

通过时间间隔,我们可以知道两个时间之间差额,更有利于我们的计算!

标签:10,Java,Temporal,第三版,API,时间,2022,LocalDateTime,now
来源: https://www.cnblogs.com/dingcx817/p/16023666.html