ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

Java8新特性之新日期API

2021-02-19 16:04:35  阅读:233  来源: 互联网

标签:之新 java time ZoneId API import Instant ZonedDateTime Java8


早期的日期 API

在早期也就是 Java 8 之前,JDK 原生比较有名的有两个类:

  • Date 类

  • Calendar 类

这两个类相对来说用起来是比较困难的,之前我们往往是用的第三方的库。

新日期 API 的引入

在我们业界来说,这两个有两个很致命的问题:

  • Date 类 和 Calendar 类都是线程不安全的

    除非我们的实例是留在方法体内的

  • Calendar 类设计不太友好

    比如,查第几个月是从 0 开始计数

现在呢,Java 8 引入了一些新的 API,彻底简化了这些操作。

围绕这套新的 API 有许多类,我们着重介绍如下几个:

  1. Instant & Duration

  1. ZonedDateTime & LocalDateTime

以上两个,是处理时间的关键

  1. DateTimeFormatter

    把一个时间对象序列化或者反序列化成字符串

  2. TemporalAdjusters

    更像是一个 help 类,不是一个非常核心的类

所有涉及时间的操作逻辑,我们可以主要分成如下两点:

  • 时区的计算

    时区是一个相对的概念,比如中国的时间、美国的时间是有时差的

  • 绝对时间

    从过去的某一个过去的时间点到现在总共过了多少秒或毫秒,比如 1970年1月1日 0点到现在过去了多少

    我们一般以绝对时间来作为参考

我们要了解新的 API 也是从这两点出发。

Instant 类和 Duration 类

Instant 类就代表了绝对时间的概念,它能告诉你无论是哪一个国家或者是哪一个城市,我们相比地球上过去历史上的某个时间点到现在为止过去了多少时间。

 1 package 新日期API;
 2 
 3 import java.time.Instant;
 4 
 5 public class NowDate {
 6     public static void main(String[] args) {
 7         Instant now = Instant.now();
 8         System.out.println("现在过去了多少秒:" + now.getEpochSecond()); // 现在过去了多少秒:1613704995
 9     }
10 }

我们可以用 Instant 的一些 get 方法可以得到绝对时间的坐标参考,比如,我们可以测量一个函数执行花费了多少时间

 1 package 新日期API;
 2 
 3 import java.time.Duration;
 4 import java.time.Instant;
 5 
 6 public class Instant {
 7     public static void main(String[] args) throws Throwable {
 8         Instant start = Instant.now();
 9         // 执行一些逻辑
10         Thread.sleep(2000);
11         Instant end = Instant.now();
12 
13         // 和 Instant 挂钩的还有一个 Duration
14             // 计算这个时间持续了多久
15         Duration duration = Duration.between(start, end);
16         System.out.println(duration.getSeconds());
17     }
18 }
19 
20 /**
21     输出:
22         2
23 */

ZonedDateTime 类和 LocalDateTime 类

Instant 类代表了时间轴上的绝对时间,但是它并不是一个友好的日历时间,只能是说当前这个时间点离格林威治时间(1970年1月1日 0点)过去了多少,但是它并不能代表着今天是星期几或者几几年的几月几日。

那么我们怎么知道一个日历时间呢?

这就要涉及到 ZonedDateTime 和 LocalDateTime 这两个类,这两个时间可以理解为相对时间。

ZonedDateTime 是带时区的类,LocalDateTime 是不带时区的类。

1. ZonedDateTime 类
 1 package 新日期API;
 2 
 3 import java.time.Instant;
 4 import java.time.ZoneId;
 5 import java.time.ZonedDateTime;
 6 
 7 public class ZonedDateTime {
 8     public static void main(String[] args) {
 9         /**
10          * 将一个绝对的时间转换成一个与地区相关的时间
11          */
12         Instant start = Instant.now();
13 
14         // 方法一:
15             // start.atZone(ZoneId.of(ZoneId))
16         ZonedDateTime zoneTime01 = start.atZone(ZoneId.of("UTC")); // Asia/Shanghai 传递即得上海的时间
17         System.out.println("atZone转成的ZonedDateTime类型的UTC时间:" + zoneTime01);
18 
19         // 方法二:
20             // ZonedDateTime.ofInstant(start, ZoneId.of(ZoneId))
21             // ZoneId
22                 // 地区id
23         ZonedDateTime dtUTC = ZonedDateTime.ofInstant(start, ZoneId.of("UTC"));
24         System.out.println("ZonedDateTime转成的UTC时间:" + dtUTC);
25 
26         // ZoneId.of() 也不一定显示的传递一个地区字符串或者 UTC 等
27         ZonedDateTime dtSH = start.atZone(ZoneId.systemDefault());
28         System.out.println("systemDefault:" + dtSH);
29     }
30 }
31 
32 /**
33     输出:
34         atZone转成的ZonedDateTime类型的UTC时间:2021-02-19T03:58:22.270337800Z[UTC]
35         ZonedDateTime转成的UTC时间:2021-02-19T03:58:22.270337800Z[UTC]
36         systemDefault:2021-02-19T11:58:22.270337800+08:00[Asia/Shanghai]
37 */
2. LocalDateTime 类

和 ZonedDateTime 类的 API 几乎是一模一样,唯一的区别就是 LocalDateTime 类是一个不带时区的。

也就是说,使用 LocalDateTime 这个类 ,你可以知道某年某月某日或某个时间,但是你不知道是属于哪个国家的,一般来说,不建议使用 LocalDateTime 。

3. 获取 ZoneId 列表

可以使用 ZoneRulesProvider.getAvailableZoneIds() 获取 ZoneId 列表

1 package 新日期API;
2 
3 import java.time.zone.ZoneRulesProvider;
4 
5 public class ZoneId {
6     public static void main(String[] args) {
7         System.out.println(ZoneRulesProvider.getAvailableZoneIds());
8     }
9 }

DateTimeFormatter 类

用于把一个时间对象序列化或者反序列化成字符串

序列化成字符串
 1 package 新日期API;
 2 
 3 import java.time.Instant;
 4 import java.time.ZoneId;
 5 import java.time.ZonedDateTime;
 6 import java.time.format.DateTimeFormatter;
 7 
 8 public class DateTimeFormatter {
 9     public static void main(String[] args) {
10         Instant start = Instant.now();
11         ZonedDateTime dtSH = ZonedDateTime.ofInstant(start, ZoneId.of("Asia/Shanghai"));
12 
13         DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
14         System.out.println(df.format(dtSH));
15     }
16 }
17 
18 /**
19     输出:
20         2021-02-19 13:48:52
21 */

格式可以随意设置,再例如:

 1 package 新日期API;
 2 
 3 import java.time.Instant;
 4 import java.time.ZoneId;
 5 import java.time.ZonedDateTime;
 6 import java.time.format.DateTimeFormatter;
 7 
 8 public class DateTimeFormatter {
 9     public static void main(String[] args) {
10         Instant start = Instant.now();
11         ZonedDateTime dtSH = ZonedDateTime.ofInstant(start, ZoneId.of("Asia/Shanghai"));
12 
13         DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
14         System.out.println(df.format(dtSH));
15     }
16 }
17 
18 /**
19     输出:
20         2021/02/19 13:51:28
21 */

也可以加上时区的偏移量

 1 package 新日期API;
 2 
 3 import java.time.Instant;
 4 import java.time.ZoneId;
 5 import java.time.ZonedDateTime;
 6 import java.time.format.DateTimeFormatter;
 7 
 8 public class DateTimeFormatter5 {
 9     public static void main(String[] args) {
10         Instant start = Instant.now();
11         ZonedDateTime dtSH = ZonedDateTime.ofInstant(start, ZoneId.of("Asia/Shanghai"));
12 
13         DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ssxx");
14         String dateStr = df.format(dtSH);
15         System.out.println(dateStr);
16     }
17 }
18 
19 /**
20     输出:
21         2021-02-19 13:52:25+0800
22 */

注意:

  • yyyy-MM-dd HH:mm:ss 年-月-日 时:分:秒

    • M 大写是为了区分 "月" 和 "分"

    • H 大写是为了区分 12小时制24小时制

      • 小写的 h 是12小时制

      • 大写的 H 是24小时制

  • 有时候我们会看到这样的格式:yyyy-M-d H​:m:​s

    • mm 与 m 等,它们的区别为 是否有前导零

    • H,m,s表示 非零开始 ,HH,mm,ss表示 从零开始

      • 比如凌晨1点2分,HH:mm显示为 01:02 ,H:m显示为 1:2

反序列化

我们可以使用 ZonedDateTime.parse() 将一个字符串转回一个反序列化的 ZonedDateTime

1 ZonedDateTime dt = ZonedDateTime.parse(dateStr, df);
2 System.out.println(dt);
3 
4 /**
5     输出:
6         2021-02-19T14:06:35+08:00
7 */

TemporalAdjusters

这个类更像是一个 help 的方法,用来调整时间,比如说,我想设置一些时间,但是可能因为某些业务逻辑,想单纯的设置某些量有点困难,就可以用这个类。

可以做一些时间业务上给我们封装好的事情

例如,我们想获取下周五的日期时间

 1 package 新日期API;
 2 
 3 import java.time.DayOfWeek;
 4 import java.time.Instant;
 5 import java.time.ZoneId;
 6 import java.time.ZonedDateTime;
 7 import java.time.temporal.TemporalAdjusters;
 8 
 9 public class TemporalAdjusters {
10     public static void main(String[] args) {
11         Instant now = Instant.now();
12         ZonedDateTime dtSH = now.atZone(ZoneId.of("Asia/Shanghai"));
13         ZonedDateTime nextFriday = dtSH.with(TemporalAdjusters.next(DayOfWeek.FRIDAY));
14         System.out.println(nextFriday);
15     }
16 }
17 
18 /**
19     输出:
20         2021-02-26T14:16:04.088263300+08:00[Asia/Shanghai]
21 */

各种datetime 之间的关系

标签:之新,java,time,ZoneId,API,import,Instant,ZonedDateTime,Java8
来源: https://www.cnblogs.com/MAQ-space/p/14415953.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有