276

I need to compare two Dates (e.g. date1 and date2) and come up with a boolean sameDay which is true of the two Dates share the same day, and false if they are not.

How can I do this? There seems to be a whirlwind of confusion here... and I would like to avoid pulling in other dependencies beyond the JDK if at all possible.

to clarify: if date1 and date2 share the same year, month, and day, then sameDay is true, otherwise it is false. I realize this requires knowledge of a timezone... it would be nice to pass in a timezone but I can live with either GMT or local time as long as I know what the behavior is.

again, to clarify:

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
Jason S
  • 184,598
  • 164
  • 608
  • 970
  • Just to clarify -- you want to know if two Date objects fall on the same day of the week? – Rob Heiser Mar 25 '10 at 17:11
  • Do you want to compare the full date (day, month, year) or only month day? – XpiritO Mar 25 '10 at 17:13
  • 1
    @Rob: no, the same day/month/year... I will clarify. – Jason S Mar 25 '10 at 17:13
  • then why don't you use "equals"? – XpiritO Mar 25 '10 at 17:14
  • 8
    Because they're not equal if the hour/minute/second are different. – Jason S Mar 25 '10 at 17:16
  • you say you want "sameDay" but in your details you state "sameDate"? – Zordid Jun 06 '13 at 06:45
  • Possible duplicate of [How to compare two Dates without the time portion?](http://stackoverflow.com/questions/1439779/how-to-compare-two-dates-without-the-time-portion) – Ole V.V. Mar 26 '17 at 09:56
  • @OleV.V. I agree but in this question I did not want to pull in any library dependencies and that question's answer uses Joda time. – Jason S Mar 27 '17 at 20:54
  • @JasonS, I just wanted to provide the link for information. You certainly have a point in avoiding a dependency on a third party library, and even if you accept one, they say that JodaTime is not the best option in 2017. [That other question](http://stackoverflow.com/questions/1439779/how-to-compare-two-dates-without-the-time-portion) has 25 answers. The accepted answer and a few others use JodaTime, most don’t. – Ole V.V. Mar 28 '17 at 02:16

14 Answers14

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

Note that "same day" is not as simple a concept as it sounds when different time zones can be involved. The code above will for both dates compute the day relative to the time zone used by the computer it is running on. If this is not what you need, you have to pass the relevant time zone(s) to the Calendar.getInstance() calls, after you have decided what exactly you mean with "the same day".

And yes, Joda Time's LocalDate would make the whole thing much cleaner and easier (though the same difficulties involving time zones would be present).

Michael Borgwardt
  • 342,105
  • 78
  • 482
  • 720
  • Thanks, that looks like it will do what I want. In my case I'm comparing successive dates in a series, so it looks like I could just use Calendar instances instead of Date instances in my series. – Jason S Mar 25 '10 at 17:20
  • 1
    @Jason That may or may not be a good idea. The main problem with Calendar is that it is a very heavyweight class with a lot of internal state, some of which is used in its equals() implementation. If you don't copmpare your dates for equality and don't put them into HashMaps, you should be fine. – Michael Borgwardt Mar 25 '10 at 17:27
  • cool, thanks, I'm just using the compare-current-and-previous-day logic asked here. the "equals" and "hashcode" functions should never get called. – Jason S Mar 25 '10 at 18:05
  • I must be missing something, why did it compare year and day and not month ? – Umer Hayat Aug 29 '14 at 09:49
  • 1
    @UmerHayat: the code compares the day of the year, not the day of the month. One less comparison necessary, shorter code. – Michael Borgwardt Aug 29 '14 at 11:00
  • 2
    Suggestion: Compare DAY_OF_YEAR first, it won't have to check the year. Ok it's not like comparing int is really expensive but ... – Martin P. Feb 11 '16 at 16:08
  • @Martin, good suggestion. The likelihood of day of year matching is much smaller that that of the year. It definitely matters where my app is concerned. – Chris - Jr Mar 04 '17 at 19:02
357

How about:

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

You can also set the timezone to the SimpleDateFormat, if needed.

Binil Thomas
  • 13,699
  • 10
  • 57
  • 70
  • 2
    (I'm actually using SimpleDateFormat anyway in my case, so it seems kind of appropriate.) – Jason S Mar 25 '10 at 18:08
  • 10
    I am actually surprised to see this, but even from a performance standpoint, this `SimpleDateFormat` method is actually faster than the other one mentioned here using `Calendar`s. On average it takes half the time as the `Calendar` method. (At least on my system). Kudos! – Michael Plautz Jul 28 '14 at 14:16
  • Most of the cost of this answer is on the SimpleDateFormat creation. Put it in a threadLocal field in a singleton if you want even better performance – Thierry Jan 21 '15 at 09:33
  • 1
    I do this in Swift too. It's amazing how such a simple thing requires the same hack in most languages. C# being the exception - if(d1.Date == d2.Date)... – Brian Birtle May 12 '16 at 17:44
175

I use the "apache commons lang" package to do this (namely org.apache.commons.lang.time.DateUtils)

boolean samedate = DateUtils.isSameDay(date1, date2);  //Takes either Calendar or Date objects
Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
Brent Watson
  • 1,751
  • 1
  • 9
  • 3
26

You can avoid external dependencies and the performance hit of using Calendar by calculating the Julian Day Number for each of the dates and then comparing these:

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;
}
AyeJay
  • 360
  • 3
  • 4
  • 4
    But beware that this [fails to take into account](http://www.xmission.com/~goodhill/dates/deltaDates.html) changes to the length of day due to daylight savings. But then straight `Date`s don't encapsulate the notion of time zones so there's no way to non-arbitrarily fix this. – AyeJay Feb 22 '11 at 14:45
  • 3
    This is by way the fastest solution -- thanks a lot, exactly what I was looking for; as I have to check a lot of dates ... – Ridcully May 11 '12 at 19:20
  • 2
    Nitpick: date1.getTime() does not return the Julian Day Number, but milliseconds since 1970-01-01. Huge difference. – Per Lindberg Jan 18 '17 at 09:14
  • 2
    This performs the comparison in the UTC time zone. If you wanted your local time zone or some other place on the planet, you cannot know whether the result you get is correct. – Ole V.V. Mar 26 '17 at 09:49
23

Joda-Time

As for adding a dependency, I'm afraid the java.util.Date & .Calendar really are so bad that the first thing I do to any new project is add the Joda-Time library. In Java 8 you can use the new java.time package, inspired by Joda-Time.

The core of Joda-Time is the DateTime class. Unlike java.util.Date, it understands its assigned time zone (DateTimeZone). When converting from j.u.Date, assign a zone.

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

LocalDate

One way to verify if two date-times land on the same date is to convert to LocalDate objects.

That conversion depends on the assigned time zone. To compare LocalDate objects, they must have been converted with the same zone.

Here is a little utility method.

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

Better would be another argument, specifying the time zone rather than assuming the first DateTime object’s time zone should be used.

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

String Representation

Another approach is to create a string representation of the date portion of each date-time, then compare strings.

Again, the assigned time zone is crucial.

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;

Span of Time

The generalized solution is to define a span of time, then ask if the span contains your target. This example code is in Joda-Time 2.4. Note that the "midnight"-related classes are deprecated. Instead use the withTimeAtStartOfDay method. Joda-Time offers three classes to represent a span of time in various ways: Interval, Period, and Duration.

Using the "Half-Open" approach where the beginning of the span is inclusive and the ending exclusive.

The time zone of the target can be different than the time zone of the interval.

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 and later comes with the java.time framework. Inspired by Joda-Time, defined by JSR 310, and extended by the ThreeTen-Extra project. See Tutorial.

The makers of Joda-Time have instructed us all to move to java.time as soon as is convenient. In the meantime Joda-Time continues as an actively maintained project. But expect future work to occur only in java.time and ThreeTen-Extra rather than Joda-Time.

To summarize java.time in a nutshell… An Instant is a moment on the timeline in UTC. Apply a time zone (ZoneId) to get a ZonedDateTime object. To move off the timeline, to get the vague indefinite idea of a date-time, use the "local" classes: LocalDateTime, LocalDate, LocalTime.

The logic discussed in the Joda-Time section of this Answer applies to java.time.

The old java.util.Date class has a new toInstant method for conversion to java.time.

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

Determining a date requires a time zone.

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

We apply that time zone object to the Instant to obtain a ZonedDateTime. From that we extract a date-only value (a LocalDate) as our goal is to compare dates (not hours, minutes, etc.).

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

Do the same to the second java.util.Date object we need for comparison. I’ll just use the current moment instead.

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

Use the special isEqual method to test for the same date value.

Boolean sameDate = localDate1.isEqual( localDate2 );
Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
  • java.time: Or you can just do `LocalDate localDate = LocalDate.fromDateFields(yourJavaUtilDate);` – CyberMew Jan 31 '17 at 04:01
  • 1
    @CyberMew Er? There is no `fromDateFields()` in [my `LocalDate` class](http://docs.oracle.com/javase/8/docs/api/java/time/LocalDate.html). – Ole V.V. Mar 26 '17 at 09:42
  • 1
    Sorry, I should have been clearer. The comment is relevant for Joda-Time [LocalDate](http://joda-time.sourceforge.net/apidocs/org/joda/time/LocalDate.html) class. – CyberMew Mar 26 '17 at 12:21
7

Convert dates to Java 8 java.time.LocalDate as seen here.

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));
Community
  • 1
  • 1
Istvan
  • 232
  • 4
  • 6
  • This is my favourite answer. If you want to control the time zone used rather than relying on the computer’s setting, it’s straightforward to put in, for example `ZoneId.of("America/Phoenix")` or `ZoneId.of("Europe/Budapest")` instead of the system default. – Ole V.V. Mar 26 '17 at 11:01
6

Java 8

If you are using Java 8 in your project and comparing java.sql.Timestamp, you could use the LocalDate class:

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

If you are using java.util.Date, have a look at Istvan answer which is less ambiguous.

amanteaux
  • 2,063
  • 21
  • 24
  • Using Java 8 is a good idea. Are you assuming `date1` and `date2` are `java.sql.Timestamp`? According to the question they are `Date`, I would understand `java.util.Date`. Also your code uses the computer’s time zone setting, which for many purposes will be fine; still I would prefer to make this fact explicit in the code. – Ole V.V. Mar 26 '17 at 09:39
  • @OleV.V. thank you for your comment, my original answer was indeed about `java.sql.Timestamp`. As you said this is generally better to explicitly set the time zone. – amanteaux Aug 14 '17 at 10:38
6

FOR ANDROID USERS:

You can use DateUtils.isToday(dateMilliseconds) to check whether the given date is current day or not.

API reference: https://developer.android.com/reference/android/text/format/DateUtils.html#isToday(long)

Hemant Kaushik
  • 1,706
  • 15
  • 22
  • 1
    This method use object Time which is Deprecated since API 22: https://developer.android.com/reference/android/text/format/Time.html – Oleksandr Bodashko Nov 08 '17 at 19:11
  • 2
    +1 for android developer. this method uses the primitive long as parameter, simply use `DateUtils.isToday(x.getTime())` (x is a java.util.date instance) will do – jackycflau Oct 01 '18 at 03:43
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);
    }
evya
  • 3,381
  • 1
  • 25
  • 28
3

For Kotlin devs this is the version with comparing formatted strings approach:

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

It's not the best way, but it's short and working.

Micer
  • 8,731
  • 3
  • 79
  • 73
  • 1
    The `SimpleDateFormat` class was supplanted years ago by the modern `java.time.DateTimeFormatter` class defined in JSR 310. Suggesting its use in 2019 is poor advice. – Basil Bourque May 12 '19 at 16:52
  • 2
    This code ignores the crucial issue of time zone. For any given moment, the date varies around the globe by zone. – Basil Bourque May 12 '19 at 16:53
1

in addition to Binil Thomas solution

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

usage

    isOnSameDay(date1,date2,date3 ...);
//or 
    isOnSameDay(mydates);
Fareed Alnamrouti
  • 30,771
  • 4
  • 85
  • 76
0

With JAVA 8 we can convert Date object to LocalDate object, hence we can do this:

public static boolean isDatesAreDifferentDays(Date date1,Date date2)
{
    LocalDate d1 = date1.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
    LocalDate d2 = date2.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
    if(d1.getDayOfMonth() != d2.getDayOfMonth())
    {
        return false;
    }
    else if(d1.getMonth() != d2.getMonth())
    {
        return false;
    }
    else if(d1.getYear() != d2.getYear())
    {
        return false;
    }
    else
    {
        return true;
    }
}
Jonathan Applebaum
  • 5,738
  • 4
  • 33
  • 52
0

FASTER SOLUTION

Like @AyeJay solution but correct for all timezones, that add a offset in timestamp.

  public static boolean isSameDay(Date dateA, Date dateB) {
    int offset = TimeZone.getDefault().getRawOffset();
    try {
        long julianDayNumber1 = (dateA.getTime() + offset) / MILLIS_PER_DAY;
        long julianDayNumber2 = (dateB.getTime() + offset) / MILLIS_PER_DAY;
        return julianDayNumber1 == julianDayNumber2;
    } catch (Exception e) {
        return false;
    }
}
José Braz
  • 575
  • 5
  • 9
-3

you can apply the same logic as the SimpleDateFormat solution without relying on SimpleDateFormat

date1.getFullYear()*10000 + date1.getMonth()*100 + date1.getDate() == 
date2.getFullYear()*10000 + date2.getMonth()*100 + date2.getDate()
jawa
  • 11
  • 2
  • 6
    These methods are deprecated in java.util.Date. You should use Calendar to do this. Also it is getYear, not getFullYear – Kris Nov 23 '11 at 10:34