ТЛ; др
LocalTime now = ZonedDateTime.now( ZoneId.of( "America/Montreal" ) )
.toLocalTime() ;
Boolean isBetween = ( ! now.isBefore( LocalTime.of( 18 , 0 ) ) // "not before" means "is equal to OR after".
&&
now.isBefore( LocalTime.of( 18 , 30 ) ) ; // Half-Open, beginning is *inclusive* while ending is *exclusive*.
Использование java.time
Вы используете старые классы даты и времени, которые оказались плохо продуманными, запутанными и хлопотными. Теперь они legacy , заменены классами java.time.
LocalTime
Не передавайте простые строки, представляющие значения времени дня. Теперь у нас есть тип для этого, LocalTime
класс.
LocalTime start = LocalTime.of( 18 , 0 );
LocalTime stop = LocalTime.of( 18 , 30 );
Передайте эти экземпляры вашему служебному методу. Этот метод не должен выполнять какой-либо синтаксический анализ, поэтому нет необходимости генерировать исключение синтаксического анализа.
public static boolean isCurrentTimeBetween( LocalTime start , LocalTime stop ) {
…
ZonedDateTime
Часовой пояс имеет решающее значение при определении текущей даты и времени суток. В любой момент времени дата меняется по всему земному шару в зависимости от зоны. Например, через несколько минут после полуночи в Париж Франция - это новый день, но все еще "вчера" в Монреаль Квебек .
Укажите собственное имя часового пояса в формате continent/region
, например America/Montreal
, Africa/Casablanca
или Pacific/Auckland
. Никогда не используйте 3-4-буквенное сокращение, например EST
или IST
, так как они не истинные часовые пояса, не стандартизированы и даже не уникальны (!).
ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = ZonedDateTime.now( z );
Чтобы сравнить текущее время, мы могли бы просто извлечь LocalTime
из этого ZonedDateTime
. Но у нас есть проблема аномалий, таких как переход на летнее время (DST) и политики, переопределяющие часовые пояса. Не может быть 6 часов вечера на определенную дату. Решение этой головоломки зависит от вашего бизнес-контекста и ваших бизнес-правил. Вы можете либо игнорировать головоломку, но и буквально спрашивать, находится ли текущее время между целевым временем начала и окончания. Или вы можете применить часовой пояс к времени начала и окончания дня и позволить классу ZonedDateTime
вносить коррективы по своему усмотрению. Давайте посмотрим на оба подхода.
Игнорировать аномалии
Во-первых, игнорируйте любые аномалии. Спросите просто и буквально, находится ли текущее время суток между целевым временем начала и окончания.
Мы можем извлечь объект времени дня из зонированного объекта даты и времени.
LocalTime localTimeNow = zdt.toLocalTime(); // Extract a time-of-day from the zoned date-time object.
Сравните это с нашим временем остановки. Обратите внимание, что мы используем здесь подход Half-Open для определения промежутка времени. В этом подходе начало включительно , а окончание исключительно . Этот подход распространен в работе с датой и временем и, как правило, является мудрым решением.
Boolean isNowOnOrAfterStart = ( ! localTimeNow.isBefore( start ) ) ; // A briefer way of asking "is equal to OR is after" is "is not before".
Boolean isNowBeforeStop = localTimeNow.isBefore( stop );
Boolean isNowInTargetZone = ( isNowOnOrAfterStart && isNowBeforeStop ); // Half-Open: beginning is inclusive while ending is exclusive.
Рассмотрим аномалии
Далее мы рассмотрим любые аномалии. Мы применяем время начала и окончания дня к текущей дате в том же часовом поясе. Мы извлекаем только дату из зонированного объекта даты и времени.
LocalDate localDateToday = zdt.toLocalDate();
ZonedDateTime zdtStart = ZonedDateTime.of( localDateToday , start , z );
ZonedDateTime zdtStop = ZonedDateTime.of( localDateToday , stop , z );
Изучите документацию класса, чтобы понять поведение ZonedDateTime.of
при разрешении неверных значений времени дня. Не существует идеального способа разрешения несуществующих значений времени дня, поэтому вы должны решить, соответствует ли этот класс вашим бизнес-правилам.
ZonedDateTime.of
public static ZonedDateTime of(LocalDate date,
LocalTime time,
ZoneId zone)
Получает экземпляр ZonedDateTime из локальной даты и времени.
Это создает зонированную дату и время, максимально соответствующие входной локальной дате и времени. Правила часового пояса, такие как переход на летнее время, означают, что не каждая местная дата и время действительны для указанной зоны, поэтому можно настроить местное время и дату.
Местное время даты и первое объединенное, чтобы сформировать местное время даты. Затем локальная дата-время разрешается в один момент времени на временной шкале. Это достигается путем нахождения действительного смещения от UTC / Гринвич для локальной даты и времени, как определено правилами идентификатора зоны.
В большинстве случаев существует только одно допустимое смещение для локальной даты и времени. В случае перекрытия, когда часы сбрасываются, есть два допустимых смещения. Этот метод использует более раннее смещение, обычно соответствующее «лету».
В случае разрыва, когда часы прыгают вперед, действительного смещения нет. Вместо этого местная дата-время корректируется, чтобы быть позже на длину промежутка. Для типичного перехода на летнее время в течение одного часа местная дата и время будут перенесены на один час позже в смещение, обычно соответствующее значению «лето».
Примените ту же логику сравнения, как мы видели выше.
Boolean isNowOnOrAfterStart = ( ! zdt.isBefore( zdtStart ) ) ; // A briefer way of asking "is equal to OR is after" is "is not before".
Boolean isNowBeforeStop = zdt.isBefore( zdtStop );
Boolean isNowInTargetZone = ( isNowOnOrAfterStart && isNowBeforeStop ); // Half-Open: beginning is inclusive while ending is exclusive.
Альтернативный способ сравнения - использовать удобный класс Interval
из проекта ThreeTen-Extra. Этот класс переносит Instant
объектов, которые вы можете извлечь из ваших ZonedDateTime
объектов. Класс Instant
представляет момент на временной шкале в UTC с разрешением наносекунд (до девяти (9) цифр десятичной дроби).
Interval interval = Interval.of( zdtStart.toInstant() , zdtStop.toInstant() );
Boolean isNowInTargetZone = interval.contains( zdt.toInstant() );
О java.time
Фреймворк java.time встроен в Java 8 и более поздние версии. Эти классы заменяют проблемные старые устаревшие классы даты и времени, такие как java.util.Date
, Calendar
, & SimpleDateFormat
.
Проект Joda-Time , в настоящее время находящийся в режиме обслуживания , рекомендует перейти на классы java.time .
Чтобы узнать больше, см. Oracle Tutorial . И поиск переполнения стека для многих примеров и объяснений. Спецификация JSR 310 .
Где получить классы java.time?
- Java SE 8 и SE 9 и выше
- Встроенный.
- Часть стандартного Java API со встроенной реализацией.
- Java 9 добавляет некоторые незначительные функции и исправления.
- Java SE 6 и SE 7
- Android
Проект ThreeTen-Extra расширяет java.time дополнительными классами. Этот проект является полигоном для возможных будущих дополнений к java.time. Здесь вы можете найти несколько полезных классов, таких как Interval
, YearWeek
, YearQuarter
и more .