方法定义与功能说明

1. minusDays(long daysToSubtract)

public LocalDate minusDays(long daysToSubtract)
  • 功能:从当前日期减去指定天数。
  • 参数daysToSubtract - 要减去的天数(可为负数,负数相当于加法)。
  • 返回值:新的 LocalDate 实例。
  • 异常DateTimeException(如果结果超出支持的日期范围)。

2. minusWeeks(long weeksToSubtract)

public LocalDate minusWeeks(long weeksToSubtract)
  • 功能:从当前日期减去指定周数(1 周 = 7 天)。
  • 参数weeksToSubtract - 要减去的周数。
  • 等价操作minusDays(weeksToSubtract * 7)

3. minusMonths(long monthsToSubtract)

public LocalDate minusMonths(long monthsToSubtract)
  • 功能:从当前日期减去指定月数。
  • 智能处理:自动处理不同月份天数差异和闰年。
  • 示例2025-03-31.minusMonths(1)2025-02-28(自动调整到2月最后一天)

4. minusYears(long yearsToSubtract)

public LocalDate minusYears(long yearsToSubtract)
  • 功能:从当前日期减去指定年数。
  • 智能处理:自动处理闰年2月29日问题。
  • 示例2024-02-29.minusYears(1)2023-02-28(非闰年,调整为28日)

三、详细示例代码

import java.time.LocalDate;

public class LocalDateMinusExample {
    public static void main(String[] args) {
        LocalDate today = LocalDate.of(2025, 8, 16);
        System.out.println("今天: " + today);

        // === minusDays ===
        LocalDate sevenDaysAgo = today.minusDays(7);
        System.out.println("7天前: " + sevenDaysAgo); // 2025-08-09

        LocalDate tomorrow = today.minusDays(-1); // 负数 = 加法
        System.out.println("明天: " + tomorrow); // 2025-08-17

        // === minusWeeks ===
        LocalDate oneWeekAgo = today.minusWeeks(1);
        System.out.println("1周前: " + oneWeekAgo); // 2025-08-09

        LocalDate fourWeeksAgo = today.minusWeeks(4);
        System.out.println("4周前: " + fourWeeksAgo); // 2025-07-19

        // === minusMonths ===
        LocalDate oneMonthAgo = today.minusMonths(1);
        System.out.println("1月前: " + oneMonthAgo); // 2025-07-16

        LocalDate threeMonthsAgo = today.minusMonths(3);
        System.out.println("3月前: " + threeMonthsAgo); // 2025-05-16

        // 特殊情况:月末处理
        LocalDate endOfMonth = LocalDate.of(2025, 3, 31);
        LocalDate febEnd = endOfMonth.minusMonths(1);
        System.out.println("3月31日减1月: " + febEnd); // 2025-02-28

        // === minusYears ===
        LocalDate oneYearAgo = today.minusYears(1);
        System.out.println("1年前: " + oneYearAgo); // 2024-08-16

        LocalDate tenYearsAgo = today.minusYears(10);
        System.out.println("10年前: " + tenYearsAgo); // 2015-08-16

        // 闰年处理
        LocalDate leapDay = LocalDate.of(2024, 2, 29);
        LocalDate nonLeapDay = leapDay.minusYears(1);
        System.out.println("2024-02-29 减1年: " + nonLeapDay); // 2023-02-28
    }
}

四、链式调用(Chaining)

minus* 方法支持链式调用,非常适合构建复杂的时间运算:

LocalDate complexDate = today
    .minusYears(2)           // 2年前
    .minusMonths(3)          // 再减3个月
    .minusWeeks(1)           // 再减1周
    .minusDays(5);           // 再减5天

System.out.println("复杂计算结果: " + complexDate);
// 等价于: today.minusDays(2*365 + 3*30 + 7 + 5) 的近似值

五、常见错误

❌ 错误 1:误以为修改了原对象

LocalDate date = LocalDate.of(2025, 8, 16);
date.minusDays(1); // ❌ 错误!没有接收返回值
System.out.println(date); // 仍然是 2025-08-16

// 正确做法:
LocalDate yesterday = date.minusDays(1);
System.out.println(yesterday); // 2025-08-15

❌ 错误 2:忽略月末/闰年处理

// 期望 2025-02-31?不存在!
LocalDate invalid = LocalDate.of(2025, 3, 31).minusMonths(1);
// 实际结果: 2025-02-28(自动调整)

❌ 错误 3:超出日期范围

// 可能抛出 DateTimeException
// LocalDate ancient = LocalDate.MIN.minusDays(1);

六、注意事项

  1. 不可变性:必须接收返回值,原对象不会改变。
  2. 智能调整
    • minusMonths/minusYears 会自动调整到有效日期(如 3月31日 → 2月28日)。
    • 不会抛出异常,而是进行合理调整。
  3. 负数参数:相当于加法操作(minusDays(-5) = plusDays(5))。
  4. 大数值:支持 long 类型,但需注意结果是否超出 LocalDate 范围(约 ±100万年)。
  5. 线程安全LocalDate 是不可变对象,线程安全。

七、使用技巧

✅ 技巧 1:封装常用时间偏移

public class DateUtils {
    public static LocalDate daysAgo(int days) {
        return LocalDate.now().minusDays(days);
    }
    
    public static LocalDate weeksAgo(int weeks) {
        return LocalDate.now().minusWeeks(weeks);
    }
}

// 使用
LocalDate lastWeek = DateUtils.daysAgo(7);
LocalDate lastMonth = DateUtils.daysAgo(30); // 近似

✅ 技巧 2:计算时间间隔

LocalDate startDate = LocalDate.of(2025, 1, 1);
LocalDate today = LocalDate.now();

// 计算距离年初已过去多少天
long daysPassed = today.toEpochDay() - startDate.toEpochDay();
System.out.println("今年已过去 " + daysPassed + " 天");

✅ 技巧 3:结合 isBefore/isAfter 使用

LocalDate thirtyDaysAgo = LocalDate.now().minusDays(30);
if (someDate.isBefore(thirtyDaysAgo)) {
    System.out.println("超过30天了");
}

八、最佳实践与性能优化

✅ 最佳实践 1:优先使用语义化方法

// 推荐:语义清晰
date.minusWeeks(2)

// 不推荐:可读性差
date.minusDays(14)

✅ 最佳实践 2:避免连续大量调用

// 对于大偏移量,直接计算更高效
LocalDate veryOld = LocalDate.of(1900, 1, 1);

// ❌ 低效
// for (int i = 0; i < 10000; i++) {
//     veryOld = veryOld.minusDays(1);
// }

// ✅ 高效
LocalDate result = veryOld.minusDays(10000);

✅ 性能说明

  • minus* 方法都是 O(1) 时间复杂度,性能极高。
  • 内部计算优化良好,无需担心性能问题。
  • 在高并发场景下,由于 LocalDate 不可变,天然线程安全。

九、总结对比

方法 单位 智能调整 典型用途
minusDays() 精确天数计算
minusWeeks() 周(7天) 周报、周期计算
minusMonths() ✅ 是 月度报表、账单周期
minusYears() ✅ 是 年龄计算、年度对比