nwGCham
nwGCham

Reputation: 313

Calender.getTimeInMillis() method returns different values in different location

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.

Upvotes: 0

Views: 1277

Answers (2)

MadProgrammer
MadProgrammer

Reputation: 347214

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

Upvotes: 1

assylias
assylias

Reputation: 328618

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

Upvotes: 3

Related Questions