Java开发中经常需要处理日期时间减法场景,比如计算两个日期的间隔天数、获取当前时间往前推几小时的时间点等。旧的Date和Calendar类虽然能实现这类功能,但存在诸多设计缺陷,而Java 8之后推出的java.time API是更优的选择。

旧日期时间API的问题
在java.time出现之前,开发者常用java.util.Date和java.util.Calendar处理日期时间运算,这类方式存在明显不足:
- Date类的大部分方法已经过时,且内部存储的是时间戳,时区处理不直观
- Calendar类API设计复杂,月份从0开始计数,容易引发逻辑错误
- 两者都不是线程安全的,在多线程环境下使用需要额外加锁处理
比如用Calendar计算两个日期的间隔天数,代码逻辑繁琐还容易出错:
import java.util.Calendar;
import java.util.Date;
public class OldDateDemo {
public static void main(String[] args) {
Calendar cal1 = Calendar.getInstance();
cal1.set(2024, 5, 10); // 注意月份从0开始,这里实际是6月10日
Calendar cal2 = Calendar.getInstance();
cal2.set(2024, 5, 15);
// 计算间隔需要先转成毫秒再换算,逻辑不直观
long diffMillis = cal2.getTimeInMillis() - cal1.getTimeInMillis();
long diffDays = diffMillis / (24 * 60 * 60 * 1000);
System.out.println("间隔天数:" + diffDays);
}
}
java.time API的核心类
java.time API提供了多个针对不同场景的日期时间类,处理减法时需要先选对对应的类:
LocalDate:只包含日期,不包含时间和时区,适合处理日期层面的运算LocalDateTime:包含日期和时间,不包含时区,适合处理日期加时间的运算ZonedDateTime:包含日期、时间和时区,适合涉及时区的运算Period:用于表示日期之间的间隔,以年、月、日为单位Duration:用于表示时间之间的间隔,以秒、纳秒为单位
不同场景的减法实现
1. 日期减法(LocalDate)
如果只需要处理日期层面的减法,比如计算两个日期的间隔,或者获取某个日期往前推N天的日期,用LocalDate配合Period即可:
import java.time.LocalDate;
import java.time.Period;
public class LocalDateSubtractDemo {
public static void main(String[] args) {
// 定义两个日期
LocalDate date1 = LocalDate.of(2024, 6, 10);
LocalDate date2 = LocalDate.of(2024, 6, 15);
// 计算两个日期的间隔,得到Period对象
Period period = Period.between(date1, date2);
System.out.println("间隔年:" + period.getYears());
System.out.println("间隔月:" + period.getMonths());
System.out.println("间隔日:" + period.getDays());
// 获取当前日期往前推3天的日期
LocalDate today = LocalDate.now();
LocalDate threeDaysAgo = today.minusDays(3);
System.out.println("三天前日期:" + threeDaysAgo);
// 也可以用minus方法指定单位
LocalDate oneMonthAgo = today.minus(Period.ofMonths(1));
System.out.println("一个月前日期:" + oneMonthAgo);
}
}
2. 日期时间减法(LocalDateTime)
如果需要同时处理日期和时间,比如计算两个时间点的间隔小时数,或者获取当前时间往前推2小时的时间,用LocalDateTime配合Duration:
import java.time.Duration;
import java.time.LocalDateTime;
public class LocalDateTimeSubtractDemo {
public static void main(String[] args) {
// 定义两个日期时间
LocalDateTime time1 = LocalDateTime.of(2024, 6, 10, 10, 30, 0);
LocalDateTime time2 = LocalDateTime.of(2024, 6, 10, 14, 45, 0);
// 计算两个时间的间隔,得到Duration对象
Duration duration = Duration.between(time1, time2);
System.out.println("间隔小时:" + duration.toHours());
System.out.println("间隔分钟:" + duration.toMinutes());
System.out.println("间隔秒:" + duration.getSeconds());
// 获取当前时间往前推2小时30分钟的时间
LocalDateTime now = LocalDateTime.now();
LocalDateTime targetTime = now.minusHours(2).minusMinutes(30);
System.out.println("目标时间:" + targetTime);
// 也可以用minus方法指定Duration
LocalDateTime targetTime2 = now.minus(Duration.ofMinutes(150));
System.out.println("目标时间2:" + targetTime2);
}
}
3. 涉及时区的减法(ZonedDateTime)
如果业务涉及时区转换,比如计算不同时区下两个时间的间隔,需要用ZonedDateTime:
import java.time.Duration;
import java.time.ZonedDateTime;
import java.time.ZoneId;
public class ZonedDateTimeSubtractDemo {
public static void main(String[] args) {
// 定义北京时区的时间
ZonedDateTime beijingTime = ZonedDateTime.of(2024, 6, 10, 12, 0, 0, 0, ZoneId.of("Asia/Shanghai"));
// 定义东京时区的时间,东京比北京快1小时
ZonedDateTime tokyoTime = ZonedDateTime.of(2024, 6, 10, 13, 0, 0, 0, ZoneId.of("Asia/Tokyo"));
// 计算间隔,会自动处理时区差异
Duration duration = Duration.between(beijingTime, tokyoTime);
System.out.println("两个时间的间隔秒数:" + duration.getSeconds()); // 输出0,因为实际是同一时刻
}
}
注意事项
- Period只能用于日期层面的运算,不能处理时间部分,如果用在LocalDateTime上只会处理日期部分
- Duration只能处理时间层面的秒和纳秒,不能直接处理年、月,因为月的天数不固定
- 所有java.time的类都是不可变的,每次运算都会返回新的实例,不会修改原有对象,天然线程安全
- 避免使用
java.util.Date和java.time类混用,如果必须转换,可以通过toInstant()和Date.from()方法实现
java.time API的设计遵循清晰、不可变、线程安全的原则,相比旧的日期时间API大幅降低了出错概率,是Java中处理日期时间运算的首选方案。
java.timeLocalDateLocalDateTimeDurationPeriod修改时间:2026-07-06 23:03:30