Parsing an ISO 8601 timestamp to a DateTime

Rich's answer was promising, so I tried to figure out why it wouldn't work, so did a bit of debugging and found that something like this:

System.debug(JSON.deserialize(JSON.serialize(Datetime.now()), Datetime.class));

would print the current Datetime, and that

System.debug(JSON.serialize(Datetime.now());

does in fact serialize to ISo 8601 format, so after a couple of minutes of staring, I realized that the string has to be a valid JSON string, which means, we need double-quotes around it. E.g., try this:

string str = '"2013-01-30T07:38:44.268Z"';
System.debug(JSON.deserialize(str, Datetime.class));

and you should see something like this in the log:

23:40:51.127 (127738280)|USER_DEBUG|[5]|DEBUG|2013-01-30 07:38:44

Or you could just do this:

datetime dt = (datetime)json.deserialize('"2012-07-31T11:22:33.444Z"', datetime.class);


Here's my current technique, but I'm looking for other options. As I put this together, I ran into a bug with the DateTime object, or at least how the JSONParser fills it.

/**
    @brief Convert an ISO 8601 timestamp to an Apex \c DateTime value.

    Uses the JSONParser getDateTimeValue() method.

    See http://en.wikipedia.org/wiki/ISO_8601 for timestamp format details.

    Throws a System.JSONException if \p iso8601_ts is not a valid ISO 8601
    timestamp.

    @param iso8601_ts Valid ISO 8601 timestamp.

    @return a \c DateTime value for the given timestamp
*/
public static DateTime convertTimestamp( String iso8601_ts)
{
    // Create a valid JSON string like '{"t":"2012-07-31T11:22:33.444Z"}'
    JSONParser parser = JSON.createParser( '{"t":"' + iso8601_ts + '"}');

    parser.nextToken();    // advance to the start object marker
    parser.nextValue();    // advance to the next value

    // Bug in JSONParser or DateTime object results in a malformed DateTime,
    // so convert to Long and back to DateTime.  Without the conversion,
    // methods that access timeGmt() and its components will actually get
    // local time instead of GMT.
    return DateTime.newInstance( parser.getDateTimeValue().getTime());

    // Once bug is fixed, this return is preferred.
    // return parser.getDateTimeValue();
}

EDIT Based on feedback from @RichUnger and @haridsv, here's an updated method (opening comments are unchanged). Once the bug is fixed I can simplify it to just return the result of JSON.deserialize().

public static DateTime convertISO8601( String iso8601_ts)
{
    DateTime dt = (DateTime) JSON.deserialize(
                                    '"' + iso8601_ts + '"', DateTime.class);
    // Bug in JSONParser or DateTime object results in a malformed DateTime,
    // so convert to Long and back to DateTime.  Without the conversion,
    // methods that access timeGmt() and its components will actually get
    // local time instead of GMT.
    return DateTime.newInstance( dt.getTime());

    // Once bug is fixed, this return is preferred
    // return dt;
}

Tags:

Datetime

Apex