java localdate разница между датами в днях

Расчет разницы дат за указанное количество дней с использованием класса LocalDate

Я пишу служебный класс для вычисления даты, чтобы увидеть, предшествует ли сохраненная дата текущей дате, что означает, что она истекла.

Однако я не уверен, что сделал все правильно. Я использую класс LocalDate для вычисления дней. Срок действия отсчитывается, начиная с даты и времени, когда пользователь нажал сохранить. Эта дата будет сохранена, и будет произведена проверка по отношению к этой сохраненной дате и времени и текущей дате и времени, т.е. когда пользователь входит в систему.

Я использую класс так:

Я ищу решение, которое будет учитывать часовые пояса. Если срок действия лицензии истекает через 3 дня, и пользователь должен был отправиться в другой часовой пояс. то есть они могут быть впереди или позади, основываясь на часах. Срок действия лицензии еще должен истечь.

4 ответа

Вместо использования java.util.Date вы можете еще больше упростить это, если просто используете long для saveTime.

Я думаю, что гораздо лучше использовать это:

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

Как уже заметил Хьюго, я бы использовал java.time.LocalDate и отказался от использования ThreeTen Backport (если только это не является специальным требованием, чтобы ваш код мог работать и на Java 6 или 7).

Часовой пояс

Вы должны решить, в каком часовом поясе вы считаете свои дни. Также я бы предпочел, чтобы вы указали часовой пояс в своем коде. Если ваша система будет использоваться только в вашем часовом поясе, выбор прост, просто сделайте его явным. Например:

Пожалуйста, заполните соответствующий идентификатор зоны. Это также обеспечит правильную работу программы, даже если однажды она запустится на компьютере с неправильной настройкой часового пояса. Если ваша система глобальна, вы можете использовать UTC, например:

Вы захотите сделать то же самое при сохранении даты, когда пользователь нажал Сохранить, чтобы ваши данные были согласованы.

72 часа

Изменить: Из вашего комментария я понимаю, что вы хотите измерить 3 дня, то есть 72 часа, от времени сохранения, чтобы определить, истек ли срок действия лицензии. Для этого LocalDate не дает вам достаточно информации. Это только дата без часового времени, как 26 мая 2017 года нашей эры. Есть несколько других вариантов:

Поскольку момент времени одинаков во всех часовых поясах, вы не указываете часовой пояс при получении текущего момента:

Если вы хотите текущую настройку часового пояса от JVM, где работает программа:

Это выполнит правильное сравнение, даже если два объекта ZonedDateTime находятся в двух разных часовых поясах. Поэтому, независимо от того, путешествует ли пользователь в другой часовой пояс, он / она не получит ни меньше, ни больше часов до истечения срока действия лицензии.

Поскольку этот вопрос не получает «достаточно ответов», я добавил еще один ответ:

Я использовал «SimpleDateFormat.setTimeZone (TimeZone.getTimeZone (» UTC «));» установить часовой пояс на UTC. Таким образом, больше нет часового пояса (все дата / время будут установлены в UTC).

saveDate установлен в UTC.

Новая дата expiresDate использует длинные миллисекунды с dateTimeNow

Запуск этого кода дает следующий вывод:

Все даты / время указаны в формате UTC. Первый не истек. Вторая истекла (сохраненная дата предшествует expiresDate).

Источник

7 ответов

Как предлагали другие пользователи, вам также необходимо установить значение миллисекунды календарей на ноль, чтобы сравнивать только даты. Этого можно добиться с помощью следующего фрагмента кода:

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

По вашей просьбе я выполняю свою функцию как цель. Я использовал календарь, я установил всю временную часть на 0 перед сравнением.

Я считаю, что вам нужно усечь часть времени с даты, прежде чем вычислять разницу, как показано ниже:

Надеюсь, это сработает.

Вы определили проблему на первом шаге, установив время на полночь: чтобы убедиться, что все часы, минуты и секунды были равны нулю. Но вы не зашли достаточно далеко! Вы также должны убедиться, что миллисекунды обнулены.

Это мой подход в настоящее время,

Но, похоже, у меня не работает.

ТЛ ; др

Наивные расчеты

Избегайте устаревших классов даты и времени

Часовой пояс

Не расширяйте java.time

Не расширяйте (создавайте подклассы) классы java.time (они отмечены final ).

И не обобщайте их интерфейсы для своей бизнес-логики; придерживайтесь конкретных классов этого фреймворка. Хотя обобщение имеет смысл в других средах, таких как Коллекции Java, но не в java.time.

Использование java.time

Эта работа намного проще с классами java.time.

ZonedDateTime представляет момент на шкале времени с назначенной временной зоной ( ZoneId ).

ChronoUnit enum может вычислить время, прошедшее между парой моментов.

then.toString (): 2017-01-23T12: 34: 56.123456789-05: 00 [Америка / Монреаль]

now.toString (): 2017-03-01T21: 26: 04.884-05: 00 [Америка / Монреаль]

Преобразование устаревших экземпляров в java.time

Полуоткрытый

О java.time

Где получить классы java.time?

Библиотека Joda Time очень хорошо справляется с такими проблемами:

Источник

Разница между двумя датами в Java

Разница между двумя датами в Java

1. обзор

В этом кратком обзоре мы рассмотрим несколько возможностей вычисления разницы между двумя датами на Java.

Дальнейшее чтение:

Дата приращения в Java

Обзор различных основных и сторонних методов для добавления дней к дате

Проверьте, является ли строка действительной датой в Java

Взгляните на разные способы проверить, является ли String действительной датой в Java

2. Основная Java

2.1. Использованиеjava.util.Date для определения разницы в днях

Давайте начнем с использования основных API-интерфейсов Java для расчета и определения количества дней между двумя датами:

Теперь вычисление разницы станет более интуитивным, если мы используемLocalDate, LocalDateTime для представления двух дат (со временем или без него) в сочетании сPeriod иDuration:.

Here ‘немного подробнее об этом API.

2.3. Использованиеjava.time.temporal.ChronoUnit для определения разницы в секундах

API времени в Java 8 представляет собой единицу даты и времени, например секунды или дни, используяTemporalUnit interface. Each unit provides an implementation for a method named between to calculate the amount of time between two temporal objects in terms of that specific unit.

Например, чтобы вычислить секунды между двумяLocalDateTimes:

ChronoUnit предоставляет набор конкретных единиц времени, реализуя интерфейсTemporalUnit. It’s highly recommended to static import the ChronoUnit enum values to achieve more readability:

Что замечательно вZonedDateTime, так это то, что расчет будет работать, даже если они установлены в разные часовые пояса:

2.4. Используяjava.time.temporal.Temporaluntil()

Любой объектTemporal, например LocalDate or ZonedDateTime, provides an until method to calculate the amount of time until another temporal in terms of the specified unit:

3. Внешние библиотеки

3.1. JodaTimeс

Мы также можем сделать относительно простую реализацию сJodaTime:

Вы можете получить последнюю версиюJoda-time из Maven Central.

Точно так же сLocalDateTime это:

3.2. Date4Jс

Date4j также обеспечивает прямую и простую реализацию без примечания, что в этом случае нам нужно явно предоставитьTimeZone.

Начнем с зависимости Maven:

Вот быстрый тест, работающий со стандартнымDateTime:

4. Заключение

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

Полный исходный код статьи доступенover on GitHub.

Источник

Разница в днях между двумя датами в Java?

мне нужно найти количество дней между двумя датами: один из отчета, а другой-текущая дата. Мой фрагмент:

здесь calculateDifference является частным методом, agingDate и today are Date объекты, просто для уточнения. Я следил за двумя статьями с форума Java,резьба 1 / резьба 2.

он отлично работает в Автономной программе, хотя когда я включаю это в свою логику для чтения из сообщаю, что получаю необычную разницу в ценностях.

почему это происходит и как я могу это исправить?

EDIT:

Я получаю большее количество дней по сравнению с фактическим количеством дней.

Примечание :

к сожалению, ни один из ответов помог мне решить проблему. Я достиг проблема С помощью Joda времени библиотека.

20 ответов

Я бы предложил вам использовать отличный Джода Времени библиотека вместо дефектной java.утиль.Свидание и друзья. Вы могли бы просто написать

Я, возможно, слишком поздно, чтобы присоединиться к игре, но какого черта? 🙂

Как вы думаете, это проблема с потоками? Как вы используете вывод этого метода, например? Или

можем ли мы изменить ваш код, чтобы сделать что-то простое, как:

diff / (24 * etc) не учитывает часовой пояс, поэтому, если в вашем часовом поясе по умолчанию есть DST, он может сбросить расчет.

этой ссылке есть миленький реализации.

вот источник приведенной выше ссылки в случае, если ссылка идет вниз:

java.время

в Java 8 и более поздних, используйте java.временные рамки (учебник).

Duration

на Duration класс представляет промежуток времени как количество секунд плюс дробная секунда. Он может считать дни, часы, минуты и секунды.

ChronoUnit

Это зависит от того, что вы определите как разницу. Сравнить две даты в полночь можно.

решение, использующее разницу между миллисекундами времени, с правильным округлением для дат DST:

одно примечание: конечно, даты должны быть в некотором часовом поясе.

Если вы не хотите раунд, вы можете использовать даты UTC,

иллюстрация проблемы: (мой код вычисляет дельту в неделях, но та же проблема применяется к Дельте в днях)

вот очень разумно выглядящая реализация:

но этот тест не получится:

но любой, кто смотрит на календарь, согласится, что ответ 2.

Я использую эту функцию:

основываясь на ответе @Mad_Troll, я разработал этот метод.

Я запустил около 30 тестовых случаев против него, это единственный метод, который обрабатывает фрагменты суб-дневного времени правильно.

пример: если вы проходите сейчас и сейчас + 1 миллисекунда, это все тот же день. Делать 1-1-13 23:59:59.098 to 1-1-13 23:59:59.099 возвращает 0 дней, правильно; выделение других методов, размещенных здесь, не будет делать это правильно.

стоит отметить, что он не заботится о том, каким образом вы их поместите, если ваша дата окончания перед вашей датой начала он будет отсчитываться назад.

вы можете удалить @NotNull аннотации, они используются Intellij для анализа кода на лету

Источник

Java и время: часть вторая

Эта статья написана в продолжение к первой части и посвящена новому Date Time API, который был введен в Java 8. Я изначально хотел оформить эту тему отдельно, поскольку она достаточно большая и серьезная. Я еще сам не в полной мере начал использовать этот API в проектах, поэтому разбираться будем вместе по ходу. В принципе в переходе на новый API нет никакой срочной необходимости, более того многие еще и не начинали проекты на Java 8, а это означает, что время на освоение еще есть.

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

История

Сравнение

Начать наверное стоит с того, что именно не устраивало многих в старом API. И тут же, чтобы не терять время сразу укажу, что в новом API изменилось к лучшему.

Класс java.util.Calendar также изменяем. Хотя это особых проблем это не доставляет поскольку большинство понимает что у него есть внутреннее состояние которое меняется, да и передавать его аргументами как-то не очень принято.

Поскольку классы в старом API изменяемые, использовать их в многопоточной среде нужно с осторожностью. В частности java.util.Date можно признать «эффективно» потоко-безопасным, если вы не вызываете у него устаревшие методы.

Опасения

Об этих и других, настороживших меня кейсах расскажу подробнее уже в примерах.

Временные зоны

Начнем как обычно с временных зон. Новый класс java.time.ZoneId обозначает временную зону. Два его сабкласса java.time.ZoneRegion и java.time.ZoneOffset реализуют два типа временных зон: временную зону по географическому принципу и временную зону по простому смещению относительно UTC, UT или GMT. Правила перевода стрелок вынесены в отдельных класс java.time.zone.ZoneRules, экземпляр которого доступен через метод java.time.ZoneId#getRules.

В целом, кроме указанного рефакторинга, я не нашел тут особых принципиальных изменений, разве что правила перевода стрелок теперь предоставляют больше методов для запроса информации. Посему все написанное в старой статье справедливо и для новых классов временных зон, разве что методы несколько отличаются по имени.

Не очень понятно почему case-4, который фактически запрашивает тоже что и case-3, в результате создает java.time.ZoneRegion, а не java.time.ZoneOffset.

Для временной зоны UTC заведена специальная константа java.time.ZoneOffset#UTC, но тем не менее запрос на ZoneId.of(«UTC») в новом API выдает уже объект класса java.util.ZoneRegion, а не эту константу.

«Время — это часы» — как утверждают некоторые физики. И это фраза является ключевой для нового API, где класс java.time.Clock является краеугольным. И также как некоторые из наших часов, время для нас может быть: константным (неидущим), опаздывающим, идущим с различной степенью точности, двигающем стрелки по разному в разных часовых поясах. В общем в новом API можно использовать (либо определить самому) практически любой ход времени, в том числе и для проверки тестов.

Стандартный экземпляр java.time.Clock можно создать только фабричными статическими методами (сам класс абстрактный).

Стандартный экземпляр java.time.Clock всегда знает о временной зоне в которой его создали (хотя это бывает и ненужным).

Можно переопределить java.time.Clock и написать любую свою логику выдачи времени, например часы которые выдают случайное время на каждый запрос, почему бы и нет?

Instant

java.time.Instant — это новый java.util.Date, только неизменяемый, с наносекундной точностью и корректным названием. Внутри хранит Unix-time в виде двух полей: long с количеством секунд, и int с количеством наносекунд внутри текущей секунды.

Значение обоих полей можно запросить напрямую, а также можно попросить посчитать более привычное для старого API представление Unix-time в виде миллисекунд:

Также как и java.util.Date (при правильном его использовании), объект класса java.time.Instant ничего не знает про временную зону.

Отдельно стоит сказать про метод java.time.Instant.toString(). Если раньше java.util.Date.toString() работал с учетом текущей локали и временной зоны по умолчанию, то новый java.time.Instant.toString() всегда формирует текстовое представление во временной зоне UTC и одинаковым форматом ISO-8601 — это касается и вывода переменных в IDE при отладке:

Базовые интерфейсы

Посмотрим на базовый интерфейс java.time.temporal.TemporalAccessor. Интерфейс TemporalAccessor — это справочник для запроса отдельной частичной информации по текущей точке или метке и его реализуют все временные классы нового API.

Попросим значение Unix-time у java.time.Instant:

Получаем исключение с совершенно необъяснимым сообщением:

Немного подебажив, становится ясна причина исключения: результат теоретически может не помещаться в диапазон int (хотя в данный момент помещается). Поле INSTANT_SECONDS надо запрашивать как long. Исправим запрос, попутно запросим дополнительную мета-информацию:

Поле CLOCK_HOUR_OF_DAY не поддерживается типом Instant. Это совершенно ожидаемо, поскольку для выяснения часа дня по временной точке нам нужно указать временную зону, которой в java.time.Instant нет. Попробуем все таки запросить это значение:

Все правильно — при запросе часа дня мы получаем исключение. Прекрасно, что метод запроса не стал использовать временную зону по умолчанию (которой в новом API и нет).

Кроме запроса отдельных полей можно запрашивать значения с помощью более сложных алгоритмов-стратегий наследующих интерфейс java.time.TemporalQuery:

java.time.temporal.Temporal — интерфейс является наследником интерфейса TemporalAccessor. Вводит операции сдвига временной точки/метки вперед и назад, операцию замены части временной информации, а также операцию вычисления расстояния до другой временной точки/метки. Реализуется почти всеми «полноценными» временными классами нового API.

Пробуем сдвинуть метку на день вперед и посчитаем разницу:

Поскольку все классы наконец-то стали неизменяемыми, то результаты операций надо не забыть присвоить другой переменной, поскольку оригинальная при операции не изменяется — все аналогично java.lang.String или java.math.BigDecimal.

Попробуем изменить час дня в java.time.Instant:

Ожидаемо получаем по рукам, поскольку для этой операции необходима временная зона.

java.time.temporal.TemporalAdjuster — интерфейс стратегии коррекции временной точки/метки, например перемещение в первый день текущего кода. Раньше приходилось для этого писать свои вспомогательные классы для работы с полями java.util.Calendar — сейчас весь код можно оформить в виде стратегии, если нужной еще нет в стандартной поставке:

Теперь можно перейти к временным классам.

LocalTime, LocalDate, LocalDateTime

java.time.LocalTime — это кортеж (час, минуты, секунды, наносекунды)
java.time.LocalDate — это кортеж (год, месяц, день месяца)
java.time.LocalDateTime — оба кортежа вместе

К этим же классам я бы отнес еще и специфические классы для хранения части информации: java.time.MonthDay, java.time.Year, java.time.YearMonth

Все эти классы объединяет то, что они содержат временные метки или их части, но временные точки на временной оси сами по себе определить не в состоянии (даже LocalDateTime) — поскольку ни в одном из них нет ни временной зоны, ни даже смещения.

Эти классы, как и все другие, поддерживают интерфейс java.lang.Comparable, но нужно понимать, что это именно сравнение временных меток, а не временных точек:

Нужно сказать, что несмотря на неизбежные параллели в использовании между java.time.LocalTime и java.sql.Time, а также между java.time.LocalDate и java.sql.Date — это совершенно различные классы. В старом API классы java.sql.Time и java.sql.Date являются наследниками java.util.Date, а это значит, что их интерпретация (получение значения часа например) зависит от временной зоны в которой объект этого класса был создан и от временной зоны в которой этот объект будет прочитан. В новом API классы java.time.LocalTime и java.time.LocalDate — это честные кортежи значений и при записи и чтении значения часа временная зона никак не участвует.

Однако временная зона необходима при создании их из временной точки, поскольку интерпретация дней-часов от нее зависит:

Исключение выбрасывается, по причине того, что временную зону взять просто неоткуда (в Instant ее нет, а зону по-умолчанию не берем). Но ее можно получить либо из часов java.time.Clock, либо передать дополнительно:

Теперь все работает, но легкость, с которой можно сделать ошибку, несколько настораживает.

В комментариях к предыдущей статье упомянули, что настоящие параноики должны еще указывать календарь при операциях с календарными значениями (что включает создание объектов всех временных классов кроме Instant). В новом API есть несколько календарей, которые названы хронологиями:

Вообще сложно представить кейс, где может потребоваться отличная от ISO-8601 хронология IsoChronology (которая практически эквивалентна грегорианскому календарю), но, если что, новый API это поддерживает.

ZonedDateTime

java.time.ZonedDateTime — аналог java.util.Calendar. Это самый мощный класс с полной информацией о временном контексте, включает временную зону, поэтому все операции со сдвигами этот класс проводит правильно.

Попробуем создать ZonedDateTime из LocalDateTime:

Сразу же получаем по рукам за то, что в операции (в LocalDateTime) нет временной зоны, а использовать временную зону по-умолчанию новое API опять отказывается (это очень хорошо).

Посмотрим, насколько ZonedDateTime строг по отношению к некорректно указанным датам. В java.util.Calendar есть переключатель lenient, который можно настроить как на «строгий», так и на «мягкий» режим. В новом API такого переключателя нет.

29-е февраля не в високосном году не пройдет:

60-ю секунду указать нельзя:

Но указание метки в момент перевода стрелок на летнее время успешно проходит, а результат отличается от ожидаемого. В строгом режиме java.util.Calendar такое не пропускал (см. предыдущую статью).

Про операции в ZonedDateTime я ничего писать не буду — можно посмотреть документацию.

OffsetTime, OffsetDateTime

java.time.OffsetTime — это LocalTime + ZoneOffset
java.time.OffsetDateTime — это LocalDateTime + ZoneOffset

Надо сказать, что также как смещение не является временной зоной (временная зона — это история смещений, плюс еще дополнительная информация), то также OffsetDateTime хранит меньше информации чем ZonedDateTime. OffsetDateTime может полноценно обозначать временную точку на временной оси, но полностью корректные сдвиги производить не в силах, поскольку о будущих и прошлых переводах стрелок этот класс ничего не знает.

Эти классы можно использовать, если по ситуации известно только текущее смещение пользователя (например через JavaScript). Полностью корректные операции сдвигов они не позволяют сделать, поэтому лучше использовать ZonedDateTime — если есть способ выяснить полноценную временную зону пользователя. С другой стороны, между двумя экземплярами OffsetDateTime всегда можно успешно и правильно посчитать разницу в секундах.

Модификации времени

Из всех классов нового API временную точку на временной оси однозначно определяют только три: java.time.Instant, java.time.ZonedDateTime и java.time.OffsetTime.

Операции сдвига и модификации времени в общем случае выполняются корректно только в java.time.ZonedDateTime, поскольку только он один знает про временные зоны.

Выполним пример с расчетом прошедших часов в день перевода стрелок на зимнее время:

Кейсы case#1 и case#2 выполняются на полноценном классе ZonedDateTime и выдают правильный результат, поскольку в этот день стрелки переводили назад в итоге получается 25 часов.

Кейс case#3 показывает, что OffsetDateTime полноценно сохраняет информацию о точке на временной оси, но кейс case#4 показывает, что с потерей временной зоны этот класс производит вычисления уже по другому.

То же с кейсами case#5 и case#6 — несмотря на то, что Instant полноценно определяет точку на временной оси, расчеты он производит без временной зоны.

Кейсы case#7 и case#8 — показывают, что LocalDateTime не может ни полноценно отразить временную точку, ни произвести расчеты без временной зоны.

Я ни в коем случае не хочу сказать, что эти примеры показывают ошибки в новом API (если кто-то так подумал). Все эффекты ожидаемы и объяснимы. Напрягает другое — насколько такое поведение будет осознано армией Java-разработчиков. В старом API такие потенциальные проблемы были невозможны, поскольку всеми расчетами занимался только один класс java.util.Calendar, а единственное, что в нем можно было сделать неправильно — забыть явно указать временную зону.

Возможно стоило запретить большинство операций со временем во всех классах кроме ZonedDateTime, поскольку только он один в курсе переводов стрелок. Возможно стоило запретить расчет Duration с использованием LocalDateTime, поскольку без временной зоны он не определяет временную точку. Я не готов сейчас как-то серьезно дискутировать на тему возможности или невозможности таких решений, но ощущение опасности от нового API у меня есть.

Period, Duration

В новом API есть два класса для определения длительности.

java.time.Period — описание календарной длительности (периода) в виде кортежа (год, месяц, день).

java.time.Duration — описание точной длительности в виде целого количества секунд и долей текущей секунды в виде наносекунд.

Разницу между двумя можно показать в примере с днем перевода стрелок на зимнее время. Из-за перевода стрелок назад этот календарный день состоит из 25 часов.

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *