2つのjava.util.Datesを比較して、それらが同じ日にあるかどうかを確認する


249

私は2つDateのを比較する必要があります(例:date1date2boolean sameDay、2つDateのsが同じ日に一致する場合はtrueを、そうでない場合はfalseを見つける必要があります。

これどうやってするの?ここには混乱の渦巻きがあるようです...そして、可能な限り、JDK以外の他の依存関係を引き込まないようにしたいと思います。

明確にするため:同じ年、月、日date1date2共有している場合sameDayはtrue、そうでない場合はfalseです。これにはタイムゾーンの知識が必要であることに気づきます...タイムゾーンを渡すのは良いことですが、動作がわかっている限り、GMTまたは現地時間のどちらでも使用できます。

再度、明確にするために:

date1 = 2008 Jun 03 12:56:03
date2 = 2008 Jun 03 12:59:44
  => sameDate = true

date1 = 2009 Jun 03 12:56:03
date2 = 2008 Jun 03 12:59:44
  => sameDate = false

date1 = 2008 Aug 03 12:00:00
date2 = 2008 Jun 03 12:00:00
  => sameDate = false

明確にするために-2つのDateオブジェクトが同じ曜日にあるかどうかを知りたいですか?
Rob Heiser、2010年

完全な日付(日、月、年)または月の日のみを比較しますか?
XpiritO 2010年

1
@ロブ:いいえ、同じ日/月/年...明確にします。
Jason S

それでは、なぜ「等しい」を使用しないのですか?
XpiritO 2010年

7
時間/分/秒が異なる場合は等しくないためです。
Jason S

回答:


416
Calendar cal1 = Calendar.getInstance();
Calendar cal2 = Calendar.getInstance();
cal1.setTime(date1);
cal2.setTime(date2);
boolean sameDay = cal1.get(Calendar.DAY_OF_YEAR) == cal2.get(Calendar.DAY_OF_YEAR) &&
                  cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR);

「同じ日」は、異なるタイムゾーンが関係する可能性がある場合に聞こえるほど単純な概念ではないことに注意してください。上記のコードは、両方の日付について、それが実行されているコンピューターで使用されているタイムゾーンを基準にして日を計算します。これが必要なものでない場合はCalendar.getInstance()、「同じ日」で正確に何を意味するかを決定した後で、関連するタイムゾーンを呼び出しに渡す必要があります。

そして、はい、Joda Time's LocalDateを使用すると、全体がよりクリーンで簡単になります(ただし、タイムゾーンに関連する同じ問題が存在します)。


ありがとう、それは私が望むことをするように見えます。私の場合、シリーズの連続する日付を比較しているので、シリーズのDateインスタンスの代わりにCalendarインスタンスを使用できるように見えます。
Jason S

1
@ジェイソンそれは良い考えかもしれませんし、そうでないかもしれません。Calendarの主な問題は、それが非常に重いクラスであり、内部状態が多く、その一部がequals()実装で使用されていることです。日付が等しいかどうかを比較せずに、それらをHashMapに入れない場合は、問題ありません。
Michael Borgwardt 2010年

クール、ありがとう、ここで尋ねられた現在と前日の比較ロジックを使用しています。「等しい」および「ハッシュコード」関数が呼び出されることはありません。
Jason S

1
@UmerHayat:コードは、月の日ではなく、年の日を比較します。比較が1つ少なくなり、コードが短くなります。
Michael Borgwardt 2014

2
提案:最初にDAY_OF_YEARを比較してください。年を確認する必要はありません。わかりました、intを比較するのは本当に高価ですが、そうではありませんが...
Martin P.

332

どうですか:

SimpleDateFormat fmt = new SimpleDateFormat("yyyyMMdd");
return fmt.format(date1).equals(fmt.format(date2));

必要に応じて、タイムゾーンをSimpleDateFormatに設定することもできます。


2
(私はとにかく実際にはSimpleDateFormatを使用しているので、それは一種の適切なようです。)
Jason S

8
私は実際にこれを見て驚いていますが、パフォーマンスの観点から見ても、このSimpleDateFormat方法は実際にCalendars を使用してここで説明した他の方法よりも高速です。平均して、Calendarメソッドの半分の時間で済みます。(少なくとも私のシステムでは)。賞賛!
Michael Plautz、2014

この回答のコストのほとんどは、SimpleDateFormatの作成にかかっています。さらに良いパフォーマンスが必要な場合は、シングルトンのthreadLocalフィールドに入れてください
Thierry

1
私もSwiftでこれを行います。このような単純なことで、ほとんどの言語で同じハックが必要なのは驚くべきことです。C#は例外です-if(d1.Date == d2.Date)...
alpsystems.com

2
これは醜いです。このようなハックが賛成されているのを見て驚いた。
Zsolt Safrany

162

「apache commons lang」パッケージを使用してこれを行います(つまり、org.apache.commons.lang.time.DateUtils

boolean samedate = DateUtils.isSameDay(date1, date2);  //Takes either Calendar or Date objects

2
これは外部依存関係を使用します...しかし、将来について知っておくのは良いことです。
Jason S

20
ソースをコピーして、それを1日と呼びます:)
アントン・クズミン

しかし、いずれかの日がnullの場合、不正な引数例外をスローします。これは、場合によっては理想的ではありません。
raviraja

1
stackoverflow.com/a/2517824/1665809でコメントされているように、異なるタイムゾーンが関係している場合、このソリューションは適切ではない可能性があります。
mrod

24

各日付のユリウス日数を計算してからこれらを比較することにより、外部依存関係とカレンダーの使用によるパフォーマンスへの影響を回避できます。

public static boolean isSameDay(Date date1, Date date2) {

    // Strip out the time part of each date.
    long julianDayNumber1 = date1.getTime() / MILLIS_PER_DAY;
    long julianDayNumber2 = date2.getTime() / MILLIS_PER_DAY;

    // If they now are equal then it is the same day.
    return julianDayNumber1 == julianDayNumber2;
}

4
ただし、これ夏時間による日の長さの変更を考慮に入れていないことに注意してください。ただし、ストレートDatesはタイムゾーンの概念をカプセル化しないため、これを勝手に修正する方法はありません。
AyeJay、2011

3
これは、最速の解決策です。私が探していたものに感謝します。多くの日付をチェックする必要があるので...
Ridcully

2
Nitpick:date1.getTime()はユリウス日番号を返さず、1970-01-01からのミリ秒を返します。大きな違い。
リンドバーグによる

2
これにより、UTCタイムゾーンで比較が実行されます。ローカルタイムゾーンまたは惑星の他の場所が必要な場合、得られる結果が正しいかどうかはわかりません。
Ole VV 2017年

20

ジョーダタイム

依存関係の追加に関しては、java.util.Date&.Calendarが本当に悪いので、新しいプロジェクトに最初に行うのはJoda-Timeライブラリーの追加です。Java 8では、Joda-Timeに触発された新しいjava.timeパッケージを使用できます。

Joda-Timeの中核はDateTimeクラスです。java.util.Dateとは異なり、割り当てられたタイムゾーン(DateTimeZone)を理解します。juDateから変換する場合は、ゾーンを割り当てます。

DateTimeZone zone = DateTimeZone.forID( "America/Montreal" );
DateTime dateTimeQuébec = new DateTime( date , zone );

LocalDate

2つの日時が同じ日付にあるかどうかを確認する1つの方法は、LocalDateオブジェクトに変換することです。

その変換は、割り当てられたタイムゾーンによって異なります。LocalDateオブジェクトを比較するには、同じゾーンで変換されている必要があります。

ここで少し実用的な方法です。

static public Boolean sameDate ( DateTime dt1 , DateTime dt2 )
{
    LocalDate ld1 = new LocalDate( dt1 );
    // LocalDate determination depends on the time zone.
    // So be sure the date-time values are adjusted to the same time zone.
    LocalDate ld2 = new LocalDate( dt2.withZone( dt1.getZone() ) );
    Boolean match = ld1.equals( ld2 );
    return match;
}

最初のDateTimeオブジェクトのタイムゾーンを使用する必要があると想定するのではなく、タイムゾーンを指定する別の引数を使用することをお勧めします。

static public Boolean sameDate ( DateTimeZone zone , DateTime dt1 , DateTime dt2 )
{
    LocalDate ld1 = new LocalDate( dt1.withZone( zone ) );
    // LocalDate determination depends on the time zone.
    // So be sure the date-time values are adjusted to the same time zone.
    LocalDate ld2 = new LocalDate( dt2.withZone( zone ) );
    return ld1.equals( ld2 );
}

文字列表現

別のアプローチは、各日時の日付部分の文字列表現を作成し、文字列を比較することです。

繰り返しますが、割り当てられたタイムゾーンは非常に重要です。

DateTimeFormatter formatter = ISODateTimeFormat.date();  // Static method.
String s1 = formatter.print( dateTime1 );
String s2 = formatter.print( dateTime2.withZone( dt1.getZone() )  );
Boolean match = s1.equals( s2 );
return match;

一定の期間

一般的な解決策は、期間を定義し、その期間にターゲットが含まれているかどうかを確認することです。このサンプルコードはJoda-Time 2.4に含まれています。「深夜」関連のクラスは非推奨であることに注意してください。代わりにwithTimeAtStartOfDayメソッドを使用してください。Joda-Timeは、時間間隔をさまざまな方法で表すために、間隔、期間、および期間の3つのクラスを提供します。

スパンの開始が包括的で終了が排他的である「ハーフオープン」アプローチの使用。

ターゲットのタイムゾーンは、間隔のタイムゾーンと異なる場合があります。

DateTimeZone timeZone = DateTimeZone.forID( "Europe/Paris" );
DateTime target = new DateTime( 2012, 3, 4, 5, 6, 7, timeZone );
DateTime start = DateTime.now( timeZone ).withTimeAtStartOfDay();
DateTime stop = start.plusDays( 1 ).withTimeAtStartOfDay();
Interval interval = new Interval( start, stop );
boolean containsTarget = interval.contains( target );

java.time

Java 8以降には、java.timeフレームワークが付属しています。JSR 310によって定義され、ThreeTen-Extraプロジェクトによって拡張されたJoda-Timeに触発されました。チュートリアルを参照してください。

Joda-Timeのメーカーは、都合のよいときにすぐにjava.timeに移動するように私たち全員に指示しました。その間、Joda-Timeは積極的に維持されているプロジェクトとして継続します。ただし、将来の作業はJoda-Timeではなくjava.timeとThreeTen-Extraでのみ発生することを期待してください。

java.timeを要約するInstantと…An はUTCのタイムラインの瞬間です。タイムゾーン(ZoneId)を適用してZonedDateTimeオブジェクトを取得します。日時の漠然と不定アイデアを得るために、タイムラインをオフに移動するには、「ローカル」なクラスを使用しますLocalDateTimeLocalDateLocalTime

この回答のJoda-Timeセクションで説明されているロジックは、java.timeに適用されます。

古いjava.util.Dateクラスには、toInstantjava.timeに変換するための新しいメソッドがあります。

Instant instant = yourJavaUtilDate.toInstant(); // Convert into java.time type.

日付を決定するにはタイムゾーンが必要です。

ZoneId zoneId = ZoneId.of( "America/Montreal" );

そのタイムゾーンオブジェクトをに適用して、Instantを取得しZonedDateTimeます。そのLocalDate目的は日付(時間、分などではなく)を比較することなので、日付のみの値(a )を抽出します。

ZonedDateTime zdt1 = ZonedDateTime.ofInstant( instant , zoneId );
LocalDate localDate1 = LocalDate.from( zdt1 );

java.util.Date比較に必要な2番目のオブジェクトについても同じことを行います。代わりに現在の瞬間を使用します。

ZonedDateTime zdt2 = ZonedDateTime.now( zoneId );
LocalDate localDate2 = LocalDate.from( zdt2 );

特別なisEqualメソッドを使用して、同じ日付値をテストします。

Boolean sameDate = localDate1.isEqual( localDate2 );

java.time:または、次のことができますLocalDate localDate = LocalDate.fromDateFields(yourJavaUtilDate);
Cyber​​Mew 2017年

1
@Cyber​​Mew Er?何もありませんfromDateFields()、私のLocalDateクラス
Ole VV 2017年

1
すみません、もっとはっきりしていたはずです。コメントは、Joda -Time LocalDateクラスに関連しています。
Cyber​​Mew 2017年

7

ここに示すように、日付をJava 8 java.time.LocalDateに変換し ます

LocalDate localDate1 = date1.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
LocalDate localDate2 = date2.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();

// compare dates
assertTrue("Not on the same day", localDate1.equals(localDate2));

これが私のお気に入りの答えです。コンピュータの設定に依存するのではなく、使用するタイムゾーンを制御する場合は、たとえばシステムのデフォルトの代わりに、ZoneId.of("America/Phoenix") またはZoneId.of("Europe/Budapest")システムのデフォルトの代わりに入力するのが簡単です。
Ole VV 2017年

6

Java 8

プロジェクトでJava 8をjava.sql.Timestamp使用して比較している場合は、LocalDateクラスを使用できます。

sameDate = date1.toLocalDateTime().toLocalDate().equals(date2.toLocalDateTime().toLocalDate());

を使用java.util.Dateしている場合は、あいまいさの少ないIstvanの回答をご覧ください。


Java 8を使用することをお勧めします。あなたは仮定date1date2ていjava.sql.Timestampますか?彼らの質問によるとDate、私は理解するでしょうjava.util.Date。また、コードはコンピューターのタイムゾーン設定を使用します。これは多くの目的で問題ありません。それでも私はこの事実をコードで明示したいと思います。
Ole VV 2017年

@ OleV.V。コメントありがとうございますjava.sql.Timestamp。私の元の答えは確かにでした。あなたが言ったように、これは一般的に明示的にタイムゾーンを設定する方が良いです。
amanteaux 2017

5
private boolean isSameDay(Date date1, Date date2) {
        Calendar calendar1 = Calendar.getInstance();
        calendar1.setTime(date1);
        Calendar calendar2 = Calendar.getInstance();
        calendar2.setTime(date2);
        boolean sameYear = calendar1.get(Calendar.YEAR) == calendar2.get(Calendar.YEAR);
        boolean sameMonth = calendar1.get(Calendar.MONTH) == calendar2.get(Calendar.MONTH);
        boolean sameDay = calendar1.get(Calendar.DAY_OF_MONTH) == calendar2.get(Calendar.DAY_OF_MONTH);
        return (sameDay && sameMonth && sameYear);
    }

5

Androidユーザー向け:

を使用DateUtils.isToday(dateMilliseconds)して、指定した日付が現在の日付であるかどうかを確認できます。

APIリファレンス:https : //developer.android.com/reference/android/text/format/DateUtils.html#isToday(long)


1
このメソッドは、API 22以降非推奨のオブジェクトTimeを使用します:developer.android.com/reference/android/text/format/Time.html
Oleksandr Bodashko

2
Android開発者の+1。このメソッドは、パラメータとしてプリミティブを使用し、単純にDateUtils.isToday(x.getTime())(xはjava.util.dateインスタンスです)使用します
jackycflau

1

Binil Thomasソリューションに加えて

public static boolean isOnSameDay(Timestamp... dates) {
    SimpleDateFormat fmt = new SimpleDateFormat("yyyyMMdd");
    String date1 = fmt.format(dates[0]);
    for (Timestamp date : dates) {
        if (!fmt.format(date).equals(date1)) {
            return false;
        }
    }
    return true;
}

使用法

    isOnSameDay(date1,date2,date3 ...);
//or 
    isOnSameDay(mydates);

1

Kotlin開発者にとって、これはフォーマットされた文字列アプローチを比較するバージョンです:

val sdf = SimpleDateFormat("yyMMdd")
if (sdf.format(date1) == sdf.format(date2)) {
    // same day
}

それは最善の方法ではありませんが、短くて機能しています。


1
このSimpleDateFormatクラスは、数年前java.time.DateTimeFormatterにJSR 310で定義された最新のクラスに取って代わられました。2019年にその使用を提案することはあまりお勧めできません。
バジルブルク

2
このコードは、タイムゾーンの重要な問題を無視します。特定の瞬間において、日付は世界中でゾーンごとに異なります。
バジルブルク

-4

SimpleDateFormatに依存せずに、SimpleDateFormatソリューションと同じロジックを適用できます

date1.getFullYear()*10000 + date1.getMonth()*100 + date1.getDate() == 
date2.getFullYear()*10000 + date2.getMonth()*100 + date2.getDate()

6
これらのメソッドは、java.util.Dateでは非推奨です。これを行うには、カレンダーを使用する必要があります。また、getFullYearではなくgetYearです
クリス
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.