1. 概述

Java8中的时间类主要有:Date、Instant、LocalDateTime(LocalDate、LocalTime)、ZonedDateTime,除去Date,java.time包下的那些时间类都是不可变类,也就是说:其是线程安全的,对其设置只会产生一个新对象。

在这里,我们要分清楚包含时区信息的类、以及不包含时区信息的类。不包含时区信息的类实际上就类似于一个yyyy-MM-dd HH:mm:ss字符串,需要额外的时区信息才能表达一个时刻,即LocalDateTime、LocalDate、LocalTime。而Date(0时区)、Instant(0时区)、ZonedDateTime都包含有时区信息。

import java.util.Date;
import java.util.TimeZone;class Scratch {public static void main(String[] args) {TimeZone.setDefault(TimeZone.getTimeZone("GMT"));Date d1 = new Date();Instant i1 = Instant.now();ZonedDateTime z1 = ZonedDateTime.now();LocalDateTime l1 = LocalDateTime.now();TimeZone.setDefault(TimeZone.getTimeZone("Asia/Shanghai"));Date d2 = new Date();Instant i2 = Instant.now();ZonedDateTime z2 = ZonedDateTime.now();LocalDateTime l2 = LocalDateTime.now();TimeZone.setDefault(TimeZone.getTimeZone("Australia/Darwin"));Date d3 = new Date();Instant i3 = Instant.now();ZonedDateTime z3 = ZonedDateTime.now();LocalDateTime l3 = LocalDateTime.now();}
}


看懂上面的代码以及断点处的变量图基本就搞懂了Java8中的时间类的使用了。我劝你可千万别跳过,好好看看。

2. 类结构

2.1. Date

    private transient long fastTime;private transient BaseCalendar.Date cdate;

本质是记录了0时区的时间,不同时区的人在同一时刻new Date()时,其对象内存放的毫秒数是一样的(都是0时区)。

2.1.1. 转换成字符串

因为System.out.println函数在打印时间时,会取操作系统当前所设置的时区,然后根据这个时区将毫秒数解释成该时区的时间。或是SimpleDateTimeFormat这种日期格式化类也会在打印时根据时区解释Date中的毫秒数。

Date date = new Date(1503544630000L);  // 对应的北京时间是2017-08-24 11:17:10SimpleDateFormat bjSdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");     // 北京
bjSdf.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));  // 设置北京时区SimpleDateFormat tokyoSdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");  // 东京
tokyoSdf.setTimeZone(TimeZone.getTimeZone("Asia/Tokyo"));  // 设置东京时区SimpleDateFormat londonSdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); // 伦敦
londonSdf.setTimeZone(TimeZone.getTimeZone("Europe/London"));  // 设置伦敦时区System.out.println("毫秒数:" + date.getTime() + ", 北京时间:" + bjSdf.format(date));
System.out.println("毫秒数:" + date.getTime() + ", 东京时间:" + tokyoSdf.format(date));
System.out.println("毫秒数:" + date.getTime() + ", 伦敦时间:" + londonSdf.format(date));// 输出
// 毫秒数:1503544630000, 北京时间:2017-08-24 11:17:10
// 毫秒数:1503544630000, 东京时间:2017-08-24 12:17:10
// 毫秒数:1503544630000, 伦敦时间:2017-08-24 04:17:10

2.1.2. 从字符串中读取时间

2017-8-24 11:17:10解析为一个Date对象,会根据SimpleDateFormat设置的时区而将其转换成0时区的Date对象。将一个时间字符串按不同时区来解释,得到的Date对象的值是不同的。验证如下:

String timeStr = "2017-8-24 11:17:10"; // 字面时间
SimpleDateFormat bjSdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
bjSdf.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
Date bjDate = bjSdf.parse(timeStr);  // 解析
System.out.println("字面时间: " + timeStr +",按北京时间来解释:" + bjSdf.format(bjDate) + ", " + bjDate.getTime());SimpleDateFormat tokyoSdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");  // 东京
tokyoSdf.setTimeZone(TimeZone.getTimeZone("Asia/Tokyo"));  // 设置东京时区
Date tokyoDate = tokyoSdf.parse(timeStr); // 解析
System.out.println("字面时间: " + timeStr +",按东京时间来解释:"  + tokyoSdf.format(tokyoDate) + ", " + tokyoDate.getTime());// 输出为:
// 字面时间: 2017-8-24 11:17:10,按北京时间来解释:2017-08-24 11:17:10, 1503544630000
// 字面时间: 2017-8-24 11:17:10,按东京时间来解释:2017-08-24 11:17:10, 1503541030000

2.2. Instant

    private final long seconds;private final int nanos;

本质是记录了0时区的时间

2.3. LocalDateTime、LocalDate、LocalTime

根据当前设置的时区获取当前时区的日期、时间,但不会记录时区信息。

Local*这些时间类实际上就相当于一个字符串,只不过把年月日、时分秒解析出来了而已。
String与LocalDateTime是等价的

2.3.1. LocalDateTime:

    private final LocalDate date;private final LocalTime time;

2.3.2. LocalDate:

    private final int year;private final short month;private final short day;

2.3.3. LocalTime

    private final byte hour;private final byte minute;private final byte second;private final int nano;

2.4. ZonedDateTime

在LocalDateTime的基础上同时保存了当前的时区,即:根据当前设置的时区获取当前时区的日期、时间,同时保存当前时区信息。

    private final LocalDateTime dateTime;private final ZoneOffset offset;private final ZoneId zone;

自带时区信息,默认获取当前时区。

3. 记录时间原理

new Date()Instant.now本质上都是记录了0时区的时间,即使当前时区不同,其存储的都是距离1970-01-01 00:00:00所经过的时间。

Local*这些时间类实际上就相当于一个字符串,只不过把年月日、时分秒解析出来了而已。

4. 打印时间

打印时设置的时区信息会对原时间解析出来的字符串有影响,打印过程会转换原时区时间到现在时区时间,这点一定要注意。

Instant打印时要给DateTimeFormatter设置时区才能打印,否则会报错。

DateTimeFormatter.ofPattern(pattern).withZone(ZoneId.of("Asia/Shanghai"))

5. 注意点

5.1. DateTimeFormatter.with*()会返回一个新的对象

正确的做法:

DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL).withZone(ZoneId.of("GMT")).withLocale(Locale.UK)

错误的做法

DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL);
formatter.withZone(ZoneId.of("GMT"));
formatter.withLocale(Locale.UK);

因为DateTimeFormatter是一个不可变类,所以不可以修改其属性,同时也就是个线程安全类了。其灵活的创建过程是利用DateTimeFormatterBuilder来实现的。

5.2. DateTimeFormatter.ofPattern()没有设置打印时的时区

需要设置时区需要DateTimeFormatter.ofPattern(“yyyy-MM-dd HH:mm:ss”).withZone(ZoneId.of(“GMT”))这样设置。

5.3. SimpleDateFormat并非线程安全

其format()与parse()方法都不是线程安全。

6. 拓展

6.1. Clock类

Clock是带有时区信息的时间处理类,用它可以获取不同时区的时间,也可以配合Duration,对时间进行时、分、秒级别的修改

6.2. Duration 和 Period

Duration 和 Period 都是用来表示两个时间量之间的差值,不同点在于Duration 是基于时间值,而 Period 是基于日期值。

6.3. java.time包下的5个包组成:

  1. java.time – 包含值对象的基础包
  2. java.time.chrono – 提供对不同的日历系统的访问
  3. java.time.format – 格式化和解析时间和日期
  4. java.time.temporal – 包括底层框架和扩展特性
  5. java.time.zone – 包含时区支持的类

6.4. JDBC映射

最新JDBC映射将把数据库的日期类型和Java 8的新类型关联起来:

date -> LocalDate
time -> LocalTime
timestamp -> LocalDateTime

6.5. SimpleDateFormat

SimpleDateFormat只能格式化Date。而DateTimeFormatter可以格式化TemporalAccessor(不包括Date,但是包括LocalDate*、Instant、ZonedDateTime等)。

7. 参考资料

  1. java 8的java.time包(非常值得推荐) - 不姓马的小马哥 - 简书
  2. Java中的时间与时区 - frcoder - CSDN
  3. 深入学习 Java 8 全新日期时间库 java.time(一)- FXBStudy - CSDN

一文搞懂Java8中表示当前的时间类Date、Instant、LocalDateTime、ZonedDateTime相关推荐

  1. 一文搞懂Qt中的颜色渐变(QGradient Class)

    一文搞懂Qt中的颜色渐变(QGradient Class) 1, 快速开始! Qt中与颜色渐变有关的类是QGradient 其中它又有三个子类:QLinearGradient.QRadialGradi ...

  2. 一文搞懂产品中的搜索设计

    搜索功能是我们日常生活中接触最多的功能之一,它更够很好的提高用户使用产品的效率,用户对搜索功能的依赖性也比较大,所以设计好搜索功能将会很大程度上提高用户体验.本文作者通过分享这篇文章,帮我们搞懂产品中 ...

  3. 一文搞懂Java8新特性

    文章目录 导语 函数式接口 Lambda表达式 Stream API Optional类 新的日期时间API 方法引用 接口中定义默认方法 导语 Java8发布时被誉为Java里程碑式的一次更新,是J ...

  4. java8 lambda 视频_一文搞懂Java8 Lambda表达式(附带视频教程)

    Lambda表达式介绍 Java 8的一个大亮点是引入Lambda表达式,使用它设计的代码会更加简洁.通过Lambda表达式,可以替代我们以前经常写的匿名内部类来实现接口.Lambda表达式本质是一个 ...

  5. python中row是什么意思_一文搞懂Python中的yield

    关注公众号「Python七号」,及时 get Python 技能. yield 可以实现生成器,可以实现协程. 什么是生成器,什么是协程,如果还不了解,可以继续往下看,概念可以不懂,只要理解它的作用和 ...

  6. 【NLP】一文搞懂NLP中的对抗训练

    本文主要串烧了FGSM, FGM, PGD, FreeAT, YOPO, FreeLB, SMART这几种对抗训练方法,希望能使各位大佬炼出的丹药更加圆润有光泽,一颗永流传 简介 对抗训练是一种引入噪 ...

  7. 服务器千兆网卡接百兆交换机不通_一文搞懂监控工程中百兆交换机和千兆交换机的区别在哪?...

    安防监控系统工程现在都是用的网络摄像机,那么就肯定会经常和网络设备--交换机打交道,很多人在做监控方案的时候犯难,多少台摄像机该选用百兆交换机还是千兆交换机呢?关于这个问题除了需要掌握理论知识还是结合 ...

  8. 一文搞懂css中精灵图如何使用

    文章目录 前言 一.精灵图是什么? 1.概念: 2.图片示例: 二.为什么使用精灵图? 1.用户体验而言: 2.就开发者而言: 3.就服务器而言: 三.怎样使用精灵图 1.background-pos ...

  9. 一文搞懂matplotlib中的颜色设置

    欢迎关注"生信修炼手册"! 在matplotlib中,颜色设置有以下多种方式 1. 常用颜色的字母表示及缩写 最常用的颜色表示方法,有以下几种常用颜色 1. red,表示红色,  ...

最新文章

  1. Java 8 Lambda
  2. 开源跳板机(堡垒机)Jumpserver v0.2.0 使用说明
  3. JAVA Swing——框架(JFrame、JDialog)位置居于父窗口中央的解决方案
  4. OpenCV离散傅立叶变换
  5. 笔记本平板电脑推荐_ONETALK 亦说便携式平板电脑推荐
  6. C# 自定义常用代码段
  7. 字节跳动将推出汽车云业务,计划2025年追赶腾讯
  8. 用jTessBoxEditor自动训练3500常用汉字
  9. 什么是狭义人工智能、通用人工智能和超级人工智能?
  10. 量子计算机未来猜想,太厉害了吧?这台量子计算机能预测16种不同的未来!
  11. Cocos 2dx - lua Action动作方法
  12. 【Delphi Stringgrid 设置表格文字居中后有重影,去除重影方法】
  13. 李德毅:未来交通——自动驾驶与智能网联
  14. 关于近期很火的视频解析APP
  15. opencv应用程序移植到hi3559板卡
  16. 屌丝的24个特征,看看自己中了几枪
  17. 搅拌反应釜cad图纸_生物发酵反应釜的设计(机械CAD图纸)
  18. 浮钓鲢鳙调漂和线组图解与饵料分析(转载)
  19. pdfGPT|无需阅读,让 PDF 和自己对话
  20. 利用python PIL库进行图像模式的转换

热门文章

  1. 愿我是清晨洒入你心间的第一缕阳光
  2. php tcpdf 嵌入字体,TCPDF如何设置中文字体为内嵌字体?
  3. 在 Solaris 系统上安装 PHP
  4. java——java介绍
  5. 一个行向量与一个列向量的乘积的值等于该列向量与行向量乘积矩阵的迹的值
  6. Mac电脑隔空投递如何添加到菜单栏?
  7. 批量修改txt(或其他)文件编码为utf-8
  8. PHP Laravel框架 微信模板消息发送
  9. KVM虚拟化技术及环境配置
  10. 地铁供电系统原理图_地铁供电系统智能化发展原稿(图文高清版)