前言

在我们的日常工作中,需要经常处理各种格式,各种类似的的日期或者时间。


比如:2025-04-21、2025/04/21、2025年04月21日等等。

有些字段是String类型,有些是Date类型,有些是Long类型。


如果不同的数据类型,经常需要相互转换,如果处理不好,可能会出现很多意想不到的问题。

这篇文章跟大家一起聊聊日期处理的常见问题,和相关的解决方案,希望对你会有所帮助。


顺便吆喝一句,技术大厂,前后端/测试[HC] ,待遇还可以,感兴趣试一试。


一、日期的坑

1.1 日期格式化陷阱

在文章的开头,先给大家列举一个非常经典的日期格式化问题:

// 旧代码片段(线程不安全的经典写法)
public class OrderService {

  private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");*

    public void saveOrder(Order order) {
        // 线程A和线程B同时进入该方法
        String createTime = sdf.format(order.getCreateTime()); 
        // 可能出现"2023-02-30 12:00:00"这种根本不存在的日期
        orderDao.insert(createTime);**
    }

}

问题复现场景:

  1. 高并发秒杀场景下,10个线程同时处理订单。
  2. 每个线程获取到的order.getCreateTime()均为2023-02-28 23:59:59。
  3. 由于线程调度顺序问题,某个线程执行sdf.format()时。
  4. 内部Calendar实例已被其他线程修改为非法状态。
  5. 最终数据库中出现2023-02-30这类无效日期。


问题根源:SimpleDateFormat内部使用了共享的Calendar实例,多线程并发修改会导致数据污染。


1.2 时区转换

我们在处理日期的时候,还可能会遇到夏令时转换的问题:

// 错误示范:简单加减8小时
public Date convertToBeijingTime(Date utcDate) {
    Calendar cal = Calendar.getInstance();
    cal.setTime(utcDate);
    cal.add(Calendar.HOUR, 8); // 没考虑夏令时切换问题
    return cal.getTime();
}

夏令时是一种在夏季期间将时间提前一小时的制度,旨在充分利用日光,病节约能源。

在一些国家和地区,夏令时的开始和结束时间是固定的。

而在一些国家和地区,可能会根据需要调整。

在编程中,我们经常需要处理夏令时转换的问题,以确保时间的正确性。


隐患分析:2024年10月27日北京时间凌晨2点会突然跳回1点,直接导致订单时间计算错误


二、优雅方案的进阶之路

2.1 线程安全重构

在Java8之前,一般是通过ThreadLocal解决多线程场景下,日期转换的问题。

例如下面这样:

// ThreadLocal封装方案(适用于JDK7及以下)
public class SafeDateFormatter {
    private static final ThreadLocal<DateFormat> THREAD_LOCAL = ThreadLocal.withInitial(() -> 
        new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
    );

    public static String format(Date date) {
        return THREAD_LOCAL.get().format(date);
    }
}


线程安全原理:

  1. 每个线程第一次调用format()方法时
  2. 会通过withInitial()初始化方法创建独立的DateFormat实例
  3. 后续该线程再次调用时直接复用已有实例
  4. 线程销毁时会自动清理ThreadLocal存储的实例


原理揭秘:通过ThreadLocal为每个线程分配独立DateFormat实例,彻底规避线程安全问题。


2.2 Java8时间API革命

在Java8之后,提供了LocalDateTime类对时间做转换,它是官方推荐的方案。

例如下面这样:

// 新时代写法(线程安全+表达式增强)
public class ModernDateUtils {
    public static String format(LocalDateTime dateTime) {
        return dateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
    }

    public static LocalDateTime parse(String str) {
        return LocalDateTime.parse(str, DateTimeFormatter.ISO_LOCAL_DATE_TIME);
    }
}


黑科技特性

  • 288种预定义格式器
  • 支持ISO-8601/ZonedDateTime等国际化标准
  • 不可变对象天然线程安全

最近就业形势比较困难,为了感谢各位小伙伴对苏三一直以来的支持,我特地创建了一些工作内推群, 看看能不能帮助到大家。

你可以在群里发布招聘信息,也可以内推工作,也可以在群里投递简历找工作

,也可以在群里交流面试或者工作的话题。


转载自:苏三说技术

开源硬件平台

还没有评论,抢个沙发!