The System.out.println(cal_Two.getTime()) invocation returns a Date from getTime(). It is the Date which is getting converted to a string for println, and that conversion will use the default IST timezone in your case.
You'll need to explicitly use DateFormat.setTimeZone() to print the Date in the desired timezone.
EDIT: Courtesy of @Laurynas, consider this:
TimeZone timeZone = TimeZone.getTimeZone("UTC");
Calendar calendar = Calendar.getInstance(timeZone);
SimpleDateFormat simpleDateFormat =
new SimpleDateFormat("EE MMM dd HH:mm:ss zzz yyyy", Locale.US);
simpleDateFormat.setTimeZone(timeZone);
System.out.println("Time zone: " + timeZone.getID());
System.out.println("default time zone: " + TimeZone.getDefault().getID());
System.out.println();
System.out.println("UTC: " + simpleDateFormat.format(calendar.getTime()));
System.out.println("Default: " + calendar.getTime());
Answer from mockinterface on Stack OverflowThe System.out.println(cal_Two.getTime()) invocation returns a Date from getTime(). It is the Date which is getting converted to a string for println, and that conversion will use the default IST timezone in your case.
You'll need to explicitly use DateFormat.setTimeZone() to print the Date in the desired timezone.
EDIT: Courtesy of @Laurynas, consider this:
TimeZone timeZone = TimeZone.getTimeZone("UTC");
Calendar calendar = Calendar.getInstance(timeZone);
SimpleDateFormat simpleDateFormat =
new SimpleDateFormat("EE MMM dd HH:mm:ss zzz yyyy", Locale.US);
simpleDateFormat.setTimeZone(timeZone);
System.out.println("Time zone: " + timeZone.getID());
System.out.println("default time zone: " + TimeZone.getDefault().getID());
System.out.println();
System.out.println("UTC: " + simpleDateFormat.format(calendar.getTime()));
System.out.println("Default: " + calendar.getTime());
java.util.Date is independent of the timezone. When you print cal_Two though the Calendar instance has got its timezone set to UTC, cal_Two.getTime() would return a Date instance which does not have a timezone (and is always in the default timezone)
Calendar cal_Two = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
System.out.println(cal_Two.getTime());
System.out.println(cal_Two.getTimeZone());
Output:
Sat Jan 25 16:40:28 IST 2014
sun.util.calendar.ZoneInfo[id="UTC",offset=0,dstSavings=0,useDaylight=false,transitions=0,lastRule=null]
From the javadoc of TimeZone.setDefault()
Sets the TimeZone that is returned by the getDefault method. If zone is null, reset the default to the value it had originally when the VM first started.
Hence, moving your setDefault() before cal_Two is instantiated you would get the correct result.
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
Calendar cal_Two = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
System.out.println(cal_Two.getTime());
Calendar cal_Three = Calendar.getInstance();
System.out.println(cal_Three.getTime());
Output:
Sat Jan 25 11:15:29 UTC 2014
Sat Jan 25 11:15:29 UTC 2014
The Timezone class does exactly what you are looking for. As far as I know, it covers the entire tz database, and I know that it covers some historical changes in the database, as shown below.
Timezone tz = Timezone.getTimeZone('America/New_York');
//before the 2007 shift of DST into November
DateTime dtpre = DateTime.newInstanceGMT(2000, 11, 1, 0, 0, 0);
system.debug(tz.getOffset(dtpre)); //-18000000 (= -5 hours = EST)
//after the 2007 shift of DST into November
DateTime dtpost = DateTime.newInstanceGMT(2012, 11, 1, 0, 0, 0);
system.debug(tz.getOffset(dtpost)); //-14400000 (= -4 hours = EDT)
It also gets the exact time at which DST starts or ends.
Timezone tz = Timezone.getTimeZone('America/New_York');
DateTime dtpre = DateTime.newInstanceGMT(2014, 11, 2, 5, 59, 59); //1:59:59AM local
system.debug(tz.getOffset(dtpre)); //-14400000 (= -4 hours = still on DST)
DateTime dtpost = DateTime.newInstanceGMT(2014, 11, 2, 6, 0, 0); //2:00:00AM local
system.debug(tz.getOffset(dtpost)); //-18000000 (= -5 hours = back one hour)
The following anonymous apex uses TimeZone.getOffset() to convert from the time in New York to UTC. Note that the getOffset() method is detecting the DST change from the perspective of a UTC input rather than the target timezones input. I.e. The offset will change between 5:59 am and 6 am in UTC rather than between 1:59 am and 2 am EST.
My current solution for this is to check the reverse offset once in UTC. If it differs for the original offset use the corrected UTC offset.
If I create a UTC DateTime for the 2nd of November 2014 at 2:00:00 a.m in EST then getOffset will return 4 hours. Checking the offset again from the 2nd of November 2014 at 6:00:00 a.m in UTC shows an offset of 5 hours. So we should actually use the 5 hour offset to determine the correct UTC value.
TimeZone tz = UserInfo.getTimeZone();
// Your results for this assertion will of course vary.
System.assertEquals('New Zealand Standard Time', tz.getDisplayName(), 'Proving the current user is in a completely different timezone to UTC and the source Timezone');
string customerTimeZoneSidId = 'America/New_York';
System.assertEquals(DateTime.newInstanceGMT(2014, 11, 2, 0, 0, 0), toUtc(customerTimeZoneSidId, '2014-11-01 20:00:00'));
System.assertEquals(DateTime.newInstanceGMT(2014, 11, 2, 1, 0, 0), toUtc(customerTimeZoneSidId, '2014-11-01 21:00:00'));
System.assertEquals(DateTime.newInstanceGMT(2014, 11, 2, 2, 0, 0), toUtc(customerTimeZoneSidId, '2014-11-01 22:00:00'));
System.assertEquals(DateTime.newInstanceGMT(2014, 11, 2, 3, 0, 0), toUtc(customerTimeZoneSidId, '2014-11-01 23:00:00'));
System.assertEquals(DateTime.newInstanceGMT(2014, 11, 2, 4, 0, 0), toUtc(customerTimeZoneSidId, '2014-11-02 0:00:00'));
System.assertEquals(DateTime.newInstanceGMT(2014, 11, 2, 5, 0, 0), toUtc(customerTimeZoneSidId, '2014-11-02 1:00:00'), 'Sunday, 2 November 2014 at 1:00:00 a.m.');
System.assertEquals(DateTime.newInstanceGMT(2014, 11, 2, 5, 59, 0), toUtc(customerTimeZoneSidId, '2014-11-02 1:59:00'), 'Sunday, 2 November 2014 at 1:59:00 a.m.');
// Note, skips 6 am UTC to 7 am UTC
// http://www.timeanddate.com/worldclock/converted.html?iso=20141102T02&p1=179&p2=0
System.assertEquals(DateTime.newInstanceGMT(2014, 11, 2, 7, 0, 0), toUtc(customerTimeZoneSidId, '2014-11-02 2:00:00'), 'Sunday, 2 November 2014 at 2:00:00 a.m');
// http://www.timeanddate.com/worldclock/converted.html?iso=20141102T03&p1=179&p2=0
System.assertEquals(DateTime.newInstanceGMT(2014, 11, 2, 8, 0, 0), toUtc(customerTimeZoneSidId, '2014-11-02 3:00:00'), 'Sunday, 2 November 2014 at 3:00:00 a.m.');
public DateTime toUtc(string customerTimeZone, string timeZoneString) {
DateTime customerDateTime = DateTime.valueofGmt(timeZoneString);
TimeZone ctz = TimeZone.getTimeZone(customerTimeZone);
integer offsetToUtc = ctz.getOffset(customerDateTime);
//System.debug('GMT Offset: ' + offsetToUtc + ' (milliseconds) ');
DateTime utcDateTime = customerDateTime.addMinutes(-1 * offsetToUtc / (1000 * 60));
// Reverse check as getOffset will be working against UTC. We can't create an instance in the customers time zone.
// May need to use the revised UTC offset once we can actaully work from UTC.
integer utcOffset = ctz.getOffset(utcDateTime);
//DateTime revisedCustomerDateTime = utcDateTime.addMinutes(utcOffset / (1000 * 60));
// Exercise for the reader, check what occurs with the other DST transition
if(offsetToUtc != utcOffset) {
System.debug(LoggingLevel.Warn, 'Revised UTC offset to ' + utcOffset);
utcDateTime = customerDateTime.addMinutes(-1 * utcOffset / (1000 * 60));
}
System.debug('Converted ' + customerDateTime + ' to ' + utcDateTime);
return utcDateTime;
}
Extra test cases you can try:
customerTimeZoneSidId = 'America/El_Salvador'; // San Salvador, El Salvador
//http://www.timeanddate.com/worldclock/converted.html?iso=20141101T18&p1=228&p2=0
System.assertEquals(DateTime.newInstanceGMT(2014, 11, 2, 0, 0, 0), toUtc(customerTimeZoneSidId, '2014-11-01 18:00:00'));
System.assertEquals(DateTime.newInstanceGMT(2014, 11, 2, 1, 0, 0), toUtc(customerTimeZoneSidId, '2014-11-01 19:00:00'));
System.assertEquals(DateTime.newInstanceGMT(2014, 11, 2, 2, 0, 0), toUtc(customerTimeZoneSidId, '2014-11-01 20:00:00'));
System.assertEquals(DateTime.newInstanceGMT(2014, 11, 2, 3, 0, 0), toUtc(customerTimeZoneSidId, '2014-11-01 21:00:00'));
System.assertEquals(DateTime.newInstanceGMT(2014, 11, 2, 4, 0, 0), toUtc(customerTimeZoneSidId, '2014-11-01 22:00:00'));
System.assertEquals(DateTime.newInstanceGMT(2014, 11, 2, 5, 0, 0), toUtc(customerTimeZoneSidId, '2014-11-01 23:00:00'));
System.assertEquals(DateTime.newInstanceGMT(2014, 11, 2, 6, 0, 0), toUtc(customerTimeZoneSidId, '2014-11-02 0:00:00'));
System.assertEquals(DateTime.newInstanceGMT(2014, 11, 2, 7, 0, 0), toUtc(customerTimeZoneSidId, '2014-11-02 1:00:00'));
System.assertEquals(DateTime.newInstanceGMT(2014, 11, 2, 7, 59, 0), toUtc(customerTimeZoneSidId, '2014-11-02 1:59:00'));
System.assertEquals(DateTime.newInstanceGMT(2014, 11, 2, 8, 0, 0), toUtc(customerTimeZoneSidId, '2014-11-02 2:00:00'));
customerTimeZoneSidId = 'Asia/Kathmandu'; // Nepal
//http://www.timeanddate.com/worldclock/converted.html?iso=20141102T1045&p1=117&p2=0
System.assertEquals(DateTime.newInstanceGMT(2014, 11, 2, 5, 0, 0), toUtc(customerTimeZoneSidId, '2014-11-02 10:45:00'));
System.assertEquals(DateTime.newInstanceGMT(2014, 11, 2, 6, 0, 0), toUtc(customerTimeZoneSidId, '2014-11-02 11:45:00'));
System.assertEquals(DateTime.newInstanceGMT(2014, 11, 2, 7, 0, 0), toUtc(customerTimeZoneSidId, '2014-11-02 12:45:00'));
System.assertEquals(DateTime.newInstanceGMT(2014, 11, 2, 8, 0, 0), toUtc(customerTimeZoneSidId, '2014-11-02 13:45:00'));
System.assertEquals(DateTime.newInstanceGMT(2014, 11, 2, 9, 0, 0), toUtc(customerTimeZoneSidId, '2014-11-02 14:45:00'));
customerTimeZoneSidId = 'America/Chicago'; // Central Standard Time
//http://www.timeanddate.com/worldclock/converted.html?iso=20141102T00&p1=64&p2=0
System.assertEquals(DateTime.newInstanceGMT(2014, 11, 2, 5, 0, 0), toUtc(customerTimeZoneSidId, '2014-11-02 0:00:00'));
System.assertEquals(DateTime.newInstanceGMT(2014, 11, 2, 6, 0, 0), toUtc(customerTimeZoneSidId, '2014-11-02 1:00:00'));
System.assertEquals(DateTime.newInstanceGMT(2014, 11, 2, 8, 0, 0), toUtc(customerTimeZoneSidId, '2014-11-02 2:00:00'));
System.assertEquals(DateTime.newInstanceGMT(2014, 11, 2, 9, 0, 0), toUtc(customerTimeZoneSidId, '2014-11-02 3:00:00'));
System.assertEquals(DateTime.newInstanceGMT(2014, 11, 2, 10, 0, 0), toUtc(customerTimeZoneSidId, '2014-11-02 4:00:00'))
Transition into Summer Time (losing 1 hour):
customerTimeZoneSidId = 'Europe/Lisbon';
//http://www.timeanddate.com/worldclock/converted.html?iso=20140330T02&p1=133&p2=0
System.assertEquals(DateTime.newInstanceGMT(2014, 3, 29, 23, 0, 0), toUtc(customerTimeZoneSidId, '2014-03-29 23:00:00'));
System.assertEquals(DateTime.newInstanceGMT(2014, 3, 30, 0, 0, 0), toUtc(customerTimeZoneSidId, '2014-03-30 00:00:00'));
System.assertEquals(DateTime.newInstanceGMT(2014, 3, 30, 0, 59, 0), toUtc(customerTimeZoneSidId, '2014-03-30 00:59:00'));
// http://www.timeanddate.com/worldclock/converted.html?iso=20140330T01&p1=133&p2=0
// The time Sunday, 30 March 2014 at 1:00:00 a.m. does not exist in Lisbon.
// Daylight Saving Time skipped one hour.
//System.assertEquals(DateTime.newInstanceGMT(2014, 3, 30, 0, 0, 0), toUtc(customerTimeZoneSidId, '2014-03-30 01:00:00')); // Will Fail
//http://www.timeanddate.com/worldclock/converted.html?iso=20140330T02&p1=133&p2=0
System.assertEquals(DateTime.newInstanceGMT(2014, 3, 30, 1, 0, 0), toUtc(customerTimeZoneSidId, '2014-03-30 02:00:00'));
//http://www.timeanddate.com/worldclock/converted.html?iso=20140330T03&p1=133&p2=0
System.assertEquals(DateTime.newInstanceGMT(2014, 3, 30, 2, 0, 0), toUtc(customerTimeZoneSidId, '2014-03-30 03:00:00'));
System.assertEquals(DateTime.newInstanceGMT(2014, 3, 30, 3, 0, 0), toUtc(customerTimeZoneSidId, '2014-03-30 04:00:00'));