Reputation: 40969
I have a Java program where I need to set a Calendar object to be midnight, so I followed the instructions from another posting on how to create a Java Date object of midnight today and midnight tomorrow, where you set the fields to be 0, like so:
calStart.set(Calendar.HOUR_OF_DAY, 0);
calStart.set(Calendar.MINUTE, 0);
calStart.set(Calendar.SECOND, 0);
calStart.set(Calendar.MILLISECOND, 0);
However, I am getting inconsistent results using Java 1.7.0_51. (Please no suggestions on using Jodatime, as I would like to use the base library only.)
Here is my test program:
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.TimeZone;
public class MidnightTester {
public static void runTestMidnight1() {
System.out.printf("runTestMidnight1() called\n");
TimeZone tz = TimeZone.getTimeZone("UTC");
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(1437004800000L);
cal.setTimeZone(tz);
System.out.printf("Original timestamp:\n");
printCalendarWithTimeZone(cal, tz);
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
System.out.printf("Timestamp after setting to midnight:\n");
printCalendarWithTimeZone(cal, tz);
}
public static void runTestMidnight2() {
System.out.printf("runTestMidnight2() called\n");
TimeZone tz = TimeZone.getTimeZone("UTC");
Calendar cal = Calendar.getInstance();
cal.setTimeZone(tz);
cal.setTimeInMillis(1437004800000L);
System.out.printf("Original timestamp:\n");
printCalendarWithTimeZone(cal, tz);
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
System.out.printf("Timestamp after setting to midnight:\n");
printCalendarWithTimeZone(cal, tz);
}
public static void printCalendarWithTimeZone(Calendar cal, TimeZone tz) {
SimpleDateFormat sdf = new SimpleDateFormat("EEEE, MMMM dd, yyyy, hh:mm:ss aaa");
sdf.setTimeZone(tz);
System.out.printf("%d= %s\n", cal.getTimeInMillis(), sdf.format(cal.getTime()));
}
public static void main(String argv[]) {
runTestMidnight1();
runTestMidnight2();
}
}
Here is the output:
runTestMidnight1() called
Original timestamp:
1437004800000= Thursday, July 16, 2015, 12:00:00 AM
Timestamp after setting to midnight:
1436918400000= Wednesday, July 15, 2015, 12:00:00 AM
runTestMidnight2() called
Original timestamp:
1437004800000= Thursday, July 16, 2015, 12:00:00 AM
Timestamp after setting to midnight:
1437004800000= Thursday, July 16, 2015, 12:00:00 AM
As you can see, in runTestMidnight1(), the day changes from July 16 to July 15 after setting the time to midnight! I don't get that.
What's more weird is that in runTestMidnight2(), I swap only two lines, and the day correctly stays the same on July 16.
cal.setTimeZone(tz);
cal.setTimeInMillis(1437004800000L);
I am in America/Pacific time, in case that matters.
Can someone help me understand what's going on?
Upvotes: 2
Views: 518
Reputation: 430
EDIT: Better Explanation
When we call setTimeInMillis(), the passed long values is assumed to be in UTC. and it calculates the time in calendar object time using user's timezone or if any timezone already available with Calendar object.
If there is no timezone passed then user's timezone gets set on calendar object. So the value '1437004800000L' considered to be in PST timezone and time gets calculated with PST timezone. Calling setTimeZone() after setting time in millis is changing the timezone in Calendar object. So the calendar object time gets moved to UTC. This is the case of runTestMidnight1(). And that's why we see a shift in date because original time was in PST.
While in second method, the timezone is first set by setTimeZone() to UTC. So the time value is '1437004800000L' and considered timezone is UTC and calculated time would be in UTC. And you gets UTC time only.
And this problem gets reproduced only if user is in timezone which behind the UTC timezone.
Hope it clarifies.
Upvotes: 3