2016-04-26 17 views
7

与えられたLocalDateTimeが2つの特定の時点の間にある場合に真を返すブール値の関数を書きたいと思います。Java 8の週末フィルタLocalDateTime

具体的には、与えられた日付が22:00 GMT金曜日と23:00 GMT日曜日の間にある場合、LocalDateTimeフィルタが必要です。

スケルトンは次のようになります。

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

私はあなたがそのようなライブラリが動作するように期待する方法この

PROGRAM

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です。

の実装時に私が最初に試したのはなので、塩の粒をとってください。ここには完全なクラスがあります。無料(ISC License)を使用することができますが、完全に自己責任で行ってください。

難しい部分は、渡された日時値のタイムゾーンまたはオフセットではなく、週末がUTCで定義されるという質問です。だから渡された日時の値をUTCに調整する必要があります。 Instantは論理的には同等ですが、はoffset 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 | [FRIDAY、SATURDAY、SUNDAY] | 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にしたいと言っているLocalDateTimeをUTC(週末の開始/停止)の値に変更することは意味がありません。 LocalDateTimeには、UTCからのオフセットのタイムゾーンはありません。命名は直感的ではないかもしれませんが、Local…クラスは、特にローカリティのない地域に適用できることを意味します。だから、彼らは意味がありません、あなたは指定されたオフセットやタイムゾーンを適用するまで、タイムライン上のポイントではありません。

この全体の回答は、この用語について混乱し、タイムライン上の実際の瞬間を比較しようとしていたことを前提としています。それは(テストする値を取得するために.now()を使用して)、このように呼ばれることになる

static class IsWeekendQuery implements TemporalQuery<Boolean>{ 

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

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

あるいは、特にUTC時間に(

+0

Thx! TemporalQueryインターフェイスを認識していませんでした。 – juxeii

+0

一般的なルールとして、 'Temporal *'インタフェースを実装するときは、決してチェックしてキャストしないでください。代わりに '.from(ta)'を使用してください。したがって、 'Instant'、' ZonedDateTime'および 'OffsetDateTime'を入力として受け入れる' Instant.from(ta) 'を使用してください。再利用可能なユーティリティメソッドの場合、私はUTCが正しい方法であるとは確信していません。代わりに 'LocalDateTime.from(ta)'を使用し、呼び出し側にタイムゾーンの問題を残します(アルゴリズム自体はオフセットを必要としないため)。クエリの静的メソッドを作成すると、 'ブール値= dateTime.query(isWeekend())' – JodaStephen

2

シンプルTemporalQueryは、トリックを行うだろう.now()を使用してテストする値を取得します)。

boolean isItWeekendNow = OffsetDateTime.now(ZoneOffset.UTC).query(new IsWeekendQuery()); 
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

希望:あなたの質問にとどまらず、あなたはラムダ式のロジックをカプセル化するのstatic final TemporalQueryを作成したい場合がありますので、IsWeekendQueryのそれが使用されるたびに新しいインスタンスを作成する理由はありませんこれは役に立ちます:

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

これは、多くのプライベート定数を使用せずに行うための最も簡単な方法です。

関連する問題