0

In my application, there is a calculation to get number of days between two dates. Calculation is doing as follows;

private int getDateDiff(Date currentDate, Date previousDate){
        Calendar currDateCal = Calendar.getInstance();
        currDateCal.clear();
        currDateCal.setTime(currentDate);

        Calendar previousDateCal = Calendar.getInstance();
        previousDateCal.clear();
        previousDateCal.setTime(previousDate);

        long milisecond1 = currDateCal.getTimeInMillis();
        long milisecond2 = previousDateCal.getTimeInMillis();

        // Find date difference in milliseconds
        long diffInMSec = milisecond1 - milisecond2;

        // Find date difference in days
        // (24 hours 60 minutes 60 seconds 1000 millisecond)
        long diffOfDays = diffInMSec / (24 * 60 * 60 * 1000);

        return (int)diffOfDays;
    }

This method returns correct value (i.e. 8 for 2015-03-10 00:00:00.0, 2015-03-02 00:00:00.0, values retrieved from the repository and passes to the method) on my local pc, windows 7, 64 bit. However, this method returns incorrect value (i.e. 7 for 2015-03-10 00:00:00.0, 2015-03-02 00:00:00.0) at pc located at Canada (Windows 7, 64 bit)

The JDK information use at local PC is;

java version "1.7.0"
Java(TM) SE Runtime Environment (build 1.7.0-b147)
Java HotSpot(TM) 64-Bit Server VM (build 21.0-b17, mixed mode)

The JDK information use at Canada PC is;

java version "1.7.0_17"
Java(TM) SE Runtime Environment (build 1.7.0_17-b02)
Java HotSpot(TM) Client VM (build 23.7-b01, mixed mode, sharing)

I knew;

1) The class Date/Timestamp represents a specific instant in time, with millisecond precision since January 1, 1970, 00:00:00 GMT, So this time difference(from epoch to current time) will be same in all the computer across the world with irrespective of Timezone.
2) It doesn't know about the the given time is on which timezone.
3) If we want the time based on timezone we should go for Calendar or SimpleDateFormat in java.
4) If you try to print Date/Timestamp object (To String) it will convert and print the time with your default timezone of your machine.
5) So we can say (Date/Timestamp).getTime() object will always have UTC (time in milliseconds)
6) To conclude Date.getTime() will give UTC time. But toString() is on locale specific timezone not UTC.

Anyone see issue(s) with this calculation? I am stuck with this.

nwGCham
  • 313
  • 1
  • 3
  • 16
  • 1
    Use Joda-Time to calculate the difference between times, [as an example](http://stackoverflow.com/questions/12851934/how-to-find-difference-between-two-joda-time-datetimes-in-minutes/12852021#12852021) – MadProgrammer May 26 '15 at 05:49

2 Answers2

3

Calculating date-related things manually is error prone, as you have discovered. DST started on March 8th in Canada this year, so you are missing one hour when the time zone of your dates is in that country. I suspect that your other location does not have DST changes or it happened on a different day (for example in the UK in happened on March 29th).

You should use built-in methods to calculate the number of days elapsed between two dates. It can be done with the Calendar class but using the new Java time API (Java 8+) or joda time may save you a few headaches. For example with Java 8:

ZonedDateTime start = LocalDate.of(2015, 3, 2).atStartOfDay(UTC);
ZonedDateTime end = LocalDate.of(2015, 3, 10).atStartOfDay(UTC);
long days = DAYS.between(start, end); //8
assylias
  • 321,522
  • 82
  • 660
  • 783
  • Since the OP is using a Java 7, I assume you mean a third party library? – MadProgrammer May 26 '15 at 05:56
  • @MadProgrammer It can be done with the Calendar class but indeed not as cleanly as with Joda if on Java 7 or the Java time API if on Java 8. – assylias May 26 '15 at 05:59
  • Thanks @assylias Your answer make scene for my issue. Yes, the country, I am in, not apply DST. Since my application using jdk 1.7, there is a difficulty of using your suggestion or Joda for date calculation, instead I though to use; int dateDiff = currDateCal.get(Calendar.DAY_OF_YEAR)- previousDateCal.get(Calendar.DAY_OF_YEAR); Will that make scene? – nwGCham May 26 '15 at 06:23
  • @javaGuy Yes, unless the two dates are not in the same year. So you would need to add/subtract 365 times the number of years. Unless there is a leap year in which case you will need to adjust the result etc. It is fairly complicated but can be done. If you have the option to use joda or the backport of the java time API you should probably consider doing that. – assylias May 26 '15 at 07:01
1

Anyone see issue(s) with this calculation?

Yes, plenty, millisecond difference is unreliable for a multitude of reasons, including daylight savings (+1 assylias), leap years/seconds, century and millennium boundaries and swag of other issues

Where possible use a dedicated library. If you get to use Java 8, use the new Time API, otherwise use something like Joda-Time

DateTime startDate = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss.S").
                parseDateTime("2015-03-10 00:00:00.0");
DateTime endDate = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss.S").
                parseDateTime("2015-03-02 00:00:00.0");

Period p = new Period(endDate, startDate);
System.out.println(p.getWeeks() + ", " + p.getDays());
Duration duration = new Duration(endDate, startDate);
System.out.println(duration.getStandardDays());
System.out.println(duration.getStandardHours());
System.out.println(duration.getStandardMinutes());

Which outputs...

1, 1  // Week, days
8     // days
192   // hours
11520 // minutes
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • 1
    Solid Answer, except that I would specify a time zone when parsing those strings. Otherwise you are implicitly relying on the JVM’s current default time zone, meaning results could vary. Insert something like: `… .withZone( DateTimeZone.forID( "America/Montreal" ) ) …`. – Basil Bourque May 27 '15 at 01:46
  • @BasilBourque Valid point. That would be based on the needs, maybe you want to use the default timezone. But still a valid point – MadProgrammer May 27 '15 at 01:48
  • 1
    [a] In the case of this Question, it seems the author did indeed expect a Canada time zone (not sure which). [b] If one does indeed want the JVM’s current default time zone (which can be changed at any moment by any code in any thread in this JVM!), I suggest *explicitly* calling `DateTimeZone.getDefault()` rather than doing so *implicitly*. I suspect this implicit or unwitting use of a default time zone is the main cause of trouble in date-time work. [c] I know [MadProgrammer](http://stackoverflow.com/users/992484/madprogrammer) understands these issues; I'm making the point for others. – Basil Bourque May 27 '15 at 01:53
  • @BasilBourque And it's welcome :) (I'd be nice if the date `String`'s had the TimeZone in them :P) – MadProgrammer May 27 '15 at 01:54