1. Java传统日期时间API概述如果你在2014年之前写过Java程序肯定对java.util.Date这个类不陌生。那时候我们要获取当前时间通常会这样写Date now new Date(); System.out.println(now); // 输出Tue Jun 25 14:30:45 CST 2024这个输出看起来还算直观但当你真正开始处理日期计算、格式化等操作时就会发现这套API设计得非常反人类。我在早期项目中踩过不少坑比如月份从0开始计数1月是012月是11年份从1900年开始计算Date对象既包含日期又包含时间但时间处理非常麻烦线程安全问题让人头疼后来JDK 1.1引入了Calendar和DateFormat试图解决这些问题但它们又带来了新的复杂性。直到Java 8才推出了全新的java.time包官方也正式将Date/Calendar标记为不推荐使用。2. Date类简单但问题重重2.1 Date的基本用法Date类最常用的两个构造方法// 无参构造获取当前时间 Date now new Date(); // 带long参数构造根据毫秒数创建日期 Date specificTime new Date(0L); // 1970-01-01 08:00:00 (东八区)这里有个坑Date的toString()输出格式是固定的英文格式而且时区显示为CSTChina Standard Time这在需要本地化显示时会很麻烦。2.2 常见陷阱陷阱1年份计算Date date new Date(124, 5, 25); // 2024年6月25日注意这里的年份参数124表示20241900124月份参数5表示6月0-based。这种反直觉的设计很容易出错。陷阱2可变性Date date new Date(); long time date.getTime(); date.setTime(time 1000); // 修改了原始对象Date对象是可变的这在多线程环境下非常危险。我在一个Web项目中就遇到过因为共享Date对象导致的线程安全问题。3. DateFormat格式化与解析3.1 SimpleDateFormat使用由于Date的toString()格式固定我们通常用SimpleDateFormat来格式化SimpleDateFormat sdf new SimpleDateFormat(yyyy-MM-dd HH:mm:ss); String formatted sdf.format(new Date()); // 输出2024-06-25 14:30:453.2 线程安全问题重要警告SimpleDateFormat不是线程安全的下面的代码在多线程环境下会出问题// 错误的共享实例写法 private static final SimpleDateFormat SDF new SimpleDateFormat(yyyy-MM-dd); // 正确做法是每个线程创建独立实例或者使用ThreadLocal private static final ThreadLocalSimpleDateFormat threadLocalSdf ThreadLocal.withInitial(() - new SimpleDateFormat(yyyy-MM-dd));我曾经在Spring MVC项目中使用共享的SimpleDateFormat实例结果在高并发时出现了日期解析错乱的问题。3.3 解析严格性默认情况下SimpleDateFormat的解析是宽松的SimpleDateFormat sdf new SimpleDateFormat(yyyy-MM-dd); Date date sdf.parse(2024-02-30); // 会自动转换为2024-03-01如果希望严格校验日期有效性需要设置sdf.setLenient(false); // 这时解析2024-02-30会抛出ParseException4. Calendar类更强大的日期操作4.1 Calendar基础Calendar解决了Date的一些设计缺陷提供了更丰富的日期字段操作Calendar cal Calendar.getInstance(); int year cal.get(Calendar.YEAR); int month cal.get(Calendar.MONTH) 1; // 仍然要1 int day cal.get(Calendar.DAY_OF_MONTH);4.2 日期计算Calendar的add方法可以方便地进行日期加减Calendar cal Calendar.getInstance(); cal.add(Calendar.DAY_OF_MONTH, 7); // 加7天 cal.add(Calendar.MONTH, -1); // 减1个月4.3 时区处理Calendar比Date更好的时区支持Calendar cal Calendar.getInstance(); cal.setTimeZone(TimeZone.getTimeZone(America/New_York));5. 新旧API对比与迁移建议虽然Java 8已经推出多年但很多遗留系统仍然在使用这些传统API。以下是迁移建议Date → Instant// 旧代码 Date date new Date(); // 新代码 Instant instant Instant.now();Calendar → ZonedDateTime// 旧代码 Calendar cal Calendar.getInstance(); // 新代码 ZonedDateTime zdt ZonedDateTime.now();SimpleDateFormat → DateTimeFormatter// 旧代码 SimpleDateFormat sdf new SimpleDateFormat(yyyy-MM-dd); // 新代码 DateTimeFormatter dtf DateTimeFormatter.ofPattern(yyyy-MM-dd);如果你正在维护老系统理解这些传统API的设计缺陷和正确用法仍然非常重要。特别是在面试中面试官经常会考察你对这些历史问题的理解程度。