【本人秃顶程序员】求求你别用SimpleDateFormat了!

←←←←←←←←←←←← 快!点关注

前言


啊哈哈,标题写的比较随意了,其实呢最近在各种面试以及博客中,SimpleDateFormat出镜率确实是比较高了,为什么?其实聪明的你们肯定知道,那必须是有坑呗,是的,那我们就以案例来分析一下到底会有那些坑,或者还有没有其他更优的替代方案呢?

正文


首先我们来看一下可能会出现在DateUtils中的写法:

private static final SimpleDateFormat dayFormat = new SimpleDateFormat("yyyy-MM-dd  HH:mm:ss");
public static Date formatDate(String date) throws ParseException {
	return dayFormat.parse(date);
}

当我们在单线程的程序中调用 formatDate(date) ,此时并不会出现任何问题(如果这也出问题那还玩什么…) ,然而当我们的程序在多线程并发执行调用这个方法的时候。

ExecuterService es = ExecuterService.newFixedThreadPool(50);
for ( ... ){
	es.execute( () -> {
		System.out.println(parse("2018-11-11 10:35:20"));
	}
	)
}

此时你会发现打印出来的时间有些是错误,程序甚至会抛出异常NumberFormatException??为什么会出现这种情况呢?我们可以直接查看SimpleDateFormat.parse() 方法的源码一探究竟。

private StringBuffer format(Date date, StringBuffer toAppendTo,
     FieldDelegate delegate) {
	// Convert input date to time field list
	calendar.setTime(date);
	Boolean useDateFormatSymbols = useDateFormatSymbols();
	for (int i = 0; i < compiledPattern.length; ) {
		int tag = compiledPattern[i] >>> 8;
		int count = compiledPattern[i++] & 0xff;
		if (count == 255) {
			count = compiledPattern[i++] << 16;
			count |= compiledPattern[i++];
		}

从源码可以看到,在多线程的环境中,执行到第五行 calendar进行操作的时候,后面的线程有可能会覆盖上一个线程设置好的值,此时就导致前面线程执行的结果被覆盖而返回了一个错误的值。

那我们该如何避免这个坑呢?

1、使用ThreadLocal,每个线程中返回各自的实例,避免了多线程环境中共用同一个实例而导致的问题

private static ThreadLocal<SimpleDateFormat> simpleDateFormatThreadLocal = new ThreadLocal<>();
public static Date formatDate(String date) throws ParseException {
	SimpleDateFormat dayFormat = getSimpleDateFormat();
	return dayFormat.parse(date);
}
private static SimpleDateFormat getSimpleDateFormat() {
	SimpleDateFormat simpleDateFormat = simpleDateFormatThreadLocal.get();
	if (simpleDateFormat == null){
		simpleDateFormat = new SimpleDateFormat("yyyy-mm-dd  HH:mm:ss");
		simpleDateFormatThreadLocal.set(simpleDateFormat);
	}
	return simpleDateFormat;
}

需要注意一点的是,ThreadLocal的使用过程中也是有小坑需要注意的,大家可以参考一下其他的资料,以后可以抽空聊聊这个话题。

2、推荐升级到JDK8+,使用LocalDateTime,LocalDate,LocalTime来代替,具体的用法请自行参考API,当然JDK8所带来的Lambda,Stream等特性也是值得一试的

3、使用三方包,推荐Joda-Time,对于日期的增减操作也是相当便捷

读者福利:


分享免费学习资料

针对于Java程序员,我这边准备免费的Java架构学习资料(里面有高可用、高并发、高性能及分布式、Jvm性能调优、MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多个知识点的架构资料)

为什么某些人会一直比你优秀,是因为他本身就很优秀还一直在持续努力变得更优秀,而你是不是还在满足于现状内心在窃喜!希望读到这的您能点个小赞和关注下我,以后还会更新技术干货,谢谢您的支持!

资料领取方式:加入Java技术交流群963944895点击加入群聊,私信管理员即可免费领取

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SimpleDateFormat类本身并不能直接求解时间差。它是一个用于日期格式化和解析的类,用于将日期对象转换为指定格式的字符串,或者将字符串解析为日期对象。要计算时间差,你可以使用Date类的getTime()方法将日期对象转换为毫秒数,然后进行计算。下面是一个示例代码: SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm"); Date startDate = sdf.parse("2003/05/09 00:00"); Date endDate = sdf.parse("2015/01/26 00:00"); long startTime = startDate.getTime(); long endTime = endDate.getTime(); long timeDifference = endTime - startTime; 请注意,这个方法计算的是毫秒级别的差值,如果需要以天、小时、分钟等单位表示时间差,你可以将毫秒数转换为相应的单位。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [Java计算时间差、日期差总结](https://blog.csdn.net/sy793314598/article/details/79544796)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [Android利用SimpleDateFormat计算时间差获得消耗时长](https://blog.csdn.net/ymtianyu/article/details/106661826)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值