Update for subsequent question edit
Here is what I think is happening:
The DateTime dt1
returned by JSONParser.getDateTimeValue() internally stores values based on the users time zone offset. In my case, and I suspect yours, this is currently GMT - 7. This is why calls to dt1.dateGmt() include an offset.
The time component that is stored internally in dt1
has been adjusted to the users time zone as well. So 11 AM becomes 4 AM due to the -7 hour offset.
Calls to dt1.hourGmt() only take into account the time portion of the DateTime, and hence return 4 rather than 11. The other missing 7 hours are stored in the date portion of the DateTime (which can be seen in calls to dt1.dateGMT()
).
An interesting experiment would be to alter the active users time zone to see if the result changes as expected.
The more I read over this the more I concur that this is a Salesforce bug in the hourGMT() method.
The DateTime dt1
returned by JSONParser.getDateTimeValue() has internally been adjusted to the active users time zone. This offset is tracked against the date component and the time component has been adjusted accordingly. For my test user on GMT-7 this only left 4 hours in the time component.
As Mike notes in his answer, DateTime.newInstance(Long) returns a DateTime in the GMT time zone.
Constructs a DateTime and initializes it to represent the specified number of milliseconds since January 1, 1970, 00:00:00 GMT. The returned date is in the GMT time zone.
Internally the dt2
date isn't tracking the users time zone offset, so the time component has the full 11 hours.
I tried modifying your example to explicitly create dt2 using the GMT values.
String iso8601 = '2012-07-31T11:22:33.000Z'; // NB: Removed milliseconds as they weren't available in newInstanceGmt
JSONParser parser = JSON.createParser( '{"t":"' + iso8601 + '"}');
parser.nextToken();
parser.nextValue();
DateTime dt1 = parser.getDateTimeValue();
// dt2 should be identical to dt1
//DateTime dt2 = DateTime.newInstance( dt1.getTime());
//DateTime dt2= DateTime.newInstanceGmt(dt1.dateGMT(), dt1.timeGmt());
DateTime dt2= DateTime.newInstanceGmt(2012, 07, 31, 11, 22, 33);
String timeformat = 'M/d/yyyy h:mm a';
//2012-07-31T11:22:33.000Z parsed as 2012-07-31 11:22:33
System.Debug( iso8601 + ' parsed as ' + dt1);
// The date values differ by 7 hours when tested with a user on PDT
System.Debug(dt1.dateGMT() + ', ' + dt1.timeGmt()); //2012-07-31 07:00:00, 04:22:33.000Z
System.Debug(dt2.dateGMT() + ', ' + dt2.timeGmt()); //2012-07-31 00:00:00, 11:22:33.000Z
System.assertEquals( dt1.format(), dt2.format(), 'localtime is the same');
System.assertEquals( dt1.getTime(), dt2.getTime(), 'same number of milliseconds since epoch');
System.assertEquals( dt1.formatGmt( timeformat), dt2.formatGmt( timeformat));
System.assertEquals( dt1.hourGmt(), dt2.hourGmt(), 'assertion fails when it should not');
The final assertion fails with the message:
System.AssertException: Assertion Failed: assertion fails when it
should not: Expected: 4, Actual: 11
Note the output of the latter two debug lines:
14:44:27.257 (257267000)|USER_DEBUG|[15]|DEBUG|2012-07-31 07:00:00,
04:22:33.000Z 14:44:27.257
(257435000)|USER_DEBUG|[16]|DEBUG|2012-07-31 00:00:00, 11:22:33.000Z
There is a difference in the internal representation of the DateTime. dt1
has a 7 hour offset in the GMT date and only 4 hours in the time component.
In contrast, dt2
has 0 hours in the GMT date and 11 hours in the time component.
The Salesforce user that executed the code had:
Time Zone (GMT-07:00) Pacific Daylight Time (America/Los_Angeles)
Best Answer
You're probably looking for formatGMT:
Note that
MM
is month, whilemm
is minute. This will give you the format you're looking for in GMT (GMT-00:00).You can read SimpleDateFormat for all available options.