Explain Codes LogoExplain Codes Logo

Calculating days between two dates with Java

java
date-formatting
java-8
best-practices
Nikita BarsukovbyNikita Barsukov·Sep 13, 2024
TLDR

Quickly calculate days between two LocalDate instances with ChronoUnit.DAYS.between(start, end):

import java.time.LocalDate; import java.time.temporal.ChronoUnit; long days = ChronoUnit.DAYS.between(LocalDate.of(2023, 1, 1), LocalDate.of(2023, 12, 31)); System.out.println("Days: " + days); // Prints: "Days: 364", sorry no free day

Now you can get the accurate difference in calendar days without the hassle of old arcane APIs.

Break down the process

Parsing dates from user strings

Convert user input into dates using the DateTimeFormatter thusly:

import java.time.LocalDate; import java.time.format.DateTimeFormatter; DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd MM yyyy"); LocalDate startDate = LocalDate.parse("01 01 2023", formatter); LocalDate endDate = LocalDate.parse("31 12 2023", formatter); long daysBetween = ChronoUnit.DAYS.between(startDate, endDate); System.out.println("Days between: " + daysBetween); // Says "Days between: 364". No, New Year isn't a day off.

Leap years are included, yay!

No need to scramble your brain cells. The java.time package accounts for leap years automatically when calculating day difference. So, rejoice!

Pitfalls disguised as shortcuts

Don't get tricked by Duration.between. It counts 24-hour periods, and might leave you at odds with calendar days once daylight savings jumps in. Always stick to ChronoUnit.DAYS.between for calendar days.

Mastering edge cases and fine-tunings

Time zones aren't your nemesis

java.time got your back by handling time zone alterations and the pesky daylight savings automatically. Nonetheless, keep ZonedDateTime or OffsetDateTime handy for specific time zones,

No to negativity!

A negative day count should belong to sci-fi novels, not your code. Ensure a non-negative result using Math.abs:

long days = Math.abs(ChronoUnit.DAYS.between(startDate, endDate)); // Now this won't bite back.

Date input is user input, beware!

Never trust input without validating it. Guard against invalid dates and handle I/O exceptions with grace:

try { LocalDate date = LocalDate.parse(inputString, formatter); } catch (DateTimeParseException e) { System.out.println("Invalid date format. Please use 'dd MM yyyy'."); // Even the best of us make mistakes. }

Clarity trumps cleverness

Keep your variable names clear and meaningful. startDate and endDate sound way more professional than d1 and d2, don't they?

Diving deeper

Legacy code isn't a lost cause

Find yourself battling legacy code using java.util.Date or SimpleDateFormat? Wrap those dates into LocalDate asap for your sanity:

Date legacyDate = new ... // Your legacy date object LocalDate newStyleDate = legacyDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); // Welcome to the modern age.

Timing is everything

When working with Instant or timestamps, Duration.between() can be your friend for higher precision. Remember though, it's not for calendar calculations.

Every day counts

Rely on ChronoUnit.DAYS.between for an accurate day count even through leap years and varying month lengths. Consider it your calendar whisperer.

TemporalAdjuster is your Swiss Army knife

Unleash the power of custom TemporalAdjuster for ambitious date manipulations. "Next Wednesday" or "last day of the month"? Done and done.