1 背景
Java8前,处理日期时间时,使用的“三大件”
- Date
- Calender
- SimpleDateFormat
以声明时间戳、使用日历处理日期和格式化解析日期时间。但这些类的API可读性差、使用繁琐,且非线程安全,如同设计的翔一样的IO,也是Java让人诟病的一大原因。
于是Java8推出全新日期时间类。这些类的API功能强大简便、线程安全。
但毕竟Java8刚出这些类,诸如序列化、数据访问等类库都不支持Java8日期时间类,需在新老类中来回切换。比如,在业务逻辑层使用LocalDateTime,存入数据库或者返回前端的时候还要切换回Date。因此,还不如沿用老的日期时间类。
不过我们生活在最好的时代,基本主流类库都支持新日期时间类型,但还有项目因还是用祖传日期时间类,出现很多古今交错的错误实践。
比如
- 通过随意修改时区,使读取到的数据匹配当前时钟
- 直接对读取到的数据做加、减几个小时的操作,来“修正数据”
本文旨在分析古今时间错乱的本质原因,看看使用遗留日期时间类,来处理日期时间初始化、格式化、解析、计算等可能会遇到的问题,以及如何使用新日期时间类解决。
2 初始化日期时间
- 初始化2020年11月11日11点11分11秒时间,这样可行吗?
- 日志输出时间是3029年12月11日11点11分11秒:
date : Sat Dec 11 11:11:11 CST 3920
这明显是彩笔才会写的垃圾代码,因为
- 年应该是和1900差值
- 月应该是 0~11 而非 1~12
- 时应该是 0~23,而非 1~24
- 修正上述代码如下:
Date date = new Date(2020 - 1900, 10, 11, 11, 11, 11);
- 日志输出:
Mon Nov 11 11:11:11 CST 2019
当有国际化需求时,又得使用Calendar类初始化时间。
使用Calendar改造后,初始化时年参数直接使用当前年即可,月0~11。亦可直接使用Calendar.DECEMBER初始化月份,肯定不会犯错。
- 分别使用当前时区和纽约时区初始化两个相同日期:
- 日志输出
- 显示两个不同时间,说明时区发生作用。但更习惯年/月/日 时:分:秒日期时间格式,对现在输出的日期格式还不满意,那就格式化日期时间