Как сравнить LocalDate с ZonedDateTime в js-joda?

Я ищу способ сравнить экземпляры LocalDate а также ZonedDateTime в js-joda, но эти классы не совместимы. Я готов принять, что LocalDate это ZonedDateTime время и часовой пояс установлены на ноль.

Какой самый простой способ сравнить эти два объекта?

2 ответа

Решение

LocalDate имеет только дату (день, месяц и год), а ZonedDateTime также имеет время (часы, минуты, секунды и наносекунды) и часовой пояс. Чтобы сравнить их, вы должны выбрать, какой из них будет преобразован в тип другого.

Как уже объясняет ответ @Dummy, одним из способов является преобразование ZonedDateTime к LocalDate, Предположим, у нас есть:

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

Вы можете использовать методы equals, isBefore или же isAfter проверить, совпадает ли местная дата (день / месяц / год) до или после другой

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

Вы также можете использовать compareTo, который может вернуть -1, 0 или же 1 если первая дата до, равна или после второй.

Как сказано в комментариях, звоню toLocalDate() сбрасывает информацию о времени и часовом поясе, сохраняя только дату (день / месяц / год). Но как LocalDate имеет только эти поля, другие не нужны для сравнения.


Чтобы сделать обратное (преобразовать LocalDate к ZonedDateTime), вам придется сделать некоторые предположения. Одна и та же дата может представлять разные моменты времени в зависимости от того, в каком часовом поясе вы находитесь (сейчас в Сан-Паулу 23 августа, а в Токио - 24 августа - выбранный вами часовой пояс может повлиять на конечный результат).

И вам также необходимо определить, в какое время (час / минута / секунда / наносекунда) будет указана эта дата. Вы сказали, что можете предположить, что LocalDate - это ZonedDateTime, для которого время и часовой пояс установлены в ноль. Это означает, что время будет полночь (00:00), а часовой пояс будет UTC (смещение нуля):

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

Тогда вы можете сравнить:

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

Обратите внимание, что equals проверяет, все ли поля одинаковы (дата, время и часовой пояс), а все остальные методы сравнивают эквивалентные Instant (даже если часовые пояса разные, соответствующие Instant используется для сравнения).

В этом случае, z2 является 2017-08-23T00:00Z (23 августа 2017 года в полночь по UTC), а z является 2017-08-23T13:12:24.856-03:00[America/Sao_Paulo], что эквивалентно в UTC 2017-08-23T16:12:24.856Z (23 августа 2017 года в 16:12:24.856 по Гринвичу).

Так, equals возвращается false потому что время и часовой пояс разные и isEquals возвращается false потому что они не представляют одно и то же мгновение (даже при конвертации в UTC они разные). isBefore возвращается true так как z2 на самом деле раньше z (полночь < 16:12) и так далее.


Если вы хотите использовать другой часовой пояс вместо UTC, вы должны использовать js-joda-timezone и ZoneId учебный класс:

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

API использует имена часовых поясов IANA (всегда в формате Region/City, лайк America/Sao_Paulo или же Europe/Berlin). Избегайте использования трехбуквенных сокращений (например, CST или же PST) потому что они неоднозначны и не стандартны.

Вы можете получить список доступных часовых поясов (и выбрать тот, который лучше всего подходит вашей системе), позвонив ZoneId.getAvailableZoneIds(),

Вы также можете использовать часовой пояс системы по умолчанию с ZoneId.systemDefault(), но это будет зависеть от системы / браузера, поэтому лучше использовать конкретный.

Вы можете сделать это

zonedDateTime.toLocalDate().compareTo(otherLocalDate)

Который возвращается -1 если zonedDateTime раньше otherLocalDate, 1 после, 0 та же

Другие вопросы по тегам