LocalDate.now()是最安全的获取当前日期方式,直接返回系统默认时区下的纯日期对象,避免可变性与时区陷阱;需指定时区时应显式传入Clock,测试中须用fixed Clock注入固定时间。
LocalDate.now() 是最安全的获取当前日期方式
直接返回系统默认时区下的纯日期对象,不含时间、不依赖
手动构造,也避免了
或
带来的可变性和时区陷阱。它内部用的是
,所以只要 JVM 时区设置正确,结果就可靠。
不要手动拼字符串再解析(比如
→
),既多余又容易因格式错报
如果需要指定时区(比如业务强制走 UTC),得显式传入
:
在单元测试中,别让测试依赖真实系统时间——用
注入固定时间点
加减天数用 plusDays/minusDays,别碰 withDayOfMonth
和
是语义清晰、边界安全的操作。比如今天是 3 月 31 日,
自动进到 4 月 1 日;而
会直接抛
,因为 3 月没有 32 号。
加减月份用
/
,它会自动处理“1 月 31 日 + 1 个月 = 2 月 28 日(或 29 日)”这类逻辑
避免混用:不要对
调用
(不存在),那是
的方法
性能上无差别,但可读性差的写法(如
)没必要,除非后续要复用
对象
计算两个 LocalDate 之间相差多少天用 ChronoUnit.DAYS.between
返回的是整数天数差,包含起始日但不包含结束日(左闭右开),结果可正可负。这是唯一推荐的跨日期天数计算方式。
别用
虽然结果一样,但可读性差,且隐藏了“为什么是 epoch day”的认知负担
返回的是年月日三段式对象,如果只关心总天数,反而多绕一层,还可能因闰年/大小月导致误解(比如
不保证
是总天数)
注意参数顺序:
得正数;反过来就是负数,别靠注释猜逻辑
LocalDate 运算后不能忽略「不可变性」这个前提
所有
、
、
方法都返回新对象,原变量不变。这是最容易漏掉的一环,尤其从老 Java 习惯转过来的人。
错误写法:
正确写法:
在流式调用里也要小心:
没问题,但中间没赋值的话,第一步的结果就丢了
如果在循环里反复运算,记得每次接收返回值,否则等于白算
LocalDate 看似简单,但真正卡住人的地方往往不是语法,而是对「不可变」和「语义操作」的下意识忽略——比如以为
是“把今年改成 2025”,其实它只改年份,其他字段照搬,3 月 31 日变成 2025 年 3 月 31 日没问题,但 2 月 30 日就会炸。
LocalDate.now()System.currentTimeMillis()new Date()Calendar.getInstance()Clock.systemDefaultZone()"2024-05-20"LocalDate.parse()DateTimeParseExceptionClockLocalDate.now(Clock.systemUTC())LocalDate.now(Clock.fixed(...))plusDays()minusDays()plusDays(1)withDayOfMonth(32)DateTimeExceptionplusMonths()minusMonths()LocalDateplusHours()LocalDateTimeplus(Period.ofDays(5))PeriodChronoUnit.DAYS.between(start, end)end.toEpochDay() - start.toEpochDay()Period.between(start, end)PeriodgetDays()between(earlier, later)plusXXXminusXXXwithXXXdate.plusDays(7); // date 没变!date = date.plusDays(7);date.plusMonths(1).minusDays(2)withYear(2025)