tags:

views:

92

answers:

5

Say I have two date fields receiveDate and currentDate. I want to check if receiveDate was 5 days before currentDate. What I did was to convert the dates in milliseconds and then compare against 5. Is there a better way of doing so? If so, how and why mine is any less better? Thanks.

Method I wrote -

private static final double DAY_IN_MILLISECONDS = 86400000;

// Param date is the receivedDate
private long getDaysOld(final Date date) {


    Calendar suppliedDate = Calendar.getInstance();
    suppliedDate.setTime(date);
    Calendar today = Calendar.getInstance();
    today.setTime(currentDate);

    double ageInMillis = (today.getTimeInMillis() - suppliedDate.getTimeInMillis());
    double tempDouble;

    if(isEqual(ageInMillis, 0.00) || isGreaterThan(Math.abs(ageInMillis), DAY_IN_MILLISECONDS)) {
        tempDouble =  ageInMillis / DAY_IN_MILLISECONDS;
    } else {
        tempDouble =  DAY_IN_MILLISECONDS / ageInMillis;
    }

    long ageInDays = Math.round(tempDouble);

    return ageInDays;


}

Then I have something like-

long daysOld = getDaysOld(receivedDate) ;   
if(daysOld <= 5) {
    .... some business code ....
}
+3  A: 

give a try to joda-time. Time calculations with the native API is always akwards at best. Joda time makes this type of calculation MUUUCH simpler and will handle time zones pretty well also.

Newtopian
A: 

It can be shortened a lot:

int daysOld = (System.currentTimeMillis() - date.getTime()) / DAY_IN_MILLISECONDS;
Eugene Kuleshov
That's shorter, but it's also incorrect. Hint: % is not the operator you're looking for.
Tom Anderson
Yep, this is wrong.
dogbane
+2  A: 
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;


public class Test {

    private static long DAY_IN_MILLISECONDS = 24 * 60 * 60 * 1000;

    public static void main(String[] args) throws Exception {
        //
        Date currentDate = getGregorianDate(1990, Calendar.JANUARY, 20);
        Date receiveDate = getGregorianDate(1990, Calendar.JANUARY, 23);
        //
        if (getDifferenceBetweenDates(receiveDate, currentDate) < 5 * DAY_IN_MILLISECONDS) {
            System.out.println("Receive date is not so old.");
        }
        else {
            System.out.println("Receive date is very old.");
        }
    }

    private static long getDifferenceBetweenDates(Date date1, Date date2) {
        return Math.abs(date1.getTime() - date2.getTime());
    }

    private static Date getGregorianDate(int year, int month, int date) {
        Calendar calendar = GregorianCalendar.getInstance();
        calendar.set(year, month, date);
        return calendar.getTime();
    }

}
Lavir the Whiolet
A: 

You can't simply subtract and divide by 24*60*60*1000, because of daylight savings (in which a day could have 23 or 25 hours).

For example, in the UK the clocks moved forward by one hour on 28/03/2010. The difference between 27/03/2010 and 28/03/2010 should be 1 day, but if you follow that approach you will get 0.

You need to take the offset into account:

public static long daysBetween(Date dateEarly, Date dateLater) {
    Calendar cal1 = Calendar.getInstance();
    cal1.setTime(dateEarly);  
    Calendar cal2 = Calendar.getInstance();
    cal2.setTime(dateLater);

    long endL = cal2.getTimeInMillis() + cal2.getTimeZone().getOffset( cal2.getTimeInMillis() );
    long startL = cal1.getTimeInMillis() + cal1.getTimeZone().getOffset( cal1.getTimeInMillis() );
    return (endL - startL) / (24 * 60 * 60 * 1000);
}

public static void main(String[] args) throws Exception {

    TimeZone.setDefault(TimeZone.getTimeZone("Europe/London"));  

    Date foo = new Date(2010,02,27);
    Date bar= new Date(2010,02,28);

    System.out.println(daysBetween(foo,bar)); //prints 1
}
dogbane
That Date constructor is deprecated, because Date isn't very good at handling dates (despite the name - don't know whose idea that was). You can do much the same thing with Calendar, though.
Tom Anderson
A: 

This all depends on what "five days" means. If you receive something monday lunchtime, then on saturday afternoon, did you receive it within five days or not? The elapsed time is greater than five days, but the day you received it is five days ago. Think about how you'd answer that question; now thing about how your mother would answer that question. It might not be the same - I would suggest that most people, particularly non-programmers, count the passing of days by the passing of local midnights. Five o'clock on wednesday morning is a day after eleven thirty on tuesday night, even though it's less than a day (less than a quarter of a day!) later.

So, i think what you want to do is compare just the dates, not the times. You can do this with Calendar by zeroing all the time fields. Given an arrivedDate and a locale (so you can tell when midnight is), i think this is correct:

    Calendar deadline = Calendar.getInstance(locale);
    deadline.set(Calendar.HOUR_OF_DAY, 0);
    deadline.set(Calendar.MINUTE, 0);
    deadline.set(Calendar.SECOND, 0);
    deadline.set(Calendar.MILLISECOND, 0);
    deadline.add(Calendar.DAY_OF_MONTH, 5);

    Calendar arrived = Calendar.getInstance(locale);
    arrived.setTime(arrivedDate);
    deadline.set(Calendar.HOUR_OF_DAY, 0);
    deadline.set(Calendar.MINUTE, 0);
    deadline.set(Calendar.SECOND, 0);
    deadline.set(Calendar.MILLISECOND, 0);

    boolean arrivedWithinDeadline = arrived.compareTo(deadline) <= 0;

You should test that thoroughly before actually using it, though.

Tom Anderson