Joda-Timeの2つの日付間の日数


335

2つのJoda-Time DateTimeインスタンス間の日数の違いを見つけるにはどうすればよいですか?「日差」とは、開始が月曜日で終了が火曜日である場合、開始日と終了日の時間/分/秒に関係なく、戻り値が1であることを意味します。

Days.daysBetween(start, end).getDays() 開始が夕方で、朝が終われば0を返します。

他の日付フィールドでも同じ問題が発生しているため、重要度の低いフィールドを「無視」する一般的な方法があるといいのですが。

つまり、2月から3月4日までの月も1になり、14:45から15:12までの時間も1になります。ただし、14:01と14:55の間の時差は0になります。

回答:


393

困ったことに、withTimeAtStartOfDayの答えは間違っていますが、たまにしかありません。あなたが欲しい:

Days.daysBetween(start.toLocalDate(), end.toLocalDate()).getDays()

「真夜中/ 1日の始まり」は、午前1時を意味する場合があります(夏時間はこのように場所によって異なります)。Days.daysBetweenは適切に処理しません。

// 5am on the 20th to 1pm on the 21st, October 2013, Brazil
DateTimeZone BRAZIL = DateTimeZone.forID("America/Sao_Paulo");
DateTime start = new DateTime(2013, 10, 20, 5, 0, 0, BRAZIL);
DateTime end = new DateTime(2013, 10, 21, 13, 0, 0, BRAZIL);
System.out.println(daysBetween(start.withTimeAtStartOfDay(),
                               end.withTimeAtStartOfDay()).getDays());
// prints 0
System.out.println(daysBetween(start.toLocalDate(),
                               end.toLocalDate()).getDays());
// prints 1

経由して行くことはLocalDate、全体の問題を回避し。


Days.daysBetween間違っていると思われる具体的なデータの事例を提供できますか?
バジルブルク14

と言うときInstant、あなたはについて話しているだけstart.toInstant()ではありませんか?
Patrick M

@PatrickMはい、そうでした。振り返ってみると、これがどのような制約を課すことを意図しているのかは明確ではないので、最後の文は削除します。ありがとう!
アリスパーセル

@chrispy daysBetweenドキュメントは、それが数を返すと言うWHOLE日を。私の場合、2日と1時間で3日返されます。あなたの例では、2日を返します。これを達成する方法はありますか?
Sujit Joshi 2016

@SujitJoshi申し訳ありません。Stack Overflowの完全な質問を投稿し、ここにリンクを貼り付けることをお勧めします:)
Alice Purcell

186

Days クラス

メソッドでDaysクラスを使用すると機能するwithTimeAtStartOfDayはずです。

Days.daysBetween(start.withTimeAtStartOfDay() , end.withTimeAtStartOfDay() ).getDays() 

1
ありがとう!私はjodaでandroid.text.format.DateUtils.getRelativeTimeSpanString()の動作を実現しようとしていましたが、これは本当に便利でした。
gosho_ot_pochivka 2013年

1
サー、この投稿を参照してtoDateMidnight()、DateTimeタイプのメソッドは非推奨になりました。
Aniket Kulkarni 2013

2
.toDateMidnight()の代わりに.withTimeAtStartOfDay()を使用する必要があります
bgolson

2
endがの前にある場合、start負の日を返しますか?
akhy 2015

7
@akhyar:やってみませんか?
Michael Borgwardt、2015

86

あなたは使うことができますLocalDate

Days.daysBetween(new LocalDate(start), new LocalDate(end)).getDays() 

サー、この投稿を参照してtoDateMidnight()、DateTimeタイプのメソッドは非推奨になりました。
Aniket Kulkarni 2013

なぜ使用new LocalDate(date)date.toLocalDate()ますか?
SARose、2017年

9

tl; dr

java.time.temporal.ChronoUnit.DAYS.between( 
    earlier.toLocalDate(), 
    later.toLocalDate() 
)

…または…

java.time.temporal.ChronoUnit.HOURS.between( 
    earlier.truncatedTo( ChronoUnit.HOURS )  , 
    later.truncatedTo( ChronoUnit.HOURS ) 
)

java.time

参考までに、Joda-Timeプロジェクトは現在メンテナンスモードにあり、チームは java.timeのクラス。

Joda-Timeに相当するものDateTimeZonedDateTimeです。

ZoneId z = ZoneId.of( "Pacific/Auckland" ) ;
ZonedDateTime now = ZonedDateTime.now( z ) ;

どうやらあなたは日付で日を数えたい、つまりあなたは時刻を無視したいのです。たとえば、午前0時の1分前に開始し、午前0時の1分後に終了すると、1日になります。この動作では、LocalDateからを抽出しますZonedDateTime。このLocalDateクラスは、時刻とタイムゾーンなしの日付のみの値を表します。

LocalDate localDateStart = zdtStart.toLocalDate() ;
LocalDate localDateStop = zdtStop.toLocalDate() ;

ChronoUnitenumを使用して、経過日数またはその他の単位を計算します。

long days = ChronoUnit.DAYS.between( localDateStart , localDateStop ) ;

切り捨て

このカウントを行うより一般的な方法について、60分の時間範囲としての完全な時間ではなく、時間単位の時間としての時間のデルタに関心がある場合、truncatedToメソッドを使用します。

これは、同じ日の14:45から15:12の例です。

ZoneId z = ZoneId.of( "America/Montreal" ); 
ZonedDateTime start = ZonedDateTime.of( 2017 , 1 , 17 , 14 , 45 , 0 , 0 , z );
ZonedDateTime stop = ZonedDateTime.of( 2017 , 1 , 17 , 15 , 12 , 0 , 0 , z );

long hours = ChronoUnit.HOURS.between( start.truncatedTo( ChronoUnit.HOURS ) , stop.truncatedTo( ChronoUnit.HOURS ) );

1

これは数日間機能しません。この場合はtoLocalDate()を使用します。


java.timeについて

java.timeのフレームワークは、Java 8に組み込まれており、後にされています。これらのクラスは面倒古い取って代わるレガシーのような日付時刻クラスをjava.util.DateCalendar、& SimpleDateFormat

ジョダタイムプロジェクトは、今でメンテナンスモードへの移行をアドバイスjava.timeのクラス。

詳細については、Oracleチュートリアルを参照してください。スタックオーバーフローで多くの例と説明を検索してください。仕様はJSR 310です。

java.timeオブジェクトをデータベースと直接交換することができます。JDBC 4.2以降に準拠したJDBCドライバーを使用します。文字列もクラスも必要ありません。java.sql.*

java.timeクラスはどこで入手できますか?

  • Java SE 8 Java SE 9 Java SE 10以降
    • ビルトイン。
    • 実装がバンドルされた標準Java APIの一部。
    • Java 9では、いくつかのマイナーな機能と修正が追加されています。
  • Java SE 6および Java SE 7
    • java.time機能の多くは、ThreeTen-BackportでJava 6および7にバックポートされています。
  • アンドロイド
    • それ以降のバージョンのAndroidには、java.timeクラスの実装がバンドルされています。
    • 以前のAndroid(<26)では、ThreeTenABPプロジェクトはThreeTen-Backport(上記)を採用しています。ThreeTenABPの使用方法…を参照してください。

ThreeTen-エクストラプロジェクトでは、追加のクラスでjava.timeを拡張します。このプロジェクトは、java.timeに将来追加される可能性があることを証明する場です。あなたはここにいくつかの有用なクラスのような見つけることがIntervalYearWeekYearQuarter、および多くを

ThreeTen-エクストラプロジェクトでは、追加のクラスでjava.timeを拡張します。このプロジェクトは、java.timeに将来追加される可能性があることを証明する場です。あなたはここにいくつかの有用なクラスのような見つけることがIntervalYearWeekYearQuarter、および多くを


truncateを使用した日のTL; DRは、受け入れられた回答に詳述されているバグの犠牲になります。つまり、1日の始まりが午前1時にある場合、1つずれています。toLocalDateを使用して、さらに下の正しい答えを使用するように更新しました。
アリスパーセル

2

受け入れられた答えは2つのLocalDateオブジェクトを構築しますが、大量のデータを読み取る場合は非常にコストがかかります。私はこれを使います:

  public static int getDaysBetween(DateTime earlier, DateTime later)
  {
    return (int) TimeUnit.MILLISECONDS.toDays(later.getMillis()- earlier.getMillis());
  }

呼び出すgetMillis()ことにより、既存の変数を使用します。
MILLISECONDS.toDays()次に、単純な算術計算を使用して、オブジェクトを作成しません。


1
この回答は、タイムゾーンと日付に関係なく、「日」の定義が正確に24時間である場合にのみ機能します。その場合は、このアプローチを使用してください。そうでない場合は、タイムゾーンに関する他の回答を参照してください。
バジルブルク

@BasilBourque、そうです、それでも、メソッド呼び出しごとに高価なオブジェクトを構築するのではなく、算術計算に基づくソリューションを選びます。Webページから入力を読み取る場合、そのような計算には多くのフレーバーがあります。大丈夫かもしれませんが、数十万行のログファイルを処理している場合、これは非常に遅くなります
JBoy

1
ループがホットな場合、Javaはオブジェクトの割り当てを最適化します。docs.oracle.com/javase/7/docs/technotes/guides/vm/…を
Alice Purcell

1

java.time.Period

java.time.Periodクラスを使用して日数数えます

Java 8は差を計算するのがより直感的LocalDateであるLocalDateTimeため、2つの日付を表すには

    LocalDate now = LocalDate.now();
    LocalDate inputDate = LocalDate.of(2018, 11, 28);

    Period period = Period.between( inputDate, now);
    int diff = period.getDays();
    System.out.println("diff = " + diff);

0
DateTime  dt  = new DateTime(laterDate);        

DateTime newDate = dt.minus( new  DateTime ( previousDate ).getMillis());

System.out.println("No of days : " + newDate.getDayOfYear() - 1 );    

-11
public static int getDifferenceIndays(long timestamp1, long timestamp2) {
    final int SECONDS = 60;
    final int MINUTES = 60;
    final int HOURS = 24;
    final int MILLIES = 1000;
    long temp;
    if (timestamp1 < timestamp2) {
        temp = timestamp1;
        timestamp1 = timestamp2;
        timestamp2 = temp;
    }
    Calendar startDate = Calendar.getInstance(TimeZone.getDefault());
    Calendar endDate = Calendar.getInstance(TimeZone.getDefault());
    endDate.setTimeInMillis(timestamp1);
    startDate.setTimeInMillis(timestamp2);
    if ((timestamp1 - timestamp2) < 1 * HOURS * MINUTES * SECONDS * MILLIES) {
        int day1 = endDate.get(Calendar.DAY_OF_MONTH);
        int day2 = startDate.get(Calendar.DAY_OF_MONTH);
        if (day1 == day2) {
            return 0;
        } else {
            return 1;
        }
    }
    int diffDays = 0;
    startDate.add(Calendar.DAY_OF_MONTH, diffDays);
    while (startDate.before(endDate)) {
        startDate.add(Calendar.DAY_OF_MONTH, 1);
        diffDays++;
    }
    return diffDays;
}

1
質問は具体的にはjoda-timeを探しています。
kapad 2015
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.