Age calculation, expiry date tracking, and scheduling are foundational requirements in software systems. From insurance policies expiring, subscription renewals, medication reminders, to calculating user ages for eligibility checks, accurate time calculations matter. A common mistake developers make is using manual arithmetic with days or months, which fails in leap years, varying month lengths, or daylight saving transitions.
The java.time
API offers robust tools (Period
, Duration
, ChronoUnit
, TemporalAdjusters
) to handle these tasks correctly and efficiently.
1. Calculating Age with Period
LocalDate birthDate = LocalDate.of(1990, 5, 15);
LocalDate today = LocalDate.now();
Period age = Period.between(birthDate, today);
System.out.printf("Age: %d years, %d months, %d days%n", age.getYears(), age.getMonths(), age.getDays());
✅ Handles leap years and month differences.
❌ Avoid manual subtraction—will fail on leap years.
2. Checking Expiry Dates
LocalDate issueDate = LocalDate.of(2023, 1, 1);
LocalDate expiryDate = issueDate.plusYears(2);
boolean isExpired = LocalDate.now().isAfter(expiryDate);
System.out.println("Is expired? " + isExpired);
✅ Great for licenses, subscriptions, or product shelf-life.
3. Scheduling with TemporalAdjusters
Next Monday (recurring meetings)
LocalDate today = LocalDate.now();
LocalDate nextMonday = today.with(TemporalAdjusters.next(DayOfWeek.MONDAY));
System.out.println("Next Monday: " + nextMonday);
Last Day of Month (salary processing)
LocalDate lastDay = LocalDate.now().with(TemporalAdjusters.lastDayOfMonth());
System.out.println("Last day of month: " + lastDay);
✅ Clean API for recurring schedules.
4. Measuring Time with Duration
LocalDateTime start = LocalDateTime.now();
// simulate task
LocalDateTime end = start.plusHours(5).plusMinutes(30);
Duration duration = Duration.between(start, end);
System.out.printf("Task duration: %d hours %d minutes%n", duration.toHours(), duration.toMinutesPart());
✅ Useful for task runtimes, session timeouts, and tracking SLAs.
5. Combining Period and Duration
LocalDateTime expiryDateTime = LocalDateTime.of(2025, 12, 31, 23, 59);
LocalDateTime now = LocalDateTime.now();
Duration remaining = Duration.between(now, expiryDateTime);
System.out.printf("Remaining: %d days, %d hours%n", remaining.toDays(), remaining.toHoursPart());
✅ Works for precise expiry down to hours and minutes.
6. Pitfalls and Anti-Patterns
- ❌ Using
System.currentTimeMillis()
for age/expiry → timezone issues. - ❌ Adding fixed days (
+365
) for a year → fails on leap years. - ❌ Not handling DST transitions in scheduling.
- ❌ Mixing
Period
(date-based) andDuration
(time-based) incorrectly.
7. Best Practices
- ✅ Use
Period
for human-readable differences (age, years, months). - ✅ Use
Duration
for machine-precise differences (sessions, timers). - ✅ Use
TemporalAdjusters
for recurring schedules. - ✅ Always validate edge cases like leap years and month-end.
📌 What's New in Java Versions?
- Java 8: Introduced
Period
,Duration
,TemporalAdjusters
. - Java 11: Minor improvements in
Duration
formatting. - Java 17: Stable API, no major changes.
- Java 21: Continued stability, regular time zone updates.
✅ Core APIs unchanged since Java 8.
Real-World Analogy
Think of age, expiry, and scheduling like a gym membership:
- Age → when you qualify for age-based discounts.
- Expiry → when your membership ends.
- Scheduling → when the next training session is due.
The API provides accurate ways to calculate each without human error.
Conclusion + Key Takeaways
- ❌ Avoid manual arithmetic for age, expiry, or schedules.
- ✅ Use
Period
for age and expiry,Duration
for time spans. - ✅ Use
TemporalAdjusters
for recurring schedules. - ✅ Always test edge cases like leap years and DST.
Correct handling ensures accurate eligibility checks, compliance reporting, and user trust.
FAQ: Expert-Level Q&A
1. Should I use Period or Duration for age calculation?
Use Period
—it handles years/months properly.
2. How to calculate expiry at a specific time of day?
Use LocalDateTime
+ Duration
for precise expiry.
3. What’s the difference between isAfter() and isBefore()?
They compare dates/times chronologically.
4. Can TemporalAdjusters skip invalid dates (e.g., 31st in February)?
Yes, they adjust to the last valid day automatically.
5. How to check if a subscription expires in the next 7 days?expiryDate.isBefore(today.plusDays(7))
.
6. Should I store expiry dates in UTC?
Yes, store in UTC, convert for user display.
7. How do I handle recurring events in multiple zones?
Store UTC, convert to ZonedDateTime
for each user’s zone.
8. Can Period and Duration be combined?
Yes—Period
for calendar-based, Duration
for clock-based precision.
9. Is there a risk of DST affecting expiry?
Yes, use ZonedDateTime
for DST-aware expiry logic.
10. Should I always test with leap years?
Yes—leap years often break naive expiry/age logic.