在 Java 中获取前一天的日期,有多种方法,主要取决于你使用的 Java 版本(Java 8 之前或之后),Java 8 引入了现代化的 java.time 包,这是目前推荐的方式。
下面我将详细介绍几种主流方法,并给出完整的代码示例。
使用 Java 8+ 的 java.time API (推荐)
这是现代 Java 开发的首选方法,它更清晰、更安全,并且是不可变的(immutable)。
使用 LocalDate
LocalDate 表示一个没有时间的日期(年-月-日),非常适合处理“昨天”这类业务逻辑。
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
public class YesterdayJava8 {
public static void main(String[] args) {
// 1. 获取今天的日期
LocalDate today = LocalDate.now();
// 2. 减去一天,得到昨天的日期
LocalDate yesterday = today.minusDays(1);
// 3. 打印结果
System.out.println("今天的日期: " + today);
System.out.println("昨天的日期: " + yesterday);
// 4. 格式化输出
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
String formattedYesterday = yesterday.format(formatter);
System.out.println("格式化后的昨天日期: " + formattedYesterday);
}
}
输出:
今天的日期: 2025-10-27
昨天的日期: 2025-10-26
格式化后的昨天日期: 2025-10-26
使用 ZonedDateTime 或 OffsetDateTime
如果你的业务逻辑依赖于特定的时区,应该使用 ZonedDateTime。
import java.time.ZonedDateTime;
import java.time.ZoneId;
public class YesterdayWithTimeZone {
public static void main(String[] args) {
// 获取指定时区的当前日期时间
ZoneId zoneId = ZoneId.of("Asia/Shanghai");
ZonedDateTime nowInShanghai = ZonedDateTime.now(zoneId);
// 减去一天
ZonedDateTime yesterdayInShanghai = nowInShanghai.minusDays(1);
System.out.println("上海今天的日期时间: " + nowInShanghai);
System.out.println("上海昨天的日期时间: " + yesterdayInShanghai);
// 如果只需要日期部分,可以转换为 LocalDate
LocalDate yesterdayDate = yesterdayInShanghai.toLocalDate();
System.out.println("上海昨天的日期: " + yesterdayDate);
}
}
使用旧的 java.util.Date 和 java.util.Calendar (不推荐,但需了解)
在 Java 8 之前,我们通常使用 Date 和 Calendar,这种方法比较繁琐,Date 类本身有很多设计缺陷。
使用 Calendar
import java.util.Calendar;
import java.util.Date;
import java.text.SimpleDateFormat;
public class YesterdayLegacy {
public static void main(String[] args) {
// 1. 获取一个 Calendar 实例
Calendar calendar = Calendar.getInstance();
// 2. 获取今天的日期
Date today = calendar.getTime();
System.out.println("今天的日期: " + today);
// 3. 将日期减去一天
calendar.add(Calendar.DAY_OF_MONTH, -1);
// 4. 获取修改后的日期(即昨天)
Date yesterday = calendar.getTime();
System.out.println("昨天的日期: " + yesterday);
// 5. 格式化输出
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String formattedYesterday = sdf.format(yesterday);
System.out.println("格式化后的昨天日期: " + formattedYesterday);
}
}
注意:
Calendar是可变的,对calendar对象的修改会直接影响其内部状态。- 月份是从 0 开始的(0 代表一月),但
get(Calendar.MONTH)会返回正确的值,这有时会造成混淆。 - 这种方法代码冗长,容易出错。
使用第三方库 (如 Joda-Time)
在 Java 8 发布之前,Joda-Time 是事实上的标准日期时间库,虽然现在 java.time 已经取代了它,但在一些遗留项目中仍然可以看到。
import org.joda.time.LocalDate; // 注意是 org.joda.time.LocalDate
public class YesterdayJodaTime {
public static void main(String[] args) {
// 1. 获取今天的日期
LocalDate today = LocalDate.now();
// 2. 减去一天
LocalDate yesterday = today.minusDays(1);
System.out.println("今天的日期: " + today);
System.out.println("昨天的日期: " + yesterday);
}
}
Maven 依赖:
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>2.12.5</version> <!-- 使用最新版本 -->
</dependency>
总结与对比
| 特性 | java.time (Java 8+) |
java.util.Calendar |
Joda-Time |
|---|---|---|---|
| 推荐度 | ⭐⭐⭐⭐⭐ (强烈推荐) | ⭐ (不推荐) | ⭐⭐ (仅在旧项目中使用) |
| 易用性 | 非常高,API 直观 | 较低,API 繁琐 | 较高,API 设计良好 |
| 线程安全 | 不可变,天生线程安全 | 可变,非线程安全 | 大部分类是不可变的,线程安全 |
| 功能 | 功能全面,覆盖所有场景 | 功能基本,但设计有缺陷 | 功能强大,曾是行业标准 |
| 时区处理 | ZonedDateTime, ZoneId |
Calendar 可设置时区 |
DateTimeZone |
对于任何新的 Java 项目,请务必使用 java.time API,它解决了旧 API 的所有主要痛点,是处理日期和时间的现代、正确的方式。
只有在维护非常古老的 Java 代码(Java 8 之前)时,你才需要使用 Calendar 或 Joda-Time。
