本文目录导读:

在Java中处理日期和时间,根据你使用的Java版本,主要有三套方案。强烈建议新项目使用 java.time 包(Java 8+),因为它设计更优秀、线程安全且操作方便。
以下是完整的处理指南和实战案例。
核心方案:java.time 包 (Java 8+)
这是现代Java处理日期时间的标准方式,包含以下核心类:
LocalDate:只包含日期(年月日)LocalTime:只包含时间(时分秒纳秒)LocalDateTime:包含日期和时间(不含时区)ZonedDateTime:包含日期、时间和时区Instant:时间戳(机器时间,从1970-01-01T00:00:00Z开始)DateTimeFormatter:格式化和解析
案例1:获取当前日期、时间、时间戳
import java.time.*;
import java.time.format.DateTimeFormatter;
public class DateDemo {
public static void main(String[] args) {
// 当前日期(2024-01-15)
LocalDate today = LocalDate.now();
System.out.println("当前日期: " + today); // 2024-01-15
// 当前时间(14:30:25.123)
LocalTime nowTime = LocalTime.now();
System.out.println("当前时间: " + nowTime); // 14:30:25.123
// 当前日期时间
LocalDateTime now = LocalDateTime.now();
System.out.println("当前日期时间: " + now); // 2024-01-15T14:30:25.123
// 时间戳(适合跨时区使用)
Instant instant = Instant.now();
System.out.println("当前时间戳: " + instant); // 2024-01-15T06:30:25.123Z
// 带时区的日期时间
ZonedDateTime zdt = ZonedDateTime.now(ZoneId.of("Asia/Shanghai"));
System.out.println("上海时间: " + zdt); // 2024-01-15T14:30:25.123+08:00[Asia/Shanghai]
}
}
案例2:字符串与日期互转(格式化/解析)
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class FormatDemo {
public static void main(String[] args) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
// 日期 -> 字符串
LocalDateTime now = LocalDateTime.now();
String formatted = now.format(formatter);
System.out.println("格式化后: " + formatted); // 2024-01-15 14:30:25
// 字符串 -> 日期
String dateStr = "2024-12-25 10:30:00";
LocalDateTime parsed = LocalDateTime.parse(dateStr, formatter);
System.out.println("解析后: " + parsed); // 2024-12-25T10:30
// 常用格式化符号:
// yyyy: 年, MM: 月, dd: 日
// HH: 24小时制, hh: 12小时制, mm: 分, ss: 秒
// E: 星期几, a: 上午/下午
}
}
案例3:日期加减、比较、计算差值
import java.time.LocalDate;
import java.time.Period;
import java.time.temporal.ChronoUnit;
public class DateCalcDemo {
public static void main(String[] args) {
LocalDate today = LocalDate.now(); // 2024-01-15
// 加10天
LocalDate tenDaysLater = today.plusDays(10);
System.out.println("10天后: " + tenDaysLater); // 2024-01-25
// 减3个月
LocalDate threeMonthsAgo = today.minusMonths(3);
System.out.println("3月前: " + threeMonthsAgo); // 2023-10-15
// 计算两个日期之间的天数差
LocalDate start = LocalDate.of(2024, 1, 1);
LocalDate end = LocalDate.of(2024, 1, 15);
long daysBetween = ChronoUnit.DAYS.between(start, end);
System.out.println("相差天数: " + daysBetween); // 14
// 计算两个日期之间的年月日差 (Period)
Period period = Period.between(start, end);
System.out.println("相差: " + period.getDays() + "天"); // 14天
// 比较日期:isAfter, isBefore, isEqual
LocalDate date1 = LocalDate.of(2024, 6, 1);
LocalDate date2 = LocalDate.of(2024, 6, 15);
System.out.println("date1在date2之前? " + date1.isBefore(date2)); // true
}
}
案例4:获取某月的第一天、最后一天、星期几
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.temporal.TemporalAdjusters;
public class DateAdjustDemo {
public static void main(String[] args) {
LocalDate today = LocalDate.now(); // 2024-01-15
// 本月的第一天
LocalDate firstDay = today.with(TemporalAdjusters.firstDayOfMonth());
System.out.println("本月第一天: " + firstDay); // 2024-01-01
// 本月的最后一天
LocalDate lastDay = today.with(TemporalAdjusters.lastDayOfMonth());
System.out.println("本月最后一天: " + lastDay); // 2024-01-31
// 下一个周一
LocalDate nextMonday = today.with(TemporalAdjusters.next(DayOfWeek.MONDAY));
System.out.println("下一个周一: " + nextMonday);
// 当前日期是星期几
DayOfWeek dayOfWeek = today.getDayOfWeek();
System.out.println("今天是星期: " + dayOfWeek); // MONDAY
System.out.println("星期几数字: " + dayOfWeek.getValue()); // 1 (周一=1, 周日=7)
}
}
案例5:时区转换
import java.time.*;
public class TimeZoneDemo {
public static void main(String[] args) {
// 将北京时间转换为纽约时间
ZonedDateTime shanghaiTime = ZonedDateTime.now(ZoneId.of("Asia/Shanghai"));
System.out.println("上海: " + shanghaiTime);
// 转换为纽约时间
ZonedDateTime newYorkTime = shanghaiTime.withZoneSameInstant(ZoneId.of("America/New_York"));
System.out.println("纽约: " + newYorkTime);
// 跨时区的时间差
Instant instant = Instant.now(); // UTC时间
System.out.println("UTC: " + instant);
}
}
旧版方案(谨慎使用,仅维护旧代码)
如果你还在维护Java 7或更早的代码,会用到 java.util.Date 和 java.util.Calendar。但请注意:它们可变、线程不安全,设计混乱。
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
public class OldDateDemo {
public static void main(String[] args) throws Exception {
// 获取当前时间
Date now = new Date();
System.out.println("当前时间: " + now); // Thu Jan 15 14:30:25 CST 2024
// 格式化
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String formatted = sdf.format(now);
System.out.println("格式化: " + formatted);
// 字符串转日期
Date parsed = sdf.parse("2024-12-25 10:30:00");
System.out.println("解析: " + parsed);
// 日期加减 (使用Calendar)
Calendar cal = Calendar.getInstance();
cal.setTime(now);
cal.add(Calendar.DAY_OF_MONTH, 10); // 加10天
Date futureDate = cal.getTime();
System.out.println("10天后: " + sdf.format(futureDate));
}
}
常见问题与最佳实践
-
项目中使用哪个版本?
- Java 8+:只用
java.time包(JSR 310)。 - Java 6/7:引入
ThreeTen-Backport库(几乎和java.timeAPI一致)。
- Java 8+:只用
-
前端传字符串,后端如何处理?
- 使用
@DateTimeFormat+@JsonFormat注解(Spring框架)或自定义反序列化器。 - 接收格式建议统一为
yyyy-MM-dd/yyyy-MM-dd'T'HH:mm:ss(ISO 8601标准)。
- 使用
-
存储到数据库(MySQL为例)
- 字段类型:
DATE->LocalDate,DATETIME/TIMESTAMP->LocalDateTime。 - 建议统一使用
TIMESTAMP并设置time_zone='+00:00'存储UTC时间,应用层转为本地时区。
- 字段类型:
-
线程安全问题
SimpleDateFormat是线程不安全的,不要定义为static全局变量。DateTimeFormatter是线程安全的,可以放心使用。
-
性能问题
java.time的Instant比Date更精确(纳秒级)。- 频繁格式化时,将
DateTimeFormatter.ofPattern("...")提取为static final常量。
| 需求 | Java 8+ 方案 | 旧方案(不推荐) |
|---|---|---|
| 获取当前时间 | LocalDateTime.now() |
new Date() |
| 格式化 | DateTimeFormatter |
SimpleDateFormat(线程不安全) |
| 日期加减 | .plusDays(), .minusMonths() |
Calendar.add() |
| 计算差值 | ChronoUnit.between(), Period |
手动计算毫秒差 |
| 时区处理 | ZonedDateTime, ZoneId |
TimeZone, Calendar |
| 时间戳 | Instant.now() |
System.currentTimeMillis() |
建议:除非必须维护遗留系统,否则直接拥抱 java.time。