Explain Codes LogoExplain Codes Logo

Comparing two java.util.Dates to see if they are in the same day

java
date-comparison
time-zones
java-8
Anton ShumikhinbyAnton Shumikhin·Jan 10, 2025
TLDR
boolean sameDay = DateUtils.isSameDay(date1, date2);

This one-liner from Apache Commons Lang's DateUtils provides a quick and easy verification if two Date objects fall on the same calendar day. This is the go-to method for a fast and reliable comparison.

But of course, there's always the hard way. Stick around if you're a fan of challenges!

Beware of time zones

Comparing dates isn't a walk in the park because of one teeny-tiny (queue sarcasm) detail - time zones. Depending on your time zone, your calendar might already be etching the next day while your best friend across the globe is just starting her day. So, if you're the kind to lose sleep over discrepancies, here's a silver bullet:

Calendar cal1 = Calendar.getInstance(TimeZone.getTimeZone("UTC")); cal1.setTime(date1); Calendar cal2 = Calendar.getInstance(TimeZone.getTimeZone("UTC")); cal2.setTime(date2); boolean sameDay = (cal1.get(Calendar.ERA) == cal2.get(Calendar.ERA) && cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR) && cal1.get(Calendar.DAY_OF_YEAR) == cal2.get(Calendar.DAY_OF_YEAR));

This snazzy piece of code moves both dates to the same time zone (UTC) before they can start a fight. Peace.

Going medieval on edge cases

Stripping away the unnecessary parts like a dedicated minimalist can be helpful. Let's use the SimpleDateFormat class to format dates to a strict "yyyyMMdd" format, which essentially 86's the time aspects of your Date objects. Cleaner and leaner.

We're about to get historical. Brace yourself! Let's calculate the Julian Day Number - (not named after me, unfortunately 🙁) a method used since ancient times to track dates.

Java 8, in all its glory, decided to simplify things further with LocalDate, providing a fancy new way to knock off the time parts of your Dates.

LocalDate localDate1 = date1.toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); LocalDate localDate2 = date2.toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); boolean sameDay = localDate1.isEqual(localDate2);

And voila, now we compare just the dates. No more time-related nightmares.

Date comparison - the "Half-Open" secret

Oh, you thought we were done nerd-ing out? Let's explore the "Half-Open" approach, which checks if date2 falls within the start and end of date1. Here's some magical incantation to clear that up:

Calendar startOfDay = Calendar.getInstance(); startOfDay.setTime(date1); startOfDay.set(Calendar.HOUR_OF_DAY, 0); startOfDay.set(Calendar.MINUTE, 0); startOfDay.set(Calendar.SECOND, 0); startOfDay.set(Calendar.MILLISECOND, 0); Date start = startOfDay.getTime(); Date end = new Date(startOfDay.getTimeInMillis() + TimeUnit.DAYS.toMillis(1)); boolean sameDay = !date2.before(start) && date2.before(end);

This approach efficiently sidesteps the problem of dates being wrong by millisecond margins. Showoff.

Handling time zones with java.time

The introduction of java.time is a blessing for dealing with these pesky time zones. Using ZonedDateTime gives you more control and clarity around time zones, making our lives all the easier.

ZonedDateTime zonedDate1 = date1.toInstant().atZone(ZoneId.systemDefault()); ZonedDateTime zonedDate2 = date2.toInstant().atZone(ZoneId.systemDefault()); boolean sameDay = zonedDate1.toLocalDate().isEqual(zonedDate2.toLocalDate());

Look at that shiny new code, making time zone complexities go poof!

Wrapping up in utilities for that clean code smell

Let's not dirty our hands with the same lines of date comparison again and again. Time for some housekeeping with utility methods:

public static boolean isSameCalendarDay(Date date1, Date date2) { LocalDate localDate1 = date1.toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); LocalDate localDate2 = date2.toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); return localDate1.isEqual(localDate2); // as efficient as a vacuum cleaner! }

That's one shiny code snippet right there - ready for reuse and readability!

Conclusion

Remember: practice makes perfect. So, code on and vote before you logout! Happy coding!👩‍💻