2016-04-26 123 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); 

這是不使用許多私有常量的最簡單方法。