tags:

views:

2463

answers:

7

I would like to have a compareTo method that ignores the time portion of a java.util.Date. I guess there are a number of ways to solve this. What's the simplest way?

+5  A: 

My preference would be to use the Joda library insetad of java.util.Date directly, as Joda makes a distinction between date and time (see YearMonthDay and DateTime classes).

However, if you do wish to use java.util.Date I would suggest writing a utility method; e.g.

public static Date setTimeToMidnight(Date date) {
    Calendar calendar = Calendar.getInstance();

    calendar.setTime( date );
    calendar.set(Calendar.HOUR_OF_DAY, 0);
    calendar.set(Calendar.MINUTE, 0);
    calendar.set(Calendar.SECOND, 0);
    calendar.set(Calendar.MILLISECOND, 0);

    return calendar.getTime();
}
Adamski
Joda-Time YearMonthDay is deprecated in favour of LocalDate.Also, the code on calendar will have issues if the time zone doesn't have midnight 00:00 due to daylight savings.
JodaStephen
+5  A: 

My preference is to use Joda Time which makes this incredibly easy:

DateTime first = ...;
DateTime second = ...;

LocalDate firstDate = first.toLocalDate();
LocalDate secondDate = second.toLocalDate();

return firstDate.compareTo(secondDate);

("Use Joda Time" is the basis of almost all SO questions which ask about java.util.Date or java.util.Calendar. It's a thoroughly superior API. If you're doing anything significant with dates/times, you should really use it if you possibly can.)

If you're absolutely forced to use the built in API, you should create an instance of Calendar with the appropriate date and using the appropriate time zone. You could then set each field in each calendar out of hour, minute, second and millisecond to 0, and compare the resulting times. Definitely icky compared with the Joda solution though :)

The time zone part is important: java.util.Date is always based on UTC. In most cases where I've been interested in a date, that's been a date in a specific time zone. That on its own will force you to use Calendar or Joda Time (unless you want to account for the time zone yourself, which I don't recommend.)

Jon Skeet
The Skeet is not wrong - JodaTime is your friend
belugabob
Altough as Jon says "Use Joda Time" is the basis of almost all SO questions which ask about java.util.Date or java.util.Calendar I always think that firstly is best to give a concrete answer based on the user's question, at least to show how hard can be to do the java way. And after that suggesting using Joda...
JuanZe
@JuanZe: That requires working out exactly how to do something properly in a painful API, which is by definition painful. I'd rather spend that time doing something more productive :)
Jon Skeet
+4  A: 

If you really want to use the java.util.Date, you would do something like this:

public class TimeIgnoringComparator extends Comparator<Date> {
  public int compare(Date d1, Date d2) {
    if (d1.getYear() != d2.getYear()) 
        return d1.getYear() - d2.getYear();
    if (d1.getMonth() != d2.getMonth()) 
        return d1.getMonth() - d2.getMonth();
    return d1.getDate() - d2.getDate();
  }
}

or, using a Calendar instead (preferred, since getYear() and such are deprecated)

public class TimeIgnoringComparator extends Comparator<Calendar> {
  public int compare(Calendar c1, Calendar c2) {
    if (c1.get(Calendar.YEAR) != c2.get(Calendar.YEAR)) 
        return d1.get(Calendar.YEAR) - d2.get(Calendar.YEAR);
    if (c1.get(Calendar.MONTH) != c2.get(Calendar.MONTH)) 
        return d1.get(Calendar.MONTH) - d2.get(Calendar.MONTH);
    return c1.get(Calendar.DAY_OF_MONTH) - c2.get(Calendar.DAY_OF_MONTH);
  }
}
Jorn
+3  A: 

I too prefer Joda Time, but here's an alternative:

long oneDay = 24 * 60 * 60 * 1000
long d1 = first.getTime() / oneDay
long d2 = second.getTime() / oneDay
d1 == d2

EDIT

I put the UTC thingy below in case you need to compare dates for a specific timezone other than UTC. If you do have such a need, though, then I really advise going for Joda.

long oneDay = 24 * 60 * 60 * 1000
long hoursFromUTC = -4 * 60 * 60 * 1000 // EST with Daylight Time Savings
long d1 = (first.getTime() + hoursFromUTC) / oneDay
long d2 = (second.getTime() + hoursFromUTC) / oneDay
d1 == d2
Daniel
That's assuming you're only interested in UTC, of course.
Jon Skeet
I said I'd rather use Joda Time, but that's a good point. I only resort to such low tactics when I'm not really interested in the TZ.
Daniel
+1  A: 

I am afraid there is no method of comparing two dates that could be called "easy" or "simple".

When comparing two time instances with any sort of reduced precision (e.g. just comparing dates), you must always take into account how time zone affects the comparison.

If date1 is specifying an event that occurred in +2 timezone and date2 is specifying an event that occurred in EST, for example, you must take care to properly understand the implications of the comparison.

Is your purpose to figure out if the two events occurred in the same calendar date in their own respective time zones? Or do You need to know if the two dates fall into the same calendar date in a specific time zone (UTC or your local TZ, for example).

Once you figure out what it is actually that You are trying to compare, it is just a matter of getting the year-month-date triple in an appropriate time zone and do the comparison.

Joda time might make the actual comparison operation look much cleaner, but the semantics of the comparison are still something You need to figure out yourself.

Roland Tepp
A: 

Any opinions on this alternative?

SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
sdf.format(date1).equals(sdf.format(date2));
Rob
I don't think that would work, even if converting to Strings was a good idea. The `==` operator doesn't necessarily return `true` for equivalent Strings (use `equals()`). You certainly can't use the other comparison operators you mentioned, either.
harto
Ahh yes - my ruby is ruining my Java! Could convert the strings to ints though for <, > etc.
Rob
Using Joda is the sound way, but this is elegant!
Arne Evertsson
We use this same solution in our project. It's not elegant but it works fine.
Lluis Martinez
A: 

Apache Commons is almost ubiquitous. So what about this?

if (DateUtils.isSameDay(date1, date2)) {
    // it's same
} else if (date1.before(date2)) {
   // it's before
} else {
   // it's after
}
André