ZetCode

Java MonthDay 类

最后修改时间:2025 年 4 月 16 日

java.time.MonthDay 类表示月份和日期的组合,不包含年份或时间。 它用于表示像生日或节日这样的重复性年度日期。 MonthDay 独立于任何年份处理月份和日期的值。

MonthDay 是不可变的且线程安全的。 它根据月份验证日期值,必要时考虑闰年。 该类遵循 ISO-8601 历法系统,并提供用于比较、格式化和解析的方法。

MonthDay 类概述

MonthDay 提供了创建、解析和操作月日组合的方法。 关键操作包括检查有效性、比较日期以及与年份结合。 该类正确处理月份长度,包括闰年中的二月。

public final class MonthDay implements TemporalAccessor, TemporalAdjuster, 
    Comparable<MonthDay>, Serializable {
    public static MonthDay now();
    public static MonthDay now(ZoneId zone);
    public static MonthDay of(int month, int dayOfMonth);
    public static MonthDay of(Month month, int dayOfMonth);
    public static MonthDay parse(CharSequence text);
    public int getMonthValue();
    public Month getMonth();
    public int getDayOfMonth();
    public boolean isValidYear(int year);
    public boolean isAfter(MonthDay other);
    public boolean isBefore(MonthDay other);
    public String format(DateTimeFormatter formatter);
}

上面的代码显示了 MonthDay 提供的主要方法。 这些方法允许创建、比较和格式化月日组合。 该类确保日期值对其各自的月份有效。

创建 MonthDay 对象

MonthDay 对象可以通过多种方式创建。 最常用的方法是 now 用于当前月日,以及用于特定组合的工厂方法。 还支持从字符串解析。

Main.java
package com.zetcode; 

import java.time.Month;
import java.time.MonthDay;

public class Main {

    public static void main(String[] args) {
        
        // Current month-day
        MonthDay current = MonthDay.now();
        System.out.println("Current month-day: " + current);
        
        // From month number and day
        MonthDay md1 = MonthDay.of(12, 25);
        System.out.println("Christmas: " + md1);
        
        // From Month enum and day
        MonthDay md2 = MonthDay.of(Month.FEBRUARY, 29);
        System.out.println("Leap day: " + md2);
        
        // From string
        MonthDay parsed = MonthDay.parse("--04-01");
        System.out.println("Parsed from string: " + parsed);
    }
}

此示例演示了创建 MonthDay 对象的不同方法。 输出显示了 ISO-8601 格式的月日组合(--MM-DD)。 请注意,即使在没有特定年份上下文的情况下创建,二月 29 日也是有效的。

获取 MonthDay 组件

一个 MonthDay 可以分解为其月份和日期组件。 月份可以作为数值或 Month 枚举检索。 这些值对于显示或进一步计算很有用。

Main.java
package com.zetcode; 

import java.time.Month;
import java.time.MonthDay;

public class Main {

    public static void main(String[] args) {

        MonthDay monthDay = MonthDay.of(Month.NOVEMBER, 11);
        
        // Get month as number
        int monthValue = monthDay.getMonthValue();
        System.out.println("Month number: " + monthValue);
        
        // Get month as enum
        Month month = monthDay.getMonth();
        System.out.println("Month: " + month);
        
        // Get day of month
        int day = monthDay.getDayOfMonth();
        System.out.println("Day: " + day);
        
        // Check validity for a specific year
        boolean isValid2023 = monthDay.isValidYear(2023);
        System.out.println("Valid for 2023: " + isValid2023);
    }
}

此示例显示了如何从 MonthDay 中提取组件。 isValidYear 方法检查该日期是否存在于指定的年份,这对于二月 29 日很重要。 所有 getter 方法都返回不可变值。

比较 MonthDay

可以比较 MonthDay 以确定一年中的时间顺序。 该类提供了 isBeforeisAftercompareTo 方法。 这些比较对于排序或查找日期范围很有用。

Main.java
package com.zetcode; 

import java.time.MonthDay;

public class Main {

    public static void main(String[] args) {

        MonthDay christmas = MonthDay.of(12, 25);
        MonthDay newYearsEve = MonthDay.of(12, 31);
        MonthDay independenceDay = MonthDay.of(7, 4);
        
        System.out.println("Christmas before New Year's Eve: " + 
            christmas.isBefore(newYearsEve));
        System.out.println("Independence Day after Christmas: " + 
            independenceDay.isAfter(christmas));
        System.out.println("Comparison result: " + 
            christmas.compareTo(independenceDay));
        
        // Equality check
        MonthDay anotherChristmas = MonthDay.parse("--12-25");
        System.out.println("Christmas equals: " + 
            christmas.equals(anotherChristmas));
    }
}

此示例演示了比较 MonthDay 对象的各种方法。 比较方法同时考虑月份和日期组件。 请注意,相等性需要月份和日期完全匹配。

与年份结合

MonthDay 可以与年份结合以创建 LocalDate。 当您需要处理年度日期的特定出现时,这很有用。 该类在组合时正确处理闰年。

Main.java
package com.zetcode; 

import java.time.LocalDate;
import java.time.MonthDay;
import java.time.Year;

public class Main {

    public static void main(String[] args) {

        MonthDay feb29 = MonthDay.of(2, 29);
        
        // Combine with specific year
        LocalDate leapDate = feb29.atYear(2020);
        System.out.println("Leap year date: " + leapDate);
        
        // Try non-leap year
        try {
            LocalDate invalidDate = feb29.atYear(2023);
            System.out.println("Non-leap year date: " + invalidDate);
        } catch (Exception e) {
            System.out.println("Error: " + e.getMessage());
        }
        
        // Using Year class
        LocalDate date2024 = feb29.atYear(Year.of(2024).getValue());
        System.out.println("Next leap year: " + date2024);
    }
}

此示例显示了如何将 MonthDay 与年份结合以创建 LocalDate 对象。 atYear 方法对无效组合(例如非闰年的二月 29 日)抛出异常。 在处理闰日时,请务必进行验证。

格式化和解析

MonthDay 支持通过 DateTimeFormatter 进行格式化和解析。 这允许自定义显示格式和解析各种字符串表示。 ISO-8601 格式为 --MM-DD。

Main.java
package com.zetcode; 

import java.time.MonthDay;
import java.time.format.DateTimeFormatter;
import java.util.Locale;

public class Main {

    public static void main(String[] args) {

        MonthDay monthDay = MonthDay.of(10, 31);
        
        // Default format
        String isoFormat = monthDay.toString();
        System.out.println("ISO format: " + isoFormat);
        
        // Custom format
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMM dd", Locale.US);
        String customFormat = monthDay.format(formatter);
        System.out.println("Custom format: " + customFormat);
        
        // Parse custom format
        MonthDay parsed = MonthDay.parse("Nov 11", 
            DateTimeFormatter.ofPattern("MMM dd", Locale.US));
        System.out.println("Parsed from custom format: " + parsed);
        
        // Parse with different pattern
        MonthDay parsed2 = MonthDay.parse("01/15", 
            DateTimeFormatter.ofPattern("MM/dd"));
        System.out.println("Parsed with slash: " + parsed2);
    }
}

此示例演示了格式化和解析 MonthDay 对象。 format 方法创建格式化的字符串,而 parse 可以处理各种输入格式。 始终为与区域设置相关的模式指定 Locale。

验证日期

MonthDay 自动根据其月份验证日期值。 额外的验证可以检查 MonthDay 对于特定年份是否有效。 这对于二月 29 日尤其重要。

Main.java
package com.zetcode; 

import java.time.MonthDay;

public class Main {

    public static void main(String[] args) {

        MonthDay feb29 = MonthDay.of(2, 29);
        
        // Check validity for various years
        System.out.println("Valid in 2020 (leap year): " + feb29.isValidYear(2020));
        System.out.println("Valid in 2023: " + feb29.isValidYear(2023));
        System.out.println("Valid in 2024: " + feb29.isValidYear(2024));
        
        // Try creating invalid month-day
        try {
            MonthDay invalid = MonthDay.of(4, 31);
            System.out.println("Created invalid month-day: " + invalid);
        } catch (Exception e) {
            System.out.println("Error creating invalid date: " + e.getMessage());
        }
        
        // Check day existence in month
        MonthDay april30 = MonthDay.of(4, 30);
        System.out.println("April 30 exists: " + 
            (april30.getDayOfMonth() == 30));
    }
}

此示例显示了 MonthDay 验证功能。 isValidYear 方法针对特定年份检查二月 29 日。 MonthDay 构造会自动拒绝无效的日期-月份组合,例如四月 31 日。

来源

Java MonthDay 类文档

在本文中,我们介绍了 Java MonthDay 类的基本方法和功能。 了解这些概念对于在 Java 应用程序中处理重复日期至关重要。

作者

我叫 Jan Bodnar,是一位经验丰富的程序员,在这一领域拥有多年的经验。 我于 2007 年开始撰写编程文章,此后撰写了 1,400 多篇文章和 8 本电子书。 凭借超过八年的教学经验,我致力于分享我的知识并帮助其他人掌握编程概念。

列出所有Java教程