ZetCode

Java LocalDate

最后修改日期:2024 年 7 月 10 日

在本文中,我们将展示如何在 Java 中使用 LocalDate。 我们将计算当前的本地日期、解析本地日期、格式化本地日期、比较本地日期并进行日期运算。

LocalDate 是 ISO-8601 日历系统中没有时区的日期,例如 2024-05-22。LocalDate 是一个不可变的日期时间对象。

LocalDate 不存储或表示时间或时区。 它是墙上时钟上看到的本地日期的描述。

应使用 equals 方法进行比较。

当前日期

当前日期使用 LocalDate.now 检索。

Main.java
import java.time.LocalDate;

void main() {

    LocalDate now = LocalDate.now();
    System.out.println(now);
}

该示例打印本地当前日期。

$ java Main.java
2024-07-10

创建 LocalDate 对象

在 Java 中,有几种创建 LocalDate 的方法。

Main.java
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

void main() {

    // Current date
    LocalDate date1 = LocalDate.now();
    System.out.println(date1);

    // Specific date
    LocalDate date2 = LocalDate.of(2021, 5, 20);
    System.out.println(date2);

    // Specific date
    LocalDate date3 = LocalDate.parse("2021-05-21", DateTimeFormatter.ISO_DATE);
    System.out.println(date3);

    // Retrieving from LocalDateTime
    LocalDate date4 = LocalDateTime.now().toLocalDate();
    System.out.println(date4);
}

该示例展示了生成 LocalDate 的四种方法。

LocalDate date1 = LocalDate.now();

LocalDate.now 创建当前的本地时间。

LocalDate date2 = LocalDate.of(2021, 5, 20);

使用 LocalDate.of,我们可以从年、月和日的值创建一个特定的本地日期。

LocalDate date3 = LocalDate.parse("2021-05-21", DateTimeFormatter.ISO_DATE);

使用 LocalDate.parse,我们从字符串解析 LocalDate

LocalDate date4 = LocalDateTime.now().toLocalDate();

也可以使用 toLocalDate 方法从 LocalDateTime 对象获取 LocalDate

$ java Main.java
2024-07-10
2021-05-20
2021-05-21
2024-07-10

LocalDate 年、月、日

以下示例将本地日期拆分为年、月和日部分。

Main.java
import java.time.LocalDate;

void main() {

    LocalDate date = LocalDate.now();

    System.out.printf("Year: %s%n", date.getYear());
    System.out.printf("Month: %s%n", date.getMonthValue());
    System.out.printf("Day: %s%n", date.getDayOfMonth());
}

getYear 获取年份,getMonthValue 获取月份,getDayOfMonth 获取日期。

$ java Main.java
Year: 2024
Month: 7
Day: 10

LocalDate 年、月、周的日期

在以下示例中,我们获取年、月和周的日期。

Main.java
import java.time.LocalDate;

void main() {

    LocalDate now = LocalDate.now();

    System.out.println(now);

    System.out.printf("Day of year: %s%n", now.getDayOfYear());
    System.out.printf("Day of month: %s%n", now.getDayOfMonth());
    System.out.printf("Day of week: %s%n", now.getDayOfWeek());
}

要执行此任务,我们使用 getDayOfYeargetDayOfMonthgetDayOfWeek 方法。

$ java Main.java
2024-07-10
Day of year: 192
Day of month: 10
Day of week: WEDNESDAY

LocalDate & DateTimeFormatter

不同的国家/地区使用不同的日期格式。 DateTimeFormatter 帮助我们格式化日期。

Main.java
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.util.Locale;

void main() {

    LocalDate now = LocalDate.now();

    DateTimeFormatter df = DateTimeFormatter.ISO_DATE;
    System.out.println(now.format(df));

    DateTimeFormatter df2 = DateTimeFormatter.ISO_ORDINAL_DATE;
    System.out.println(now.format(df2));

    DateTimeFormatter df3 = DateTimeFormatter.ofPattern("dd LLLL yyyy");
    System.out.println(now.format(df3));

    DateTimeFormatter df4 = DateTimeFormatter.ofPattern("dd/MM/yyyy");
    System.out.println(now.format(df4));

    System.out.println("----------------------");

    LocalDate day = LocalDate.of(2020, 9, 20);

    System.out.println(DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL)
        .withLocale(Locale.FRENCH).format(day));
    System.out.println(DateTimeFormatter.ofLocalizedDate(FormatStyle.LONG)
        .withLocale(Locale.FRENCH).format(day));
    System.out.println(DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM)
        .withLocale(Locale.FRENCH).format(day));
    System.out.println(DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT)
        .withLocale(Locale.FRENCH).format(day));
}

该示例使用 DateTimeFormatter 格式化日期。

DateTimeFormatter df = DateTimeFormatter.ISO_DATE;
System.out.println(now.format(df));

我们将时间格式化为 ISO_DATE 格式日期标准。

DateTimeFormatter df3 = DateTimeFormatter.ofPattern("dd LLLL yyyy");
System.out.println(now.format(df3));

我们可以使用 DateTimeFormatter.ofPattern 选择自定义日期格式。 DateTimeFormatter 的文档包含我们可以使用的各种格式化字符的描述。

System.out.println(DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL)
    .withLocale(Locale.FRENCH).format(day));

使用 ofLocalizedDate 方法,我们有一个特定于区域设置的日期格式。

$ java Main.java
2024-07-10
2024-192
10 júl 2024
10/07/2024
----------------------
dimanche 20 septembre 2020
20 septembre 2020
20 sept. 2020
20/09/2020

LocalDate 算术

Java LocalDate 具有执行日期算术的方法。

Main.java
import java.time.LocalDate;

void main() {

    LocalDate now = LocalDate.now();
    System.out.println("Current date: " + now);

    // LocalDate addition
    System.out.println("Adding 3 days: " + now.plusDays(3));
    System.out.println("Adding 12 months: " + now.plusMonths(12));
    System.out.println("Adding 45 weeks: " + now.plusWeeks(45));
    System.out.println("Adding 4 years: " + now.plusYears(4));

    System.out.println("----------------------");

    // LocalDate subtraction
    System.out.println("Subtracting 3 days: " + now.minusDays(3));
    System.out.println("Subtracting 12 months: " + now.minusMonths(12));
    System.out.println("Subtracting 45 weeks: " + now.minusWeeks(45));
    System.out.println("Subtracting 4 years: " + now.minusYears(4));
}

该示例展示了添加和减去日期单位的方法。

System.out.println("Adding 3 days: " + now.plusDays(3));

plusDays 将三天添加到当前的本地日期。

System.out.println("Subtracting 3 days: " + now.minusDays(3));

同样,minusDays 从当前的本地日期中减去三天。

$ java Main.java
Current date: 2024-07-10
Adding 3 days: 2024-07-13
Adding 12 months: 2025-07-10
Adding 45 weeks: 2025-05-21
Adding 4 years: 2028-07-10
----------------------
Subtracting 3 days: 2024-07-07
Subtracting 12 months: 2023-07-10
Subtracting 45 weeks: 2023-08-30
Subtracting 4 years: 2020-07-10

LocalDate until

使用 until 方法,我们可以计算指定单位下到另一个日期的日期。

Main.java
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;

void main() {

    LocalDate d1 = LocalDate.of(2021, 5, 22);
    LocalDate d2 = LocalDate.parse("2021-12-25");

    System.out.printf("%s days%n", d1.until(d2, ChronoUnit.DAYS));
    System.out.printf("%s months%n", d1.until(d2, ChronoUnit.MONTHS));
    System.out.printf("%s years%n", d1.until(d2, ChronoUnit.YEARS));
}

该示例计算到另一个日期需要经过的天数、月数和年数。

System.out.printf("%s days%n", d1.until(d2, ChronoUnit.DAYS));

使用 ChronoUnit.DAYS,我们指定以天为单位计算日期差。

$ java Main.java
217 days
7 months
0 years

比较 LocalDate 对象

以下示例展示了如何比较日期。

Main.java
import java.time.LocalDate;

void main() {

    LocalDate d1 = LocalDate.of(2020, 2, 12);
    LocalDate d2 = LocalDate.of(2021, 3, 15);
    LocalDate d3 = LocalDate.of(2021, 5, 22);

    if (d1.compareTo(d2) == 0) {
        System.out.println("date1 and date2 are equal");
    } else {
        System.out.println("date1 and date2 are not equal");
    }

    if (d2.isBefore(d3)) {
        System.out.println("date2 comes before date3");
    } else {
        System.out.println("date2 does not come before date3");
    }

    if (d3.isAfter(d1)) {
        System.out.println("date3 comes after date1");
    } else {
        System.out.println("date3 does not come after date1");
    }
}

该示例比较日期。 我们检查它们是否相等,是否在另一个日期之前或之后。

if (d1.compareTo(d2) == 0) {

compareTo 比较两个本地日期。

if (d2.isBefore(d3)) {

isBefore 检查日期是否在另一个日期之前。

if (d3.isAfter(d1)) {

isAfter 检查日期是否在另一个日期之后。

$ java Main.java
date1 and date2 are not equal
date2 comes before date3
date3 comes after date1

LocalDate datesUntil

datesUntil 方法返回一个顺序排序的日期流。 返回的流从开始日期(包括)开始,到结束日期(不包括)结束,增量步长为一天。

Main.java
import java.time.LocalDate;

void main() {

    LocalDate start = LocalDate.of(2021, 4, 5);
    LocalDate end = LocalDate.of(2021, 5, 22);

    start.datesUntil(end).forEach(System.out::println);
}

在该示例中,我们打印两个指定日期之间的所有日期。

$ java Main.java
2021-04-05
2021-04-06
2021-04-07
2021-04-08
...
2021-05-20
2021-05-21

LocalDate 范围

range 方法获取指定字段的有效值的范围。

Main.java
import java.time.LocalDate;
import java.time.temporal.ChronoField;
import java.time.temporal.ValueRange;

void main () {

    LocalDate d = LocalDate.of(2021, 5, 22);

    ValueRange r = d.range(ChronoField.DAY_OF_MONTH);
    
    System.out.printf("DAY_OF_MONTH: %s%n", r);

    r = d.range(ChronoField.DAY_OF_WEEK);
    System.out.printf("DAY_OF_WEEK: %s%n", r);

    r = d.range(ChronoField.YEAR);
    System.out.printf("YEAR: %s%n", r);

    r = d.range(ChronoField.DAY_OF_YEAR);
    System.out.printf("DAY_OF_YEAR: %s%n", r);

    r = d.range(ChronoField.YEAR_OF_ERA);
    System.out.printf("YEAR_OF_ERA: %s%n", r);

    r = d.range(ChronoField.ERA);
    System.out.printf("ERA: %s%n", r);
}

我们获取各种字段的范围,包括 DAY_OF_MONTHYEARDAY_OF_YEAR

$ java Main.java
DAY_OF_MONTH: 1 - 31
DAY_OF_WEEK: 1 - 7
YEAR: -999999999 - 999999999
DAY_OF_YEAR: 1 - 365
YEAR_OF_ERA: 1 - 999999999
ERA: 0 - 1

LocalDate 查询

query 方法使用指定的查询来查询日期。 它们用于从时间对象中提取信息。

Main.java
import java.time.LocalDate;
import java.time.Month;
import java.time.temporal.ChronoField;
import java.time.temporal.TemporalAccessor;
import java.time.temporal.TemporalQuery;
import java.util.List;

void main() {

    var dates = List.of(LocalDate.of(2020, 9, 1), LocalDate.of(2020, 1, 15),
        LocalDate.of(2020, 1, 1), LocalDate.of(2020, 11, 14), 
        LocalDate.of(2020, 12, 24), LocalDate.of(2020, 3, 6), 
        LocalDate.of(2020, 8, 8), LocalDate.of(2020, 12, 16),
        LocalDate.of(2020, 5, 8), LocalDate.of(2020, 10, 21));

    dates.forEach(d -> {

        checkBirthday(d);
    });
}

void checkBirthday(LocalDate d) {

    Boolean isBirthday = d.query(new Birthdays());

    if (isBirthday.booleanValue()) {
        
        System.out.printf("%s is a family birthday%n", d);
    } else {

        System.out.printf("%s is not a family birthday%n", d);
    }
}

class Birthdays implements TemporalQuery<Boolean> {

    @Override
    public Boolean queryFrom(TemporalAccessor ta) {

        int month = ta.get(ChronoField.MONTH_OF_YEAR);
        int day = ta.get(ChronoField.DAY_OF_MONTH);

        if ((month == Month.JANUARY.getValue()) && day == 15) {
            return Boolean.TRUE;
        }

        if ((month == Month.MARCH.getValue()) && day == 6) {
            return Boolean.TRUE;
        }

        if ((month == Month.MAY.getValue()) && day == 19) {
            return Boolean.TRUE;
        }

        if ((month == Month.AUGUST.getValue()) && day == 8) {
            return Boolean.TRUE;
        }

        if ((month == Month.OCTOBER.getValue()) && day == 21) {
            return Boolean.TRUE;
        }

        return Boolean.FALSE;
    }
}

在该示例中,我们检查家庭成员是否在指定日期有生日。

var dates = List.of(LocalDate.of(2020, 9, 1), LocalDate.of(2020, 9, 15),
    LocalDate.of(2020, 1, 1), LocalDate.of(2020, 11, 14), 
    LocalDate.of(2020, 12, 24), LocalDate.of(2020, 5, 1), 
    LocalDate.of(2020, 12, 17), LocalDate.of(2020, 12, 16),
    LocalDate.of(2020, 5, 8), LocalDate.of(2020, 6, 19));

我们有一个日期列表。

dates.forEach(d -> {

    checkBirthday(d);
});

我们遍历列表并使用 checkBirthday 检查每个元素是否是家庭生日。

Boolean isBirthday = d.query(new Birthdays());

if (isBirthday.booleanValue()) {

    System.out.printf("%s is a holiday in Slovakia%n", d);
} else {

    System.out.printf("%s is not a holiday in Slovakia%n", d);
}

我们使用 query 方法查询当前日期; 我们将该方法传递给 TemporalQuery

class Birthdays implements TemporalQuery<Boolean> {

    @Override
    public Boolean queryFrom(TemporalAccessor ta) {

        int month = ta.get(ChronoField.MONTH_OF_YEAR);
        int day = ta.get(ChronoField.DAY_OF_MONTH);

        if ((month == Month.JANUARY.getValue()) && day == 15) {
            return Boolean.TRUE;
        }

        ...

        return Boolean.FALSE;
    }
}

TemporalQuery's queryFrom 方法中,我们指定该方法返回 true 的日期(生日)。

$ java Main.java
2020-09-01 is not a family birthday
2020-01-15 is a family birthday
2020-01-01 is not a family birthday
2020-11-14 is not a family birthday
2020-12-24 is not a family birthday
2020-03-06 is a family birthday
2020-08-08 is a family birthday
2020-12-16 is not a family birthday
2020-05-08 is not a family birthday
2020-10-21 is a family birthday

来源

Java LocalDate - 语言参考

在本文中,我们使用了 Java LocalDate。

作者

我的名字是 Jan Bodnar,我是一位充满热情的程序员,拥有丰富的编程经验。 我自 2007 年以来一直在撰写编程文章。 至今,我已撰写了 1,400 多篇文章和 8 本电子书。 我拥有超过十年的编程教学经验。

列出所有Java教程