跳到主要内容

Java LocalDate

在Java 8之前,日期时间处理一直是Java开发中的痛点。传统的java.util.Datejava.util.Calendar类设计不够合理,使用起来既繁琐又容易出错。随着Java 8的发布,引入了全新的日期时间API,其中LocalDate类是处理日期的核心类之一。

什么是LocalDate?

LocalDate是Java 8中的一个不可变类,用于表示不含时间的日期,例如"2023-05-15"。它不包含时区信息,只表示日期本身。

提示

不可变意味着一旦创建了LocalDate对象,就不能更改其值。任何修改操作都会返回一个新的LocalDate对象。

创建LocalDate对象

获取当前日期

java
// 获取当前日期
LocalDate today = LocalDate.now();
System.out.println("今天的日期是:" + today);

// 输出示例:今天的日期是:2023-10-25

指定特定日期

java
// 创建特定日期的LocalDate对象
LocalDate date = LocalDate.of(2023, 10, 25);
System.out.println("指定的日期是:" + date);

// 输出示例:指定的日期是:2023-10-25

从字符串解析

java
// 从字符串解析日期
LocalDate parsedDate = LocalDate.parse("2023-10-25");
System.out.println("解析的日期是:" + parsedDate);

// 使用自定义格式
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy");
LocalDate customDate = LocalDate.parse("25/10/2023", formatter);
System.out.println("自定义格式解析的日期是:" + customDate);

// 输出示例:
// 解析的日期是:2023-10-25
// 自定义格式解析的日期是:2023-10-25

获取日期的组成部分

LocalDate提供了丰富的方法来获取日期的各个部分:

java
LocalDate date = LocalDate.of(2023, 10, 25);

// 获取年、月、日
int year = date.getYear(); // 2023
int month = date.getMonthValue(); // 10
int day = date.getDayOfMonth(); // 25

System.out.println("年: " + year);
System.out.println("月: " + month);
System.out.println("日: " + day);

// 获取星期
DayOfWeek dayOfWeek = date.getDayOfWeek();
System.out.println("星期: " + dayOfWeek); // WEDNESDAY

// 获取一年中的第几天
int dayOfYear = date.getDayOfYear();
System.out.println("一年中的第几天: " + dayOfYear); // 298

日期操作

日期加减

java
LocalDate date = LocalDate.of(2023, 10, 25);

// 日期加法
LocalDate plusDays = date.plusDays(5);
LocalDate plusWeeks = date.plusWeeks(2);
LocalDate plusMonths = date.plusMonths(3);
LocalDate plusYears = date.plusYears(1);

System.out.println("原始日期: " + date); // 2023-10-25
System.out.println("加5天: " + plusDays); // 2023-10-30
System.out.println("加2周: " + plusWeeks); // 2023-11-08
System.out.println("加3个月: " + plusMonths); // 2024-01-25
System.out.println("加1年: " + plusYears); // 2024-10-25

// 日期减法
LocalDate minusDays = date.minusDays(5);
LocalDate minusWeeks = date.minusWeeks(2);
LocalDate minusMonths = date.minusMonths(3);
LocalDate minusYears = date.minusYears(1);

System.out.println("减5天: " + minusDays); // 2023-10-20
System.out.println("减2周: " + minusWeeks); // 2023-10-11
System.out.println("减3个月: " + minusMonths); // 2023-07-25
System.out.println("减1年: " + minusYears); // 2022-10-25

日期修改

java
LocalDate date = LocalDate.of(2023, 10, 25);

// 修改年、月、日
LocalDate withYear = date.withYear(2024);
LocalDate withMonth = date.withMonth(5);
LocalDate withDay = date.withDayOfMonth(15);

System.out.println("修改年份: " + withYear); // 2024-10-25
System.out.println("修改月份: " + withMonth); // 2023-05-25
System.out.println("修改日期: " + withDay); // 2023-10-15

// 设置为当月的第一天/最后一天
LocalDate firstDayOfMonth = date.withDayOfMonth(1);
LocalDate lastDayOfMonth = date.with(TemporalAdjusters.lastDayOfMonth());

System.out.println("当月第一天: " + firstDayOfMonth); // 2023-10-01
System.out.println("当月最后一天: " + lastDayOfMonth); // 2023-10-31

日期比较

LocalDate提供了多种方法来比较日期:

java
LocalDate date1 = LocalDate.of(2023, 10, 25);
LocalDate date2 = LocalDate.of(2023, 11, 5);

// 比较两个日期
boolean isEqual = date1.isEqual(date2); // false
boolean isBefore = date1.isBefore(date2); // true
boolean isAfter = date1.isAfter(date2); // false

System.out.println("日期相等: " + isEqual);
System.out.println("date1在date2之前: " + isBefore);
System.out.println("date1在date2之后: " + isAfter);

// 计算两个日期之间的差距
long daysBetween = ChronoUnit.DAYS.between(date1, date2);
long monthsBetween = ChronoUnit.MONTHS.between(date1, date2);
System.out.println("相差的天数: " + daysBetween); // 11
System.out.println("相差的月数: " + monthsBetween); // 0

日期格式化

LocalDate对象格式化为字符串:

java
LocalDate date = LocalDate.of(2023, 10, 25);

// 使用预定义格式
String basicIsoDate = date.format(DateTimeFormatter.BASIC_ISO_DATE);
String isoDate = date.format(DateTimeFormatter.ISO_DATE);

System.out.println("BASIC_ISO_DATE格式: " + basicIsoDate); // 20231025
System.out.println("ISO_DATE格式: " + isoDate); // 2023-10-25

// 使用自定义格式
DateTimeFormatter customFormatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日");
String formattedDate = date.format(customFormatter);
System.out.println("自定义格式: " + formattedDate); // 2023年10月25日

// 本地化格式
DateTimeFormatter localizedFormatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL);
String localizedDate = date.format(localizedFormatter);
System.out.println("本地化格式: " + localizedDate); // 2023年10月25日 星期三

实际应用案例

案例1:计算还款日期

在贷款或分期付款应用中,常需要计算每月的还款日期:

java
public List<LocalDate> calculatePaymentDates(LocalDate startDate, int installments) {
List<LocalDate> paymentDates = new ArrayList<>();

// 添加首次还款日期
paymentDates.add(startDate);

// 计算后续还款日期
for (int i = 1; i < installments; i++) {
LocalDate nextDate = startDate.plusMonths(i);
paymentDates.add(nextDate);
}

return paymentDates;
}

// 使用示例
LocalDate loanStartDate = LocalDate.of(2023, 10, 15);
int numberOfInstallments = 12;
List<LocalDate> dates = calculatePaymentDates(loanStartDate, numberOfInstallments);

System.out.println("贷款还款日期:");
for (LocalDate date : dates) {
System.out.println(date);
}

// 输出示例:
// 贷款还款日期:
// 2023-10-15
// 2023-11-15
// 2023-12-15
// ...以此类推

案例2:计算工作日

在业务应用中,经常需要计算工作日(排除周末):

java
public LocalDate addWorkingDays(LocalDate date, int workingDays) {
int addedDays = 0;
LocalDate result = date;

while (addedDays < workingDays) {
result = result.plusDays(1);
if (!(result.getDayOfWeek() == DayOfWeek.SATURDAY ||
result.getDayOfWeek() == DayOfWeek.SUNDAY)) {
addedDays++;
}
}

return result;
}

// 使用示例
LocalDate today = LocalDate.of(2023, 10, 25); // 星期三
LocalDate futureDate = addWorkingDays(today, 10);
System.out.println("今天: " + today);
System.out.println("10个工作日后: " + futureDate); // 2023-11-08 (星期三)

案例3:年龄计算

计算一个人的确切年龄:

java
public int calculateAge(LocalDate birthDate, LocalDate currentDate) {
if (birthDate == null || currentDate == null) {
return 0;
}
return Period.between(birthDate, currentDate).getYears();
}

// 使用示例
LocalDate birthDate = LocalDate.of(1990, 5, 15);
LocalDate currentDate = LocalDate.now();
int age = calculateAge(birthDate, currentDate);

System.out.println("出生日期: " + birthDate);
System.out.println("当前日期: " + currentDate);
System.out.println("年龄: " + age + "岁");

小结

LocalDate是Java 8日期时间API中的一个重要类,提供了简洁、直观的方式来处理日期。它具有以下特点:

  1. 不可变性,保证线程安全
  2. 只包含日期信息,不包含时间和时区
  3. 提供丰富的日期操作和比较功能
  4. 支持多种格式化选项

与旧的Date类相比,LocalDate解决了很多问题,例如:月份从1开始计数(而不是从0开始)、线程安全、更直观的API设计等。在现代Java应用开发中,应优先使用LocalDate来处理日期相关的操作。

练习题

  1. 编写一个方法,计算两个日期之间的工作日数量(不包括周末)。
  2. 实现一个方法,判断给定的年份是否为闰年。
  3. 编写一个方法,找出某年某月的所有星期日的日期。
  4. 实现一个方法,计算给定日期后的第n个工作日(排除法定节假日)。

进一步学习资源

  • Java官方文档关于LocalDate的描述
  • Java 8日期时间API中的其他类:LocalTimeLocalDateTimeZonedDateTime
  • 时间操作类:PeriodDurationChronoUnit

通过充分利用LocalDate类,你可以轻松处理各种日期相关的操作,使你的代码更加简洁、可读和可维护。