In many business applications, you don’t always need the full LocalDate
(year, month, and day). Sometimes you only care about the year of a financial statement, the month of a recurring subscription, or a birthday without a year. Java’s java.time
API introduces Year
, YearMonth
, and MonthDay
for these exact scenarios.
A common pain point: developers misuse LocalDate
and put dummy values (e.g., year 1970 for birthdays), leading to confusing bugs and unnecessary data. This tutorial explains how to properly model partial date information with Year
, YearMonth
, and MonthDay
.
1. The Year Class
Represents a year in the ISO-8601 calendar system.
Year year = Year.of(2025);
System.out.println(year.isLeap()); // true or false
System.out.println(year.length()); // days in the year
Use Cases
- Academic or fiscal year records.
- Yearly reports or summaries.
2. The YearMonth Class
Represents a particular year and month, without a day.
YearMonth ym = YearMonth.of(2025, Month.FEBRUARY);
System.out.println(ym.lengthOfMonth()); // 28 or 29 depending on leap year
LocalDate firstDay = ym.atDay(1);
LocalDate lastDay = ym.atEndOfMonth();
System.out.println(firstDay + " to " + lastDay);
Use Cases
- Credit card expiration dates.
- Monthly billing cycles.
- Financial planning.
3. The MonthDay Class
Represents a month and day in the ISO calendar, without a year.
MonthDay md = MonthDay.of(Month.FEBRUARY, 29);
System.out.println(md.isValidYear(2024)); // true
System.out.println(md.isValidYear(2025)); // false
LocalDate birthday = md.atYear(2028);
System.out.println(birthday); // 2028-02-29
Use Cases
- Birthdays.
- Anniversaries.
- Recurring reminders without year context.
4. Converting Between Year, YearMonth, MonthDay, and LocalDate
YearMonth ym = YearMonth.now();
LocalDate date = ym.atDay(15); // Convert to LocalDate
MonthDay md = MonthDay.now();
LocalDate resolved = md.atYear(2026); // Attach year to resolve full date
5. Pitfalls and Anti-Patterns
- ❌ Using
LocalDate
with placeholder values for missing fields. - ❌ Forgetting leap year rules with
MonthDay.of(FEBRUARY, 29)
. - ❌ Comparing
YearMonth
directly toLocalDate
without conversion.
6. Business Case Study: Subscription Billing
- Subscription expires in March 2025 → Store as
YearMonth.of(2025, 3)
. - Birthday reminder → Store as
MonthDay.of(5, 10)
(May 10). - Annual report → Store as
Year.of(2025)
.
This ensures correct modeling without forcing dummy values.
📌 What's New in Java Versions?
- Java 8: Introduced
Year
,YearMonth
, andMonthDay
in thejava.time
API. - Java 11: Minor performance improvements.
- Java 17: No API changes.
- Java 21: Still stable—these classes haven’t changed since Java 8.
✅ These types are mature and safe to use across all modern Java versions.
Real-World Analogy
Think of these classes like calendar fragments:
Year
→ A whole calendar year (e.g., 2025).YearMonth
→ A specific month (like a magazine issue: March 2025 edition).MonthDay
→ A recurring event (like a birthday every April 14).
Conclusion + Key Takeaways
- ❌ Don’t misuse
LocalDate
with placeholder values. - ✅ Use
Year
for year-only contexts. - ✅ Use
YearMonth
for month + year values like credit card expiry. - ✅ Use
MonthDay
for recurring dates without year. - ✅ Always validate
MonthDay
against leap years.
Modeling dates correctly makes your applications cleaner, more accurate, and domain-driven.
FAQ: Expert-Level Q&A
1. Can Year
handle negative years (BC)?
Yes, ISO-8601 supports proleptic years, including negatives.
2. Does YearMonth
consider leap years?
Yes, lengthOfMonth()
accounts for leap years automatically.
3. What happens if MonthDay
is Feb 29 in a non-leap year?isValidYear(year)
returns false; attaching a year throws DateTimeException
.
4. Can I compare YearMonth
with LocalDate
?
Yes, but convert LocalDate
to YearMonth
using YearMonth.from(date)
first.
5. Is Year
immutable?
Yes, like all java.time
classes.
6. Can I use YearMonth
for payroll systems?
Yes, it’s ideal for monthly payroll cycles.
7. Should birthdays be stored as LocalDate
or MonthDay
?
Use MonthDay
if the year is irrelevant, LocalDate
if the year matters (e.g., age checks).
8. Can Year
be used for historical calendars (Julian)?
Not directly—ISO-8601 only. Use java.time.chrono
for alternate calendars.
9. How do I format YearMonth
?
Use DateTimeFormatter.ofPattern("MM/yyyy")
or similar.
10. Can YearMonth
be persisted in databases?
Yes—map to VARCHAR
or split into two numeric columns (year
, month
).