Servlet 处理日期

java.time 的格式化、解析、时区,以及和旧 Date 的互转。

Beginner
Key Points新代码一律用 java.time:LocalDate 表示日期,Instant 表示时刻,格式化用线程安全的 DateTimeFormatter。

三个核心类型

TypeHoldsUse when
LocalDate年月日生日、账单日
LocalTime时分秒营业时间
LocalDateTime年月日时分秒,无时区页面展示
InstantUTC 瞬间存储、比较、日志
ZonedDateTime瞬间 + 时区跨时区换算

格式化与解析

Java
import java.time.*;
import java.time.format.DateTimeFormatter;

DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

LocalDateTime now = LocalDateTime.now();
String s = now.format(fmt);                     // 2026-11-03 14:25:09
LocalDateTime back = LocalDateTime.parse(s, fmt);

// 页面里常用的中文格式
DateTimeFormatter cn = DateTimeFormatter.ofPattern("yyyy年M月d日");
System.out.println(LocalDate.of(2026, 11, 3).format(cn));
Output
2026-11-03 14:25:09
2026年11月3日

DateTimeFormatter is immutable and thread-safe, so a static final constant is fine. The legacy SimpleDateFormat is not, and sharing one across threads corrupts parses — a very subtle bug in old code.

时区

Java
ZoneId shanghai = ZoneId.of("Asia/Shanghai");
ZoneId utc = ZoneId.of("UTC");

ZonedDateTime local = ZonedDateTime.now(shanghai);
ZonedDateTime sameMoment = local.withZoneSameInstant(utc);
System.out.println(local);           // 2026-11-03T14:25:09+08:00[Asia/Shanghai]
System.out.println(sameMoment);      // 2026-11-03T06:25:09Z[UTC]
Store timestamps in UTC (an Instant or a timezone-aware column) and convert only for display. Storing local time breaks DST and cross-timezone users, and cannot be repaired later.

与旧 API 互转

Java
// java.util.Date <-> Instant
Date legacy = Date.from(Instant.now());
Instant instant = legacy.toInstant();

// java.sql.Date / Timestamp <-> java.time
java.sql.Date sqlDate = java.sql.Date.valueOf(LocalDate.now());
LocalDate d = sqlDate.toLocalDate();
Timestamp ts = Timestamp.valueOf(LocalDateTime.now());
LocalDateTime ldt = ts.toLocalDateTime();

计算差值

Java
LocalDate a = LocalDate.of(2026, 1, 31);
LocalDate b = LocalDate.of(2026, 11, 3);

Period period = Period.between(a, b);
System.out.println(period.getMonths() + " 个月 " + period.getDays() + " 天");

long days = ChronoUnit.DAYS.between(a, b);
System.out.println("相差 " + days + " 天");
Output
9 个月 3 天
相差 276 天

Period is a calendar difference (years, months, days); ChronoUnit.DAYS.between gives total days. Use the former for ages, the latter for countdowns — mixing them yields plausible but wrong numbers.

Friends & Partners