工作这么久了,对于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-02T13:20:20

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)

// 打印结果:2019-12-02T14:43:00.402Z

三, 时间间隔(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中的无锁并发策略可以分为三种:

基于乐观锁的CAS操作

Copy On Write:写时复制是指:在并发访问的情景下,当需要修改JAVA中Containers的元素时,不直接修改该容器,而是先复制一份副本,在副本上进行修改。修改完成之后,将指向原来容器的引用指向新的容器(副本容器)

ThreadLocal:线程本地存储,就是为每一个线程创建一个变量,只有本线程可以在该变量中查看和修改值。

8.2 Question

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

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

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

java8 时间加一秒_都9012了,Java8中的日期时间API你还没有掌握?相关推荐

  1. java8 时间加一秒_年货买瓜子有讲究!这些加了“料”的瓜子不安全!

    还有不到一个月的时间 就是春节假期 不少人都开始置办年货了 过年一家老小围坐在一起 边嗑瓜子边唠嗑 是不少家庭的日常动作 瓜子可以说是最常见 最受欢迎的年货之一了 它不但含有丰富的不饱和脂肪酸 及维生 ...

  2. mysql 日期循环_如何在mysql存储过程中循环日期时间

    即时通讯使用mysql存储过程,如何制作一个循环,每1小时变量strathour将有1小时的间隔然后返回查询的总数.当starthour小于11月的日期时,它将具有1小时的间隔并执行查询. 这是我的代 ...

  3. 深入JavaScript与.NET Framework中的日期时间(1):基本概念与概述

    日期时间是开发过程中最尝使用的数据类型之一,但是很多开发人员在使用过程中忽视了时间日期的一些特性.现在的应用越来越讲究"国际化"和"本地化",它们的重要特征之一 ...

  4. python时间函数纳秒_在Python中以秒和纳秒获取POSIX / Unix时间?

    我一直在努力找到一种方法来获取自1970-01-01 00:00:00 UTC以来的时间,以秒为单位,在python中以纳秒为单位,我找不到能给我正确精度的任何东西. 我尝试过使用时间模块,但是精度只 ...

  5. qt mysql 系统时间_使用QT和参数在SQLite数据库中插入日期时间

    我想从C++/QT应用程序执行插入到SQLite数据库. 我想要插入数据的表格中的一列是datetime(yyyy-mm-dd hh:mm:ss).使用QT和参数在SQLite数据库中插入日期时间 我 ...

  6. MySQL中常用日期时间函数及获得

    MySQL中常用日期时间函数: 下面的查询选择了所有记录,其date_col的值是在最后30天以内: mysql> SELECT something FROM table WHERE TO_DA ...

  7. SQL Server中的日期时间类型

    一. 数据类型 SQL Server008在上一个版本的基础上把日期时间类的数据类型增加到了六个.除了SQL Server2005的datetime和smalltime之外,加了date,dateti ...

  8. mysql 时间字符串 1_Mysql 中的日期时间字符串查询

    一.将数据库中的Date格式的数据,或者指定日期的字符串格式化为想要的样式 DATE_FORMAT (date, format)能根据格式串format 格式化日期或日期和时间值date,返回结果字符 ...

  9. mysql中所有时间类型_MySQL 中的日期时间类型

    INSERT INTO todo (title,created_on) VALUES ('blah','2019-09-31'); ERROR 1292 (22007): Incorrect date ...

  10. mysql根据时间回退_MySQL 中的日期时间类型

    日期时间类型中包含以下几种数据类型: 各类型都有具体的取值范围,超出或非法的其他值时,MySQL 会回退到 0.TIMESTAMP 类型是个例外,给它设置一个超出范围的值时,将保存上该类型允许的最大值 ...

最新文章

  1. 可持久化Trie+堆优化 OR Trie树上求XOR第K大 ---- P5283 [十二省联考2019]异或粽子
  2. java 按顺序取出json_java取json 的方法
  3. 在线富文本编辑器 UMeditor
  4. python ip动态代理_Python 爬虫设置动态代理
  5. 1001:Hello,World!
  6. Xamarin中国技术社区及BXUG官网上线啦
  7. 接口自动化- 基于 Python
  8. linux jobs
  9. Makefile:Makefile中的调试打印方法
  10. 59. DNS 服务器
  11. Linux下调用wps的Tables接口,WPS二次开发简单示例
  12. Windows 11彻底禁用IE浏览器后,银行网银系统完全解决方案!
  13. mediawiki修改用mysql数据库_MediaWiki定制化改动
  14. MAK VR-Forces 3.7
  15. HDUOJ 1069 Monkey and Banana
  16. Latex 表格的模版笔记
  17. 基于FPGA的视频图像拼接融合(附源码)。
  18. 线阵ccd模块LCAMV8-S11639-01/S11638高灵敏线阵图像传感器模组、驱动板
  19. 一文带您读懂FCC、CE、CCC认证的区别
  20. 多个Serial.print拼成一条Serial.print省时间吗?

热门文章

  1. Steam Deck 游戏掌机可运行 Windows
  2. 惠普打印机如何取消任务
  3. 文章同一位置引用多篇参考文献标注方法
  4. PHP计算比较两段文字内容的重复率
  5. Egret(引擎篇)
  6. 计算机id换系统会变吗,小雷问答丨手机恢复出厂设置后会变成最原始的系统吗?...
  7. Java数据通讯中使用Googgle Protobuf 序列化与反序列化
  8. 稳压二极管和TVS管知识点总结
  9. Java计算组合数以及生成组合排列
  10. 200行Python代码实现B站UP主小助手(显示视频播放数、粉丝数等)