2016-04-26 168 views
7

周末过滤器我想写一个布尔值函数,如果给定LocalDateTime的时间落在两个特定点之间返回true,否则为false。对Java 8 LocalDateTime

具体来说,我想有一个LocalDateTime过滤器,如果给定的日期是北京时间22:00周五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时库一个简单的解决方案(或任何其他现有的过滤方法) 。

我知道如何检查周,小时等一天,但避免推倒重来。

+3

LocalDateTime没有时区信息 - 所以在这里说GMT没有意义...... – assylias

+0

由于assylias评论说,如果你真的在UTC的时间轴上工作,你应该使用'即时'对象。 'LocalDateTime'类不*代表时间轴上的时刻;它代表了对可能时刻的模糊想法。 –

回答

2

我已经写了一个小程序来实现这一

程序

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; 
    } 

} 
+0

Thx,我有类似的东西,很好奇,如果有一个小型库的各种过滤器。 – juxeii

5

你怎么会想到这样的图书馆管理员的工作?你仍然需要告诉它当你的周末的开始和结束,它最终会被并不比简单

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

态查询

的java.time框架短得多包括架构,询问有关日期时间值:Temporal QueryTemporalQuery接口的一些实现可以在复数名为TemporalQueries的类中找到。

您可以编写自己的实现,以及。 TemporalQueryfunctional interface,这意味着它有一个声明的方法。该方法是queryFrom

这是我第一次尝试在执行TemporalQuery,所以拿一粒盐。这是完整的课程。免费使用(ISC License),但完全需要您自担风险。

棘手的部分是问题的要求是周末通过UTC来定义,而不是时区或通过日期时间值的偏移量。所以我们需要将传入的日期时间值调整为UTC。虽然Instant在逻辑上等同,我用OffsetDateTimeoffset of UTC,因为它是更灵活的。具体而言,OffsetDateTime提供了getDayOfWeek方法。

CAVEAT:我不知道我是否正在做一个正统的方法,因为我没有完全理解它的创建者所期望的java.time设计的基础。具体而言,我不知道我的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. 实例化一个TemporalQuery对象。
  2. 适用于我们的日期时间对象。
    (在我们的例子中java.time.chrono.ChronoZonedDateTime任何情况下,如ZonedDateTime

在使用中。

WeekendFri2200ToSun2300UtcQuery query = new WeekendFri2200ToSun2300UtcQuery(); 

我添加静态description方法调试和记录,以确认查询的设置。这是我自己发明的方法,不需要TemporalQuery接口。

System.out.println ("Weekend is: " + WeekendFri2200ToSun2300UtcQuery.description()); 

今天是星期二。不应该在周末。

ZonedDateTime now = ZonedDateTime.now (ZoneId.of ("America/Montreal")); 
Boolean nowIsWithinWeekend = now.query (query); 
System.out.println ("now: " + now + " is in weekend: " + nowIsWithinWeekend); 

现在这个星期五早上。周末应该不是

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); 

而在本周五晚些时候。在周末内应该为TRUE。

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 [美国/蒙特利尔]是在周末:假

friday1000:2016-04-29T10:00-04:00 [美洲/蒙特利尔]是周末:假

friday2330:2016-04-29T23:30-04:00 [美国/蒙特利尔]是周末:真

Local…并不意味着本地

参考问题...说你想c将UTC值(周末开始/停止)的值与LocalDateTime相比毫无意义。 A LocalDateTime没有UTC的偏移时区。虽然命名可能是违反直觉的,但类别意味着它们可以适用于没有特定地点的任何地点。所以它们没有意义,它们不是时间轴上的一个点,直到您应用指定的偏移量或时区。

这整个答案假设你对这个术语感到困惑,并打算比较时间线上的实际时刻。(使用.now()得到一个值来测试)

static class IsWeekendQuery implements TemporalQuery<Boolean>{ 

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

它会被称为像这样:

+0

Thx为这个详细的答案!没有意识到TemporalQuery接口。 – juxeii

+0

作为一般规则,不要在实现'Temporal *'接口时检查和投射,而应使用'.from(ta)'。因此使用'Instant.from(ta)'接受'Instant','ZonedDateTime'和'OffsetDateTime'作为输入。对于可重复使用的实用方法,我不相信UTC会是正确的路要走。相反,我会使用'LocalDateTime.from(ta)'并将时区问题留给调用者(因为算法本身不需要偏移量)。如果为查询创建静态方法,则可以将其用作'Boolean w = dateTime.query(isWeekend())' – JodaStephen

2

一个简单TemporalQuery会做的伎俩

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

或者,特别是在UTC时间(使用.now()来获得测试值):

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

超越你的问题,没有理由创造IsWeekendQuery一个新的实例每次使用时间,所以你可能要创建一个静态最终TemporalQuery封装在lambda表达式的逻辑:

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); 
0

希望这有助于:

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

这是不使用许多私有常量的最简单方法。

相关问题