Фильтр выходных для Java 8 LocalDateTime

Я хочу написать логическую функцию, которая возвращает true, если задано LocalDateTime попадает между двумя конкретными точками времени, в противном случае false.

в частности, я хочу иметь LocalDateTime фильтр, если заданная дата находится между 22: 00 GMT пятница и 23: 00 GMT воскресенье.

скелет может выглядеть так:

public boolean isWeekend(LocalDateTime dateTime) {
    //Checks if dateTime falls in between Friday's 22:00 GMT and Sunday's 23:00 GMT
    //return ...???
}

это в основном фильтр выходных, и мне интересно, есть ли простое решение с новой библиотекой времени Java 8(или любой другой существующей методы фильтрации).

Я знаю, как проверить день недели, час и т. д. но избегайте изобретать колесо.

5 ответов


Я написал небольшую программу для достижения этой

программа

public class TestWeekend {
    private static final int FRIDAY = 5;
    private static final int SATURDAY = 6;
    private static final int SUNDAY = 7;
    private static final Integer WEEKEND_START_FRIDAY_CUT_OFF_HOUR = 22;
    private static final Integer WEEKEND_END_SUNDAY_CUT_OFF_HOUR = 23;
    private static List<Integer> weekendDaysList = Arrays.asList(FRIDAY, SATURDAY, SUNDAY);

    public static void main(String []args) throws FileNotFoundException {
        System.out.println(" is weekend - "+isWeekend(LocalDateTime.of(2016,4,22,18,39)));
        System.out.println(" is weekend - "+isWeekend(LocalDateTime.of(2016,4,22,21,59)));
        System.out.println(" is weekend - "+isWeekend(LocalDateTime.of(2016,4,22,22,0)));
        System.out.println(" is weekend - "+isWeekend(LocalDateTime.of(2016,4,23,5,0)));
        System.out.println(" is weekend - "+isWeekend(LocalDateTime.of(2016,4,24,8,0)));
        System.out.println(" is weekend - "+isWeekend(LocalDateTime.of(2016,4,24,22,59)));
        System.out.println(" is weekend - "+isWeekend(LocalDateTime.of(2016,4,24,23,0)));
        System.out.println(" is weekend - "+isWeekend(LocalDateTime.of(2016,4,25,11,5)));
    }

    public static  boolean isWeekend(LocalDateTime dateTime) {
        System.out.print("Date - "+dateTime+" , ");
        if(weekendDaysList.contains(dateTime.getDayOfWeek().getValue()) ){
            if(SATURDAY ==  dateTime.getDayOfWeek().getValue()){
                return true;
            }
            if(FRIDAY == dateTime.getDayOfWeek().getValue() && dateTime.getHour() >=WEEKEND_START_FRIDAY_CUT_OFF_HOUR){
               return true;
            }else if(SUNDAY == dateTime.getDayOfWeek().getValue() && dateTime.getHour()  < WEEKEND_END_SUNDAY_CUT_OFF_HOUR ){
                return   true;
            }
        }
        //Checks if dateTime falls in between Friday's 22:00 GMT and Sunday's 23:00 GMT
         return false;
    }

 }

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

boolean isWeekend(LocalDateTime dt) {
    switch(dt.getDayOfWeek()) {
        case FRIDAY:
            return dt.getHour() >= ...;
        case SATURDAY:
            return true;
        case SUNDAY:
            return dt.getHour() < ...;
        default:
            return false;
    }
}

Временные Запрос

java.Time framework включает архитектуру для запроса значения даты-времени:Временные Запрос. Некоторые реализации TemporalQuery интерфейс можно найти во множественном числе-по имени TemporalQueries класса.

вы также можете написать свою собственную реализацию. TemporalQuery это функционального интерфейса, что означает, что он имеет один объявленный метод. Метод queryFrom.

это моя первая попытка на реализацию TemporalQuery, так что возьмите с солью. Вот полный класс. Бесплатно использовать (лицензия ISC), но исключительно на свой страх и риск.

хитрая часть-требование вопроса заключается в том, что выходные дни определяются UTC, а не часовым поясом или смещением переданного значения даты-времени. Поэтому нам нужно настроить переданное значение даты и времени в UTC. В то время как Instant is логически эквивалентно, я использовал OffsetDateTime С смещение UTC как это более гибким. В частности,OffsetDateTime предлагает getDayOfWeek метод.

предостережение: я понятия не имею, делаю ли я что-то ортодоксальным методом, поскольку я не полностью понимаю основы java.замыслы времени по замыслу его создателей. В частности, я не уверен, что мой кастинг TemporalAccessor ta до java.time.chrono.ChronoZonedDateTime является правильным. Но, кажется, это работает достаточно хорошо.

было бы лучше, если бы этот класс работал с Instant экземпляров, а также ChronoZonedDateTime/ZonedDateTime.

package com.example.javatimestuff;

import java.time.LocalDate;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;

/**
 * Answers whether a given temporal value is between Friday 22:00 UTC
 * (inclusive) and Sunday 23:00 UTC (exclusive).
 *
 * @author Basil Bourque. 
 * 
 * © 2016 Basil Bourque
 * This source code may be used according to the terms of the ISC License (ISC). (Basically, do anything but sue me.)
 * https://opensource.org/licenses/ISC
 *
 */
public class WeekendFri2200ToSun2300UtcQuery implements TemporalQuery<Boolean> {

    static private final EnumSet<DayOfWeek> WEEKEND_DAYS = EnumSet.of ( DayOfWeek.FRIDAY , DayOfWeek.SATURDAY , DayOfWeek.SUNDAY );
    static private final OffsetTime START_OFFSET_TIME = OffsetTime.of ( LocalTime.of ( 22 , 0 ) , ZoneOffset.UTC );
    static private final OffsetTime STOP_OFFSET_TIME = OffsetTime.of ( LocalTime.of ( 23 , 0 ) , ZoneOffset.UTC );

    @Override
    public Boolean queryFrom ( TemporalAccessor ta ) {
        if (  ! ( ta instanceof java.time.chrono.ChronoZonedDateTime ) ) {
            throw new IllegalArgumentException ( "Expected a java.time.chrono.ChronoZonedDateTime such as `ZonedDateTime`. Message # b4a9d0f1-7dea-4125-b68a-509b32bf8d2d." );
        }

        java.time.chrono.ChronoZonedDateTime czdt = ( java.time.chrono.ChronoZonedDateTime ) ta;

        Instant instant = czdt.toInstant ();
        OffsetDateTime odt = OffsetDateTime.ofInstant ( instant , ZoneOffset.UTC );
        DayOfWeek dayOfWeek = odt.getDayOfWeek ();
        if (  ! WeekendFri2200ToSun2300UtcQuery.WEEKEND_DAYS.contains ( dayOfWeek ) ) {
            // If day is not one of our weekend days (Fri-Sat-Sun), then we know this moment is not within our weekend definition.
            return Boolean.FALSE;
        }
        // This moment may or may not be within our weekend. Very early Friday or very late Sunday is not a hit.
        OffsetDateTime weekendStart = odt.with ( DayOfWeek.FRIDAY ).toLocalDate ().atTime ( START_OFFSET_TIME );  // TODO: Soft-code with first element of WEEKEND_DAYS.
        OffsetDateTime weekendStop = odt.with ( DayOfWeek.SUNDAY ).toLocalDate ().atTime ( STOP_OFFSET_TIME );  // TODO: Soft-code with last element of WEEKEND_DAYS.

        // Half-Open -> Is equal to or is after the beginning, AND is before the ending.
        // Not Before -> Is equal to or is after the beginning.
        Boolean isWithinWeekend = (  ! odt.isBefore ( weekendStart ) ) && ( odt.isBefore ( weekendStop ) );

        return isWithinWeekend;
    }

    static public String description () {
        return "WeekendFri2200ToSun2300UtcQuery{ " + START_OFFSET_TIME + " | " + WEEKEND_DAYS + " | " + STOP_OFFSET_TIME + " }";
    }

}

давайте использовать это TemporalQuery. При определении TemporalQuery принимает некоторую работу, используя его настолько очень просто и легко:

  1. создать экземпляр a не быть в выходные.
    ZonedDateTime friday1000 = ZonedDateTime.of ( LocalDate.of ( 2016 , 4 , 29 ) , LocalTime.of ( 10 , 0 ) , ZoneId.of ( "America/Montreal" ) );
    Boolean friday1000IsWithinWeekend = friday1000.query ( query );
    System.out.println ( "friday1000: " + friday1000 + " is in weekend: " + friday1000IsWithinWeekend );
    

    и поздно в эту пятницу. Должно быть, в выходные.

    ZonedDateTime friday2330 = ZonedDateTime.of ( LocalDate.of ( 2016 , 4 , 29 ) , LocalTime.of ( 23 , 30 ) , ZoneId.of ( "America/Montreal" ) );
    Boolean friday2330IsWithinWeekend = friday2330.query ( query );
    System.out.println ( "friday2330: " + friday2330 + " is in weekend: " + friday2330IsWithinWeekend );
    

    при запуске.

    выходные: WeekendFri2200ToSun2300UtcQuery{ 22:00Z | [пятница, суббота, воскресенье] | 23: 00Z }

    сейчас: 2016-04-26T20:35:01.014-04: 00[Америка/Монреаль] в выходные: false

    friday1000:2016-04-29T10:00-04: 00[Америка/Монреаль] в выходные: false

    friday2330: 2016-04-29T23:30-04:00[Америка/Монреале] в выходные: правда

    Local… не означает local

    ссылаясь на вопрос ... говоря, что вы хотите сравнить LocalDateTime к значениям в UTC (начало/остановка выходных) не имеет смысла. А LocalDateTime не имеет часового пояса смещения от-UTC. В то время как именование может быть контр-интуитивным, Local… классы означают, что они могут применяться к любой местности без конкретной местности. Поэтому они не имеют смысла, они не являются точкой на временной шкале, пока вы не примените заданное смещение или часовой пояс.

    весь этот ответ предполагает, что вы были смущены этой терминологией и намеревались сравнить фактический момент на временной шкале.


простой TemporalQuery будет делать трюк:

static class IsWeekendQuery implements TemporalQuery<Boolean>{

    @Override
    public Boolean queryFrom(TemporalAccessor temporal) {
        return temporal.get(ChronoField.DAY_OF_WEEK) >= 5;
    }
}

это будет называться так (используя .now() чтобы получить значение для проверки):

boolean isItWeekendNow = LocalDateTime.now().query(new IsWeekendQuery());

или, в частности, в UTC времени (используя .now() чтобы получить значение для проверки):

boolean isItWeekendNow = OffsetDateTime.now(ZoneOffset.UTC).query(new IsWeekendQuery());

выходя за рамки вашего вопроса, нет причин создавать новый экземпляр IsWeekendQuery каждый раз, когда он используется, поэтому вы можете создать статический финал TemporalQuery это инкапсулирует логику в лямбда-код выражение:

static final TemporalQuery<Boolean> IS_WEEKEND_QUERY = 
    t -> t.get(ChronoField.DAY_OF_WEEK) >= 5;

boolean isItWeekendNow = OffsetDateTime.now(ZoneOffset.UTC).query(IS_WEEKEND_QUERY);

надеюсь, это поможет:

LocalDateTime localDateTime = LocalDateTime.now(DateTimeZone.UTC);
int dayNum = localDateTime.get(DateTimeFieldType.dayOfWeek());
boolean isWeekend = (dayNum == DateTimeConstants.SATURDAY || dayNum == DateTimeConstants.SUNDAY);

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