Find your content:

Search form

You are here

Parsing an ISO 8601 timestamp to a DateTime

 
Share

I've written a simple method to parse a specific kind of ISO 8601 timestamp (GMT, with milliseconds), into a DateTime.

I'm looking to replace it with something that can parse any ISO 8601 timestamp (with or without element separators, missing elements like seconds or milliseconds, with timezone, etc.) Rather that re-inventing the wheel, I'm wondering about using a built-in method.

A similar question about converting ISO 8601 timestamps in Java on Stack Overflow pointed out that, "JAXB must be able to parse ISO8601 date string according to the XML Schema specification".

I don't know what JAXB is, or whether it's available from Apex, but I do know that Apex has all sorts of XML parsers and WSDL tools. The XMLNode class doesn't have an ISO 8601 parser, but I did find mention of one as part of the JSONParser class (getDatetimeValue() method), and I plan to use that in a wrapper for my conversion.

I'm wondering:

  • If there's something simpler.
  • If there are known limitations of getDatetimeValue() from JSONParser.

Attribution to: tomlogic

Possible Suggestion/Solution #1

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

Attribution to: haridsv

Possible Suggestion/Solution #2

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;
}

Attribution to: tomlogic

Possible Suggestion/Solution #3

Or you could just do this:

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


Attribution to: Rich Unger
This content is remixed from stackoverflow or stackexchange. Please visit https://salesforce.stackexchange.com/questions/1013

My Block Status

My Block Content