本文目录导读:

Java 中时间处理的案例非常丰富,涵盖了从早期的 java.util.Date、Calendar 到现代的 java.time(JSR-310)包,现代 Java 开发强烈推荐使用 java.time 包,因为它解决了旧 API 的线程安全、设计混乱等问题。
以下是一些典型的 Java 时间处理案例,按功能分类展示:
核心案例:新旧 API 对比与基础操作
场景:获取当前时间、格式化、解析。
旧 API(不推荐):
// 1. 获取当前时间
Date now = new Date();
System.out.println(now); // 输出:Tue Oct 24 10:30:00 CST 2023
// 2. 格式化(线程不安全)
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String formatted = sdf.format(now);
System.out.println(formatted); // 输出:2023-10-24 10:30:00
// 3. 解析
String dateStr = "2023-10-24 10:30:00";
try {
Date parsed = sdf.parse(dateStr);
} catch (ParseException e) {
e.printStackTrace();
}
新 API(推荐):
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
// 1. 获取当前时间(不可变、线程安全)
LocalDateTime now = LocalDateTime.now();
System.out.println(now); // 输出:2023-10-24T10:30:00
// 2. 格式化
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String formatted = now.format(formatter);
System.out.println(formatted); // 输出:2023-10-24 10:30:00
// 3. 解析
String dateStr = "2023-10-24 10:30:00";
LocalDateTime parsed = LocalDateTime.parse(dateStr, formatter);
关键点:新 API 的 LocalDate、LocalTime、LocalDateTime 是不可变对象,所有操作返回新实例,天然线程安全。
时间计算与操作
场景:加减天数、月份,获取前后日期,计算两个时间的差值。
import java.time.LocalDate;
import java.time.Period;
import java.time.Duration;
import java.time.LocalDateTime;
public class TimeCalculationExample {
public static void main(String[] args) {
// 1. 日期加减
LocalDate today = LocalDate.now();
LocalDate nextWeek = today.plusDays(7);
LocalDate lastMonth = today.minusMonths(1);
LocalDate nextYear = today.plusYears(1);
System.out.println(" " + today);
System.out.println("一周后: " + nextWeek);
// 2. 计算两个日期之间的天数差
LocalDate start = LocalDate.of(2023, 1, 1);
LocalDate end = LocalDate.of(2023, 12, 31);
Period period = Period.between(start, end);
System.out.println("间隔: " + period.getYears() + "年, "
+ period.getMonths() + "月, "
+ period.getDays() + "天");
// 3. 计算两个时间之间的精确秒/毫秒差
LocalDateTime time1 = LocalDateTime.of(2023, 10, 24, 10, 0, 0);
LocalDateTime time2 = LocalDateTime.of(2023, 10, 24, 12, 30, 0);
Duration duration = Duration.between(time1, time2);
System.out.println("时间差: " + duration.toHours() + "小时, "
+ duration.toMinutes() + "分钟");
}
}
关键点:Period 适用于日期(年月日),Duration 适用于时间(时分秒纳秒)。
时区处理
场景:不同时区的时间转换、获取时区时间。
import java.time.ZonedDateTime;
import java.time.ZoneId;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class TimeZoneExample {
public static void main(String[] args) {
// 1. 获取当前时区时间(系统默认时区)
ZonedDateTime nowInLocal = ZonedDateTime.now();
System.out.println("本地时区: " + nowInLocal);
// 2. 获取指定时区时间
ZoneId tokyoZone = ZoneId.of("Asia/Tokyo");
ZonedDateTime nowInTokyo = ZonedDateTime.now(tokyoZone);
System.out.println("东京时间: " + nowInTokyo);
// 3. 时区转换(从北京时间转为纽约时间)
ZoneId beijingZone = ZoneId.of("Asia/Shanghai");
ZoneId newYorkZone = ZoneId.of("America/New_York");
ZonedDateTime beijingTime = ZonedDateTime.of(
LocalDateTime.now(), beijingZone
);
ZonedDateTime newYorkTime = beijingTime.withZoneSameInstant(newYorkZone);
DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss VV");
System.out.println("北京: " + beijingTime.format(format));
System.out.println("纽约: " + newYorkTime.format(format));
}
}
关键点:ZonedDateTime 用于带时区的日期时间,ZoneId 用于标识时区,withZoneSameInstant 用于在不同时区间转换。
与数据库/系统交互
场景:与数据库中的 TIMESTAMP、DATE 类型互转,与旧 java.util.Date 互转。
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;
public class InteropExample {
public static void main(String[] args) {
// 1. LocalDateTime 转 java.util.Date
LocalDateTime localDateTime = LocalDateTime.now();
Instant instant = localDateTime.atZone(ZoneId.systemDefault()).toInstant();
Date date = Date.from(instant);
System.out.println("LocalDateTime -> Date: " + date);
// 2. java.util.Date 转 LocalDateTime
Date legacyDate = new Date();
Instant legacyInstant = legacyDate.toInstant();
LocalDateTime localFromLegacy = LocalDateTime.ofInstant(
legacyInstant, ZoneId.systemDefault()
);
System.out.println("Date -> LocalDateTime: " + localFromLegacy);
// 3. 与数据库交互 (JDBC 4.2+)
// 数据库插入: preparedStatement.setObject(1, LocalDate.now());
// 数据库读取: LocalDate date = resultSet.getObject("column", LocalDate.class);
System.out.println("Java 8+ JDBC 直接支持 LocalDate/LocalDateTime");
}
}
关键点:
- Java 8+ 的 JDBC 驱动直接支持
LocalDate、LocalTime、LocalDateTime类型。 Instant是一个时间线上的瞬时点,可用于与旧 API 互转。
实际业务案例:日历与时间范围
场景:计算某个月有多少天、判断闰年、获取工作日等。
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.temporal.TemporalAdjusters;
public class CalendarExample {
public static void main(String[] args) {
LocalDate today = LocalDate.now();
// 1. 当月第一天和最后一天
LocalDate firstDay = today.with(TemporalAdjusters.firstDayOfMonth());
LocalDate lastDay = today.with(TemporalAdjusters.lastDayOfMonth());
System.out.println("当月第一天: " + firstDay + ", 最后一天: " + lastDay);
// 2. 下个周五
LocalDate nextFriday = today.with(TemporalAdjusters.next(DayOfWeek.FRIDAY));
System.out.println("下周五: " + nextFriday);
// 3. 判断闰年
boolean isLeap = today.isLeapYear();
System.out.println(today.getYear() + " 是闰年吗? " + isLeap);
// 4. 获取当月天数
int daysInMonth = today.lengthOfMonth();
System.out.println("本月有 " + daysInMonth + " 天");
}
}
关键点:TemporalAdjusters 类提供了丰富的日期调整器,如 firstDayOfMonth()、next(DayOfWeek) 等。
常见陷阱与注意事项
案例:线程安全问题(旧 API 失败案例)
// 错误做法(多线程环境下)
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
// 多个线程同时调用 parse() 会抛出异常或产生错误结果
// 正确做法
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
// DateTimeFormatter 是线程安全的
案例:时间精度问题
// java.util.Date 的精度是毫秒 // LocalDateTime 的精度是纳秒 LocalDateTime now = LocalDateTime.now(); System.out.println(now.getNano()); // 输出纳秒部分,如 123456789
| 功能分类 | 推荐使用类 | 旧类(不推荐) | 主要优势 |
|---|---|---|---|
| 日期(无时间) | LocalDate |
java.sql.Date |
清晰、不可变 |
| 时间(无日期) | LocalTime |
java.sql.Time |
清晰、不可变 |
| 日期+时间 | LocalDateTime |
java.util.Date |
不可变、线程安全 |
| 带时区 | ZonedDateTime |
Calendar、TimeZone |
更语义化、易用 |
| 格式化解析 | DateTimeFormatter |
SimpleDateFormat |
线程安全、不可变 |
推荐学习路径:
- 掌握
LocalDate、LocalTime、LocalDateTime的创建与基础运算。 - 学会使用
DateTimeFormatter进行格式化。 - 理解时区概念,使用
ZonedDateTime处理跨时区问题。 - 熟悉
Period和Duration做时间差值计算。 - 了解与数据库和旧系统的互转方式。