simpledateformat格式_大厂都是怎么用Java8代替SimpleDateFormat?
点击上方“JavaEdge”,关注公众号
设为“星标”,好文章不错过!
1 SimpleDateFormat 之坑
1.1 格式化
1.1.1 案例
初始化一个Calendar,设置日期2020年12月29日
日志
这是由于混淆SimpleDateFormat的各种格式化模式:
小写y是年
大写Y是week year,即所在的周属于哪一年
一年第一周的判断方式
从getFirstDayOfWeek
()开始,完整的7天,并且包含那一年至少getMinimalDaysInFirstWeek
()天。
该计算方式和区域相关,对zh_CN
区域,2020年第一周条件:从周日开始的完整7天,2020年包含1天即 可。显然,2019年12月27日周日到2020年1月2日周六是2020年第一周,得出的week year就是2021年。
若把区域改为法国
Locale.setDefault(Locale.FRANCE);
则week yeay就还是2020年,因为一周的第一天从周一开始算,2020年的第一周是2019年12月28日周一开始,27日还是属于去年:
小结
无特殊需求,针对年份的日期格式化,应该一律使用 “y” 而非 “Y”。
线程安全问题
使用一个100线程的线程池,循环20次把时间格式化任务提交到线程池处理,每个任务中又循环10次解析2020-01-01 11:12:13这样一个时间表示:
运行程序后大量报错,即使没有报错的输出结果也不正常,比如2020年解析成57728年
SimpleDateFormat 用于定义解析和格式化日期时间的模式。看起来是一次性工作,应该复用,但它的解析和格式化操作都非线程安全。
分析源码
SimpleDateFormat继承自DateFormat,DateFormat有字段Calendar;
SimpleDateFormat#parse
调用CalendarBuilder#establish
构建Calendar
establish方法内部先清空Calendar再构建Calendar,整个操作没有加锁。
显然,若使用线程池调用parse,即多线程并发操作一个Calendar,就可能会产生一个线程还没来得及处理Calendar就被另一个线程清空。format方法同理,不再赘述。因此只能在同一个线程复用SimpleDateFormat,
解决方案
通过ThreadLocal来存放SimpleDateFormat:
日志输出全部正确
1.2 当需要解析的字符串和格式不匹配,SimpleDateFormat还是能得到结果
案例
使用yyyyMM解析20160901字符串:
居然输出2112年,这是因为把 1111当成月份
对于SimpleDateFormat的这些坑,使用Java 8中的DateTimeFormatter即可避免。
2 Java 8中的DateTimeFormatter
2.1 格式化字符串
首先,使用DateTimeFormatterBuilder定义格式化字符串,无需死记大写Y还是小写y,大写M还是小写m:
2.2 线程安全
可定义为static使用
2.3 待解析字符串和格式不匹配时就报错
日志
2020/11/11 11:11:11.789Exception in thread "main" java.time.format.DateTimeParseException: Text '20201111' could not be parsed at index 0 at java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:1949) at java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1777) at org.javaedge.time.commonmistakes.datetime.dateformat.CommonMistakesApplication.better(CommonMistakesApplication.java:96) at org.javaedge.time.commonmistakes.datetime.dateformat.CommonMistakesApplication.main(CommonMistakesApplication.java:47)
3 Java8计算日期时间
有人喜欢使用时间戳进行计算,比如希望得到当前时间后30天:把
new Date().getTime
得到的时间戳加30天对应毫秒数得到的日期居然比当前日期还要早,根本不是后30天
因为int发生了溢出!。
应将30改为30L,使其为long:
正确输出
Java 8前代码,建议使用Calendar:
使用Java 8的日期时间类型,可以直接进行各种计算,更加简洁和方便:
对日期时间做计算操作,日期时间API会比Calendar功能强大很多。
3.1 minus/plus直接对日期加减
3.2 with快捷时间调节
TemporalAdjusters.firstDayOfMonth得到当前月的第一天
TemporalAdjusters.firstDayOfYear()得到当前年的第一天
TemporalAdjusters.previous(DayOfWeek.SATURDAY)得到上一个周六
TemporalAdjusters.lastInMonth(DayOfWeek.FRIDAY)得到本月最后一个周五
3.3 使用lambda自定义的时间调整
为当前时间增加100天以内的随机天数:
判断日期是否符合某个条件
query查询是否匹配条件
使用Java 8操作和计算日期时间虽然方便,但计算两个日期差时可能会踩坑:Java 8中有一个专门的类Period定义了日期间隔,通过Period.between得到了两个LocalDate的差,返回的是两个日期差几年零几月零几天。
如果希望得知两个日期之间差几天,直接调用Period的getDays()方法得到的只是最后的“零几天”,而不是算总的间隔天数。
比如,计算2020年12月12日和2020年10月1日的日期间隔,很明显日期差是2个月零11天,但获取getDays方法得到的结果只是11天,而不是72天:
可使用ChronoUnit.DAYS.between解决这个问题:
4 总结
也许你认为java.util.Date
类似于新API中的LocalDateTime
。其实不是,虽然它们都没时区概念
java.util.Date类是因为使用UTC表示,所以没有时区概念,其本质是时间戳
LocalDateTime,严格上可以认为是一个日期时间的表示,而不是一个时间点
因此,在把Date转换为LocalDateTime的时候,需要通过Date的toInstant方法得到一个UTC时间戳进行转换,并需要提供当前的时区,这样才能把UTC时间转换为本地日期时间(的表示)。反过来,把LocalDateTime的时间表示转换为Date时,也需要提供时区,用于指定是哪个时区的时间表示,也就是先通过atZone方法把LocalDateTime转换为ZonedDateTime,然后才能获得UTC时间戳:
Date in = new Date();LocalDateTime ldt = LocalDateTime.ofInstant(in.toInstant(), ZoneId.systemDefault());Date out = Date.from(ldt.atZone(ZoneId.systemDefault()).toInstant());
有人说新API很麻烦,还需要考虑时区,真麻烦。但并非因为API强行设计繁琐,而是UTC时间要变为当地时间,必须考虑时区!
往期推荐
大厂如何解决数值精度/舍入/溢出问题
大厂数据库事务实践-事务生效就能保证正确回滚?
线上问题事迹(一)数据库事务居然都没生效?
硬核干货:HTTP超时、重复请求必见坑点及解决方案
给大忙人们看的Java NIO教程之Channel
目前交流群已有 800+人,旨在促进技术交流,可关注公众号添加笔者微信邀请进群
喜欢文章,点个“在看、点赞、分享”素质三连支持一下~
simpledateformat格式_大厂都是怎么用Java8代替SimpleDateFormat?相关推荐
- 查询两个日期间隔天数怎么算_大厂都是怎么用Java8代替SimpleDateFormat?
1 SimpleDateFormat 之坑 1.1 格式化 1.1.1 案例 初始化一个Calendar,设置日期2020年12月29日 日志 这是由于混淆SimpleDateFormat的各 ...
- simpledateformat格式_如何使用SimpleDateFormat?
SimpleDateFormat是一种比较常用的时间类,可以实现对时间按照一定的字符串格式进行处理. ·DateFormat类的作用 把时间对象转化成指定格式的字符串.反之,把指定格式的字符串转化成时 ...
- simpledateformat 毫秒_阿里巴巴 | 为啥代码中禁用static修饰SimpleDateFormat?
来自:8rr.co/4KkS 在项目开发过程中经常遇到时间处理,但是你真的用对了吗,理解阿里巴巴开发手册中禁用static修饰SimpleDateFormat吗? 通过阅读本篇文章你将了解到: 为什么 ...
- 互联网一二线大厂名单_为什么字节跳动、阿里巴巴、腾讯等互联网大厂都喜欢拿金融牌照...
前言 据说字节跳动也开始坐实了一张第三方支付牌照,感觉第三方支付牌照目前对于互联网大厂而言,基本上已经是标配了.除去第三方支付牌照,小贷.消费金融.银行.保险经纪和基金销售等等一系列金融相关的一线或二 ...
- 腾讯视频下载格式_怎么下载腾讯视频
不管这个腾讯视频好用与否,都有一大批用户,本文播放器家园网小编分享腾讯视频下载格式_怎么下载腾讯视频.腾讯视频时刻为您推荐最新最火的视频,精彩不断随时观看.支持各种画质的下载,没网也能享受高视觉的享受 ...
- Office文档上传后实时转换为PDF格式_图片文件上传后实时裁剪_实现在线预览Office文档
Office文档上传后实时转换为PDF格式_图片文件上传后实时裁剪 前置条件 安装LibreOffice 安装OpenOffice 安装Unoconv 安装ImageMagick.x86_64 安装G ...
- 超详细解析|大厂都在用的设计提效神器 Design Toke
设计从来不是一成不变的东西.优秀的设计师往往都明白一个道理:想要通过一劳永逸的设计创造一个伟大产品是不现实的.设计存在的终极目的是解决问题,市场在不断的变化,那么设计也会随之不断的适应和更迭,所以怎样 ...
- SimpleDateFormat格式
错误使用SimpleDateFormat导致时间显示错误 SimpleDateFormat格式 SimpleDateFormat格式 我每次从数据库读存入的时间,然后new Date(longTime ...
- 为什么大厂都用DevOps呢?我来告诉你
目前很多大厂如阿里.腾讯.百度.头条.滴滴.美团等公司内部都在做DevOps,那么 DevOps是什么 ? 为什么大厂都对其趋之若鹜 ? DevOps到底应该怎么做 ?刚好我也负责我们公司的DevOp ...
最新文章
- 北大发布最新《图神经网络推荐系统》2020综述论文,27页pdf
- csv data set config使用介绍
- 关于C#(ASP.net)存取MySQL LongText字段的心得[转]
- Spring 2.5架构图
- 将数据导入到mysql_06955.10.2如何将CM的外部PostgreSQL数据库迁移至MySQL服务
- php 读取页面全部变量,PHP-如何从外部文件获取“页面”变量?
- 牛客14718 开心的涂刷
- bzoj5406: Gift
- Python中字符串格式化输出的学习笔记
- input限制输入字符
- ElasticSearch - 学习
- CSS的position属性
- 【140815】VC编程技巧280例 电子书下载
- Windows--IOmeter测试网络
- dd如何查找单位蓝牙机子mac地址和raw数据
- 双网口设备 网关设置注意事项
- 系统web服务器配置,简单介绍Web服务器的配置方法
- 最简解决方案--安装ubuntu 遇到32位 EFI(UEFI) /EFI/BOOT/bootia32.efi unavilable
- 【20221205】Windows系统反斜杠(倒斜杠 \ )和 Linux系统正斜杠(斜杠 / )
- C++从freshman到老油条(1)——基础知识
热门文章
- resnet18 结构
- Dangling meta character '?' near index 0
- linux c++ 实现http请求
- 打开帧率显示_2K165hz IPS屏,微星MAG274QRF-QD显示器
- linux驱动编写(声卡驱动之asoc移植)
- 郑州大学计算机专业本科毕业去向,河南6所高校毕业生月薪公布 :河大最高 郑大垫底...
- linux登录用户目录,linux命令
- linux ps指令查看进程,linux下查看进程指令-ps
- dwr框架查看外放方法_先睹为快!IntelliJ IDEA v2019.3带来的新框架和新技术
- python中的优化器有哪些_Python SciPy 优化器(Optimizers)