工作这么久了,对于Java中时间日期的操作一直很蛋疼,一会用Date,一会用Calendar一会用LocalDateTime,始终没有认真总结过它们的联系与区别。迷迷糊糊用了好几年了,今天终于搞清楚了!

一,Java8日期时间API产生的前因后果

1.1 为什么要重新定义一套日期时间API

  • 操作不方便:java中最初的Date不能直接对指定字段进行加减操作也不支持国际化,后来新增了Calendar,但是Calendar又不支持格式化操作,需要转换成Date再进行格式化,总之一直在填坑,使用起来一点都不够优雅。
  • 线程不安全:Date,Caleandar,SimpleDateFormat都是可变的,线程不安全的,所以你需要编写额外的代码处理线程安全问题。

1.2 Java8重新定义

  • 对时间日期相关操作进行细分:时间,日期,日期&时间,时间戳,时间段,日期段,格式化等
  • 所有类都是不可变的,线程安全
  • 兼容旧的日期时间

1.3Java8兼容旧版本的Date,同时也规范了日期时间的转换流程。

一,给人读的( LocalDateTime & LocalDate & LocalTime)

java8中将时间和日期进行的区分,用LocalDateTime表示日期和时间,LocalDate用来表示日期而LocalTime表示时间。内部实现也非常好理解,LocalDateTime = LocalDate + LocalTime,并且他们的内部api也一致,所以笔者就结合工作中的经验,介绍他们最常见的用法。

1.1 获取当前时间

LocalDateTime localDateTime = LocalDateTime.now();
// 打印结果: 2019-12-02T22:09:20.503

1.2 获取指定时间

// 获取 2019年12月02号 23 : 59 : 59
LocalDateTime localDateTime2 = LocalDateTime.of(2019, 12, 2, 23, 59, 59);
// 打印结果: 2019-12-02T23:59:59

1.3 日期/时间加减操作

// localDateTime2的基础上加1天零1s
LocalDateTime localDateTime3 = localDateTime2.plusDays(1).plusSeconds(1);
// 打印结果:2019-12-04T00:00

1.4 获取指定的字段(年月日时分秒,纳秒,不支持毫秒)

System.out.println("现在是: " + localDateTime.getYear() + " 年中的第 " + localDateTime.getDayOfYear() +" 天");
// 打印结果:现在是: 2019 年中的第 336 天
// 画外音: 快过年了呀,感觉这一年又没啥收获

二,给计算机读的(Instant)

小知识:地球上不同地区经度不同会划分时区,以零度经线上为准(格林尼治天文台旧址,UTC时区)为准,将地球上各个部分分为了24个时区。向西走,每过一个时区,就要把表拨慢1个小时;同理每向东走一个时区,就要把表拨快1个小时。最后,中国处于东8区。

2.1 获取UTC时间(格林尼治时间)

Instant instant = Instant.now();
// 打印结果: 2019-12-02T14:31:41.661Z

2.2 获取北京时间(东8区)

// OffsetTime表示有时差的时间,除了UTC时间,都是OffsetTime
OffsetDateTime offsetDateTime = instant.atOffset(ZoneOffset.ofHours(8));
// 打印结果: 2019-12-02T22:31:41.661+08:00

2.3 获取毫秒数(1970-01-01T00:00:00Z开始计算)

long epochMilli = instant.toEpochMilli()
// 打印结果:1575297101661

2.4 定义时间戳

Instant instant1 = Instant.ofEpochSecond(59);
// 打印结果: 1970-01-01T00:00:59Z
instant2 = instant1.plusSeconds(99)
// 打印结果:1970-01-01T00:02:38Z

三, 时间间隔(Duration)

3.1 计算日期间隔(参数位置影响结果哦)

Instant instant1 = Instant.now();
Instant instant2 = instant1.plusSeconds(99); Duration duration1 = Duration.between(instant1, instant2);
Duration duration2 = Duration.between(instant2, instant1);
// 打印结果 duration1:PT1M39S
// 打印结果 duration2:PT-1M-39S long duration1Seconds = duration1.getSeconds();
long duration2Seconds = duration1.getSeconds();
// 打印结果 duration1Seconds: 90
// 打印结果 duration2Seconds: -90

3.2 操作时间间隔

Duration duration3 = duration1.plusDays(1);
// 打印结果:PT24H1M39S

注意 : 仅支持时间操作(Instant, LocalTime,LocalDateTime),不支持日期(LocalDate)

四,日期间隔(Period)

LocalDate localDate1 = LocalDate.now();
LocalDate localDate2 = localDate1.plusDays(1);
Period period = Period.between(localDate1, localDate2);
long days = period.getDays();
// 打印结果 peroid: P1D
// 打印结果 days: 1

五,日期/时间校正器(TemporalAdjuster)

5.1 获取指定日期或时间

LocalDateTime localDateTime1 = LocalDateTime.now();
LocalDateTime localDateTime2 = localDateTime.withDayOfMonth(20);
// 打印结果 localDateTime1:2019-12-02T22:57:47.674
// 打印结果 localDateTime2:2019-12-20T22:57:47.674

5.2 获取下一个固定日期(下一个星期天)

LocalDateTime localDateTime3 = localDateTime.with(TemporalAdjusters.next(DayOfWeek.SUNDAY));
// 打印结果 localDateTime33:2019-12-08T23:00:43.101

5.3 自定义矫正器

// 获取下一个工作日
LocalDateTime localDateTime4 = localDateTime.with((tempDateTime) -> {
LocalDateTime localDateTime5 = (LocalDateTime) tempDateTime;
DayOfWeek dayOfWeek = localDateTime5.getDayOfWeek();
if (dayOfWeek.equals(DayOfWeek.FRIDAY)) {
return localDateTime5.plusDays(3);
} else if (dayOfWeek.equals(DayOfWeek.SATURDAY)) {
return localDateTime5.plusDays(2);
} else {
return localDateTime5.plusDays(1);
}
});
// 打印结果 localDateTime4:2019-12-03T23:00:43.101

六,日期时间格式化

DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime localDateTime = LocalDateTime.now();
String dateStr =dateTimeFormatter.format(localDateTime);
// 打印结果: 2019-12-02 23:08:55
LocalDateTime localDateTime2 = LocalDateTime.parse(dateStr, dateTimeFormatter);
// 打印结果: 2019-12-02T23:08:55
LocalDate localDate = LocalDate.parse(dateStr, dateTimeFormatter);
// 打印结果: 2019-12-02

七,基于Instant进行转换

java8api对于时间戳,日期时间以及老版本的Date对象之间的转换也进行了兼容和适配,所有的转换操作都可以基于Instant对象进行。由于LocalDate,LocalTime和LocalDateTime三个类的操作完全一样,所以下文仍使用LocalDateTime演示。

7.1 时间戳转LocalDate,LocalDate,LocalDateTime

long timestamp = Instant.now().toEpochMilli();
LocalDateTime localDateTime = Instant.ofEpochMilli(timestamp).atOffset(ZoneOffset.ofHours(8)).toLocalDateTime();
// 打印结果:2019-12-02T23:20:25.791

7.2 LocalDate,LocalDate,LocalDateTime转时间戳

LocalDateTime localDateTime = LocalDateTime.now();
long timestamp = localDateTime.toInstant(ZoneOffset.ofHours(8)).toEpochMilli();
// 打印结果:1575300368099

7.3 兼容旧版本Date

LocalDateTime localDateTime3 = LocalDateTime.now();Date date =
Date.from(localDateTime.atZone(ZoneOffset.ofHours(8)).toInstant());LocalDateTime localDateTime4  =
localDateTime3.atZone(ZoneOffset.ofHours(8)).toLocalDateTime();
// 打印结果 date:Mon Dec 02 23:32:53 CST 2019
// 打印结果 lcoalDateTime4:2019-12-02T23:32:53.188

八, Q&A

上一篇问题:在java中通常使用synchronized来实现方法同步,AQS中通过CAS保证了修改同步状态的一致性问题,那么对比synchronized,cas有什么优势不同与优势呢?你还知道其他无锁并发的策略吗?

8.1 Answer

Java中的无锁并发策略可以分为三种:

  1. 基于乐观锁的CAS操作
  2. Copy On Write:写时复制是指:在并发访问的情景下,当需要修改JAVA中Containers的元素时,不直接修改该容器,而是先复制一份副本,在副本上进行修改。修改完成之后,将指向原来容器的引用指向新的容器(副本容器)
  3. ThreadLocal:线程本地存储,就是为每一个线程创建一个变量,只有本线程可以在该变量中查看和修改值。

8.2 Question

  1. 这是一道送分题:正如上文提到的,Java8之前的日期时间以及格式化类是线程不安全的,你知道怎么编写测试代码吗?

  2. 如果优雅得获取昨天0点整的毫秒值?

学习Java过程中可能遇到问题和困惑,关注我vx公众号 “cruder” ,后台留言,笔者帮你一起解决!(需要学习资料的请关注后后台留言,主要都是java相关,java基础,并发,mysql,redis,es,mq等都都有!)

都9012了,Java8中的日期时间API你还没有掌握?的更多相关文章

  1. 【Java8新特性】关于Java8中的日期时间API,你需要掌握这些!!

    写在前面 Java8之前的日期和时间API,存在一些问题,比如:线程安全的问题,跨年的问题等等.这些问题都在Hava8中的日期和时间API中得到了解决,而且Java8中的日期和时间API更加强大.立志 ...

  2. Java8中的日期时间类

    测试类: import java.time.*; import java.time.format.DateTimeFormatter; public class App { public static ...

  3. JDK8中新日期时间API

    它们面临的问题是:可变性:像日期和时间这样的类应该是不可变的.偏移性:Date中的年份是从1900开始的,而月份都从0开始.格式化:格式化只对Date有用,Calendar则不行.此外,它们也不是线程 ...

  4. Java 8 新特性-菜鸟教程 (8) -Java 8 日期时间 API

    Java 8 日期时间 API Java 8通过发布新的Date-Time API (JSR 310)来进一步加强对日期与时间的处理. 在旧版的 Java 中,日期时间 API 存在诸多问题,其中有: ...

  5. Java 8 日期时间 API

    转自:https://www.runoob.com/java/java8-datetime-api.html Java 8通过发布新的Date-Time API (JSR 310)来进一步加强对日期与 ...

  6. java 数据结构(三):java常用类 三 日期时间API

    JDK 8之前日期时间API 1.获取系统当前时间:System类中的currentTimeMillis()long time = System.currentTimeMillis();//返回当前时 ...

  7. Java 常用类-程序员头大的日期时间API

    第二节.日期时间API 一.JDK8之前日期时间API 1.1 java.lang.System类 System类提供的public static long currentTimeMillis()用来 ...

  8. Java日期时间API系列11-----Jdk8中java.time包中的新的日期时间API类,使用java8日期时间API重写农历LunarDate

    通过Java日期时间API系列7-----Jdk8中java.time包中的新的日期时间API类的优点,java8具有很多优点,现在网上查到的农历转换工具类都是基于jdk7及以前的类写的,下面使用ja ...

  9. Java日期时间API系列6-----Jdk8中java.time包中的新的日期时间API类

    因为Jdk7及以前的日期时间类的不方便使用问题和线程安全问题等问题,2005年,Stephen Colebourne创建了Joda-Time库,作为替代的日期和时间API.Stephen向JCP提交了 ...

随机推荐

  1. Flask:项目的准备工作

    1.创建虚拟环境 (1)打开Windows命令窗口,输入命令(先确保电脑上安装了Anaconda): conda create -n FlaskPath python=3.5.2 FlaskPath为 ...

  2. Vue中错误图片的处理

    在一个Vue的PC项目中,要求给错误图片不要让它显示丑陋的图片,就要给图片写一个失败后的默认图片, 在这里写了两种方法, 第一种方法,也就是百度到的最多的代码,就是给一张图片一个默认值. 第二种问题, ...

  3. Feeling after reading《Jane Eyre》

    Yesterday I read and listened over the book named <Jane Eyre>, the book is very thoughtful, th ...

  4. 暑期集训20190727 水(water)

    [题目描述] 有一块矩形土地被划分成n×m个正方形小块.这些小块高低不平,每一小 块都有自己的高度.水流可以由任意一块地流向周围四个方向的四块地中,但 是不能直接流入对角相连的小块中. 一场大雨后,由 ...

  5. 关于多线程start()方法原理解读

    1.为什么启动线程不用run()方法而是使用start()方法 run()方法只是一个类中的普通方法,调用run方法跟调用普通方法一样 而start()是创建线程等一系列工作,然后自己调用run里面的 ...

  6. NOIP模拟 7

    考试最后半小时发现T1过不去任何样例,T飞,发现没调用solv函数,挽回40分 考试最后几分钟给T2测了一组自制样例,发现了bug,挽回20分 天- -检查这么重要的么(其实是我第一次打的时候就没验证 ...

  7. python学习之【第十六篇】:Python中的常用模块之OS模块、sys模块、random模块

    1. OS模块 OS模块是与操作系统交互的一个接口.内部提供了以下方法: os.getcwd() 获取当前工作目录,即当前python脚本工作的目录路径 os.chdir("dirname& ...

  8. 19.7.29 NOIP模拟10

    话说这次三道考试题直接可以连成一个段子:我一个辣鸡,连模板都不会打,只能跪倒在大佬面前; T1 辣鸡 但是我实在是太辣鸡了,最后干的T1,时间不够用,连暴力都没打对,无奈之下交了一个qj程序,60分( ...

  9. Medium高赞系列,如何正确的在Stack Overflow提问

    在我们写程序的时候,经常会遇到各色各样的问题,在国内,小伙伴们经常去知乎.CSDN.博客园.思否.安卓巴士等地方提问并获得答案. 这些地方汇集了很多优秀的.爱分享的国内资源.小编比较自豪的一件事情就是 ...

  10. linux-mysql8的安装步骤详解及需要注意的坑

    (本文由言念小文原创,转载请注明出处) 前言 最近安装mysql8时,遇到了一些问题,记录下来作为以后操作指导资料. Linux上mysql安装方法个人目前使用的有两种: 一种是基于rpm安装: 另一 ...