规范Java日期时间工具类需用对java.time类型、守住不可变性、规避线程风险、明确语义边界;LocalDate用于纯日期,LocalDateTime用于本地时刻,Instant用于系统交互,ZonedDateTime用于带时区展示;格式器须预编译为static final常量;“开始时间”等逻辑须固化;跨日计算禁用毫秒加减;方法须单一、无副作用、类型明确、异常直抛。

规范封装 Java 日期时间工具类,核心是用对 java.time、守住不可变性、规避线程风险、明确语义边界。不靠堆方法数量,而靠职责清晰和边界严谨。
用对类型,不混用 LocalDate/LocalDateTime/Instant
不同场景必须匹配对应类型,硬套会埋坑:
-
只关心“哪一天”(如生日、排班日、报表日期维度)→ 用
LocalDate,避免带时间引发的零点歧义 -
本地业务时刻(如订单创建时间、日志打点)→ 用
LocalDateTime,但注意它不含时区,不能用于跨系统时间比对 -
系统间交互或精确时间点(如消息时间戳、数据库
TIMESTAMP WITH TIME ZONE字段)→ 必须用Instant,它是 UTC 时间轴上的绝对坐标 - 需要展示给用户看的带时区时间(如会议邀请)→ 用
ZonedDateTime,而不是自己拼字符串或算偏移
格式化与解析必须预编译、线程安全
DateTimeFormatter 是线程安全的,但每次调用 ofPattern() 都新建实例,浪费且易出错:
- 所有常用格式(如
"yyyy-MM-dd"、"yyyy-MM-dd HH:mm:ss")应声明为public static final常量 - 禁止在方法体内 new
SimpleDateFormat或反复调用DateTimeFormatter.ofPattern(...) - 若需动态格式(如参数传入 pattern),应通过缓存(如
ConcurrentHashMap)管理 formatter 实例,避免重复构造
“开始时间”“结束时间”必须明确定义并固化逻辑
业务中高频出现的“某天开始时间”,不是直觉问题,而是契约问题:
立即学习“Java免费学习笔记(深入)”;
- “2026-10-10 的开始时间” =
LocalDate.of(2026, 10, 10).atStartOfDay(ZoneId.systemDefault())→ 转为ZonedDateTime才真正可靠 - 跨日计算(如生成连续日期列表)必须用
LocalDate.plusDays(1),绝不用毫秒加减(+24*60*60*1000),否则夏令时切换时丢天或多天 - 两个日期之间“所有日期”应返回
List<LocalDate>,而非Date或Instant,因为目标是“日粒度”,不是“时刻粒度”
工具方法必须单一、无副作用、可测试
每个 public 方法只做一件事,输入输出明确,不操作静态状态:
- 命名体现意图:如
parseDateOnly(String)、toStartOfDay(LocalDate)、daysBetweenInclusive(LocalDate, LocalDate) - 拒绝“万能方法”:不提供
format(Object o, String pattern)这类泛型模糊接口;类型明确才安全 - 所有方法默认抛出运行时异常(如
DateTimeParseException),不吞异常也不转成 checked exception,让调用方决定如何处理 - 配套写 JUnit 测试,覆盖边界:闰年2月29日、月末(31→1)、跨年、时区夏令时切换日(如北京2026年无夏令时,但欧洲有)
不复杂但容易忽略


















