还记得刚学 Java 时被Date支配的恐惧吗?
Java 8 之前的日期处理,就像一场没有地图的冒险,而LocalDate/LocalTime的出现,终于给了程序员一张高清导航图。
特性 |
传统 Date/SimpleDateFormat |
Java 8 新特性 (LocalDate/LocalTime) |
设计理念 |
可变对象,时区隐藏 |
不可变对象,时区显式处理 |
月份表示 |
0-11 的反人类设计 |
1-12 的正常人类逻辑 |
线程安全 |
非线程安全,并发必翻车 |
线程安全,可放心在多线程环境使用 |
功能丰富度 |
格式化靠拼接,计算靠数学公式 |
内置plusDays/minusMonths等语义化方法 |
时区处理 |
全靠自觉,一不小心就成 "国际玩笑" |
ZoneId/ZonedDateTime明确时区,妈妈再也不用担心我搞乱时差 |
举个栗子:用传统方式计算 "3 天后的日期":
Date today = new Date();
Calendar calendar = Calendar.getInstance();
calendar.setTime(today);
calendar.add(Calendar.DAY_OF_MONTH, 3);
Date result = calendar.getTime(); // 每次写都要祈祷别搞反年月日
用新特性:
LocalDate today = LocalDate.now();
LocalDate threeDaysLater = today.plusDays(3); // 像说人话一样写代码,爽!
场景 1:把 "2023-10-01" 转成 "2023 年 10 月 01 日 星期六"
LocalDate date = LocalDate.of(2023, 10, 1);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日 E");
String result = date.format(formatter); // 输出:2023年10月01日 星期日
注意:MM是两位月份,M是一位;dd是两位日期,d是一位,强迫症患者的福音。
场景 2:解析 "2023/10/01" 这种非标准格式
String str = "2023/10/01";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy/MM/dd");
LocalDate date = LocalDate.parse(str, formatter); // 再也不用手动分割字符串啦!
场景 1:计算 "从今天起 100 天后是星期几"
LocalDate today = LocalDate.now();
LocalDate future = today.plusDays(100);
DayOfWeek dayOfWeek = future.getDayOfWeek(); // 直接获取枚举值,比如MONDAY/TUESDAY
System.out.println("100天后是:" + dayOfWeek); // 输出:WEDNESDAY(假设今天是周日)
场景 2:计算两个日期相差多少天 / 月 / 年
LocalDate birthDate = LocalDate.of(1990, 1, 1);
LocalDate now = LocalDate.now();
Period period = Period.between(birthDate, now);
System.out.println("年龄:" + period.getYears() + "岁" + period.getMonths() + "个月" + period.getDays() + "天");
// 输出:比如33岁9个月15天(根据当前时间变化)
场景:把北京时间 "2023-10-01 12:00" 转为纽约时间
ZoneId beijingZone = ZoneId.of("Asia/Shanghai");
ZoneId newYorkZone = ZoneId.of("America/New_York");
ZonedDateTime beijingTime = ZonedDateTime.of(2023, 10, 1, 12, 0, 0, 0, beijingZone);
ZonedDateTime newYorkTime = beijingTime.withZoneSameInstant(newYorkZone);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm z");
System.out.println(newYorkTime.format(formatter)); // 输出:2023-09-30 23:00 America/New_York
知识点:withZoneSameInstant是瞬间转换(物理时间不变),withZoneSameLocal是本地时间转换(可能产生夏令时问题)。
反模式:if (date != null) date.getYear();( NullPointerException 警告!)正解:用Optional包裹,或者在 API 中明确要求非 null:
public void processDate(LocalDate date) {
// 编译器会强制调用者处理null,比传统Date安全10086倍
}
比如美国夏令时结束时,时钟回拨 1 小时,会出现重复的时间。解决方案:使用ZoneRules检查时间是否有效:
ZoneId zone = ZoneId.of("America/Chicago");
LocalDateTime ambiguousTime = LocalDateTime.of(2023, 11, 5, 1, 30);
ZoneRules rules = zone.getRules();
if (rules.isValidLocalDateTime(ambiguousTime)) {
// 处理有效时间
} else {
// 处理重复时间(通常加1小时)
}
推荐:
从被Date虐到怀疑人生,到用LocalDate优雅处理时间,Java 8 的新特性简直是程序员的救星。记住三个核心类:
下次再有人让你处理 "2020 年 2 月 30 日" 这种反人类需求,记得甩出DateTimeException异常:"对不起,Java 不支持穿越到不存在的日期哦~"
赶紧抛弃古老的Date吧,让代码像时间一样,流淌得优雅而有序~