How to compare LocalDate with ZonedDateTime in js-joda?

6.4k views Asked by At

I'm looking for a way to compare instances of LocalDate and ZonedDateTime in js-joda, but those classes are not compatible. I'm willing to accept, that LocalDate is a ZonedDateTime with time and timezone set to zero.

What would be the easiest way to compare those two objects?

2

There are 2 answers

0
AudioBubble On BEST ANSWER

A LocalDate has only a date (day, month and year), while the ZonedDateTime also has a time (hour, minute, second and nanosecond) and a timezone. To compare them, you must choose which one will be converted to the other's type.

As @Dummy's answer already explains, one way is to convert the ZonedDateTime to a LocalDate. Supposing we have:

var z = ZonedDateTime.now(); // 2017-08-23T13:12:24.856-03:00[America/Sao_Paulo]
var dt = LocalDate.now(); // 2017-08-23

You can use the methods equals, isBefore or isAfter to check if the local date (day/month/year) is the same, before or after the other

z.toLocalDate().equals(dt); // true
z.toLocalDate().isBefore(dt); // false
z.toLocalDate().isAfter(dt); // false

You can also use compareTo, which can return -1, 0 or 1 if the first date is before, equals or after the second one.

As told in the comments, calling toLocalDate() discards the time and timezone information, keeping just the date (day/month/year). But as the LocalDate has only these fields, you don't need the others to do the comparison.


To do the opposite (convert the LocalDate to a ZonedDateTime), you'll have to make some assumptions. The same date can represent a different instant depending on the timezone you are (right now is August 23th in São Paulo, but in Tokyo is August 24th - the timezone you choose might affect the final result).

And you'll also need to define at what time (hour/minute/second/nanosecond) this date will be. You told you can assume that LocalDate is a ZonedDateTime with time and timezone set to zero. This means that the time will be midnight (00:00) and the timezone will be UTC (offset zero):

// consider LocalDate = ZonedDateTime with time and timezone set to zero (midnight in UTC)
var z2 = dt.atStartOfDay(ZoneOffset.UTC); // 2017-08-23T00:00Z

Then you can compare:

z2.equals(z); // false: check if all fields are the same (date/time/timezone)
z2.isEqual(z); // false: check if both represent the same instant (even if timezones are different)
z2.isBefore(z); // true
z2.isAfter(z); // false
z2.compareTo(z); // -1

Note that equals checks if all fields are the same (date, time and timezone), while all other methods compare the equivalent Instant (even if the timezones are different, the corresponding Instant is used to do the comparison).

In this case, z2 is 2017-08-23T00:00Z (August 23th 2017 at midnight in UTC), while z is 2017-08-23T13:12:24.856-03:00[America/Sao_Paulo], which is equivalent in UTC to 2017-08-23T16:12:24.856Z (August 23th 2017 at 16:12:24.856 in UTC).

So, equals returns false because the time and timezone are different and isEquals returns false because they don't represent the same instant (even when converting to UTC, they're are different). isBefore returns true because z2 is actually before z (midnight < 16:12) and so on.


If you want to use another timezone instead of UTC, you must use js-joda-timezone and the ZoneId class:

// get this date at midnight in London timezone
dt.atStartOfDay(ZoneId.of("Europe/London"));

The API uses IANA timezones names (always in the format Region/City, like America/Sao_Paulo or Europe/Berlin). Avoid using the 3-letter abbreviations (like CST or PST) because they are ambiguous and not standard.

You can get a list of available timezones (and choose the one that fits best your system) by calling ZoneId.getAvailableZoneIds().

You can also use the system's default timezone with ZoneId.systemDefault(), but this will be system/browser dependent, so it's better to explicity use a specific one.

4
Trash Can On

You can do this

zonedDateTime.toLocalDate().compareTo(otherLocalDate)

Which returns -1 if zonedDateTime is before otherLocalDate, 1 is after, 0 is the same