文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

大厂如何使用Java8日期时间?

2024-12-03 16:18

关注

 1 背景

Java8前,处理日期时间时,使用的“三大件”

以声明时间戳、使用日历处理日期和格式化解析日期时间。但这些类的API可读性差、使用繁琐,且非线程安全,如同设计的翔一样的IO,也是Java让人诟病的一大原因。

于是Java8推出全新日期时间类。这些类的API功能强大简便、线程安全。

但毕竟Java8刚出这些类,诸如序列化、数据访问等类库都不支持Java8日期时间类,需在新老类中来回切换。比如,在业务逻辑层使用LocalDateTime,存入数据库或者返回前端的时候还要切换回Date。因此,还不如沿用老的日期时间类。

不过我们生活在最好的时代,基本主流类库都支持新日期时间类型,但还有项目因还是用祖传日期时间类,出现很多古今交错的错误实践。

比如

本文旨在分析古今时间错乱的本质原因,看看使用遗留日期时间类,来处理日期时间初始化、格式化、解析、计算等可能会遇到的问题,以及如何使用新日期时间类解决。

2 初始化日期时间

初始化2020年11月11日11点11分11秒时间,这样可行吗?

日志输出时间是3029年12月11日11点11分11秒:

  1. date : Sat Dec 11 11:11:11 CST 3920 

这明显是彩笔才会写的垃圾代码,因为

修正上述代码如下:

  1. Date date = new Date(2020 - 1900, 10, 11, 11, 11, 11); 

日志输出:

  1. Mon Nov 11 11:11:11 CST 2019 

当有国际化需求时,又得使用Calendar类初始化时间。

使用Calendar改造后,初始化时年参数直接使用当前年即可,月0~11。亦可直接使用Calendar.DECEMBER初始化月份,肯定不会犯错。

分别使用当前时区和纽约时区初始化两个相同日期:

日志输出

显示两个不同时间,说明时区发生作用。但更习惯年/月/日 时:分:秒日期时间格式,对现在输出的日期格式还不满意,那就格式化日期时间

3 时区问题

全球有24个时区,同一个时刻不同时区(比如中国上海和美国纽约)的时间不同。全球化项目,若初始化时间时未提供时区,那就不是真正意义上的时间,只能认为是我看到的当前时间的一个表示。

3.1 Date类

Date无时区概念,任一机器使用new Date()初始化得到时间相同。因为,Date中保存的是UTC时间,其为以原子钟为基础的统一时间,不以太阳参照计时,无时区划分

Date中保存的是一个时间戳,代表从1970年1月1日0点(Epoch时间)到现在的毫秒数。尝试输出Date(0):

  1. System.out.println(new Date(0)); 
  2. System.out.println(TimeZone.getDefault().getID() + ":" + 
  3.     TimeZone.getDefault().getRawOffset()/3600000); 

得到1970年1月1日8点。我的机器在中国上海,相比UTC时差+8小时:

  1. Thu Jan 01 08:00:00 CST 1970 
  2. Asia/Shanghai:8 

对于国际化项目,处理好时间和时区问题首先就是要正确保存日期时间。

这里有两种

3.2 如何正确保存日期时间

保存的时间无时区属性,不涉及时区时间差问题的世界统一时间。常说的时间戳或Java中的Date类就是这种方式,也是推荐方案

比如年/月/日 时:分:秒,务必同时保存时区信息。有了时区,才能知道该字面量时间真正的时间点,否则它只是一个给人看的时间表示且只在当前时区有意义。

而Calendar才具有时区概念,所以通过使用不同时区初始化Calendar,才能得到不同时间。

正确地保存日期时间后,就是正确展示,即要使用正确时区,将时间点展示为符合当前时区的时间表示。至此也就能理解为何会发生“时间错乱”。

从字面量解析成时间 & 从时间格式化为字面量

对同一时间表示,不同时区转换成Date会得到不同时间戳

比如2020-11-11 11:11:11

对当前上海时区/纽约时区,转化为UTC时间戳不同

  1. Wed Nov 11 11:11:11 CST 2020:1605064271000 
  2. Thu Nov 12 00:11:11 CST 2020:1605111071000 

这就是UTC的意义,并非时间错乱。对同一本地时间的表示,不同时区的人解析得到的UTC时间必定不同,反过来不同本地时间可能对应同一UTC。

格式化后出现的错乱

即同一Date,在不同时区下格式化得到不同时间表示。

在当前时区和纽约时区格式化2020-11-11 11:11:11

输出如下,当前时区Offset(时差)是+8小时,对于-5小时的纽约

因此,有时数据库中相同时间,由于服务器时区设置不同,读取到的时间表示不同。这不是时间错乱,而是时区作用,因为UTC时间需根据当前时区解析为正确的本地时间。

所以要正确处理时区,在于存和读两阶段

Java8处理时区问题

时间日期类ZoneId、ZoneOffset、LocalDateTime、ZonedDateTime和DateTimeFormatter,使用起来更简单清晰。

初始化上海、纽约和东京三时区

可使用ZoneId.of初始化一个标准时区,也可使用ZoneOffset.ofHours通过一个offset初始化一个具有指定时间差的自定义时区。

日期时间表示

因此,LocalDateTime仅是一个时间表示,ZonedDateTime才是一个有效时间。这里将把2020-01-02 22:00:00这个时间表示,使用东京时区解析得到一个ZonedDateTime。

使用DateTimeFormatter格式化时间

可直接通过withZone直接设置格式化使用的时区。最后,分别以上海、纽约和东京三个时区来格式化这个时间输出:

日志输出:相同时区,经过解析存和读的时间表示一样(比如最后一行)

对不同时区,比如上海/纽约,输出本地时间不同。

+9小时时区的晚上10点,对上海时区+8小时,所以上海本地时间为早10点

而纽约时区-5小时,差14小时,为晚上9点

小结

要正确处理国际化时间问题,推荐Java8的日期时间类,即

使用ZonedDateTime保存时间

然后使用设置了ZoneId的DateTimeFormatter配合ZonedDateTime进行时间格式化得到本地时间表示

本文转载自微信公众号「 JavaEdge」,可以通过以下二维码关注。转载本文请联系 JavaEdge公众号。

 

来源:JavaEdge内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯