How to parse and generate DateTime objects in ISO 8601 format
Solution 1
The format you're describing is ISO 8601.
Since you're working with timestamps that inclulde a time zone component, I'd strongly recommend using DateTimeOffset
instead of DateTime
. It makes things so much easier!
To create a DateTimeOffset
for a given date, time, and time zone offset, use this syntax:
var date = new DateTimeOffset(2016, 3, 29, 12, 20, 35, 93, TimeSpan.FromHours(-5));
// March 29, 2016 at 12:20:35.93 GMT-5
This code will format a DateTimeOffset
as ISO 8601:
public static string FormatIso8601(DateTimeOffset dto)
{
string format = dto.Offset == TimeSpan.Zero
? "yyyy-MM-ddTHH:mm:ss.fffZ"
: "yyyy-MM-ddTHH:mm:ss.fffzzz";
return dto.ToString(format, CultureInfo.InvariantCulture);
}
And, to parse a string back to a DateTimeOffset
:
public static DateTimeOffset ParseIso8601(string iso8601String)
{
return DateTimeOffset.ParseExact(
iso8601String,
new string[] { "yyyy-MM-dd'T'HH:mm:ss.FFFK" },
CultureInfo.InvariantCulture,
DateTimeStyles.None);
}
If you must get back to a DateTime
you can get this from the DateTimeOffset
.UtcDateTime
property.
Solution 2
A simpler way is to use the ToString method on DateTimeOffset with the "o" argument. This automatically prints the date in ISO8601 format
DateTimeOffset.Now.ToString("o");
The static parse method is also capable of correctly parsing a date in ISO8601 format.
DateTimeOffset.Parse("2016-25-12T20:45:30.3124+01:00");
DateTimeOffset.Parse("2016-25-12T20:45:30.3124Z");
Stephen H. Anderson
Updated on June 09, 2020Comments
-
Stephen H. Anderson almost 4 years
There is this SOAP web service that sends me datetime objects in the following format
2016-03-29T12:20:35.093-05:00
That is day 29 of March of year 2016. Hour: 12:20:35.093 (GMT-5).
I want to be able to create a
DateTime
object, like this:DateTime.Now
and get the string representation in the format described above and also the inverse operation, create a DateTime from a string like the one given above.
I've tried the following in order to create the date:
new DateTime(2016, 3, 29, 12, 20, 35, 093, DateTimeKind.Utc)
However, I can't not see how to specifie GMT-5 there...
I don't know how to convert a DateTime to the specified string format, either.
Using Nate's code I'm doing the following:
var d = new DateTimeOffset(2016, 3, 29, 12, 20, 35, 93, TimeSpan.FromHours(-3)); FormatIso8601(d)
However this call is returning: "2016-03-29T15:20:35Z" instead of :
"2016-03-29T12:20:35.093-03:00"
which is what I actually need.
I think this works:
d.ToString("yyyy-MM-ddTHH:mm:ss.fffzzz")
-
Stephen H. Anderson about 8 yearsThanks a lot. Is it safe to do this? ParseIso8601(myDate).DateTime to obtain a datetime object? In my system I would need datetimes instead of datetimeoffsets, if possible. Thanks
-
Nate Barbettini about 8 yearsIt's possible, but beware of unintended side effects: the time you get will depend on the local time zone of your machine. UtcDateTime will always return a UTC time, if you want to avoid that conversion.
-
Stephen H. Anderson about 8 yearsSo it's impossible to obtaina DateTime object which represents the same exact time I passed in the string to ParseIso8601?
-
Nate Barbettini about 8 years"Exact time" in which time zone? The string may represent a different time zone than your machine is in.
-
Nate Barbettini about 8 yearsSure - UtcDateTime will be unambiguous.
-
Stephen H. Anderson about 8 yearsIf I do this: var date = new DateTimeOffset(2016, 3, 29, 12, 20, 35, 93, TimeSpan.FromHours(-5)); and then I do date.DateTime would it still be in GMT-5?
-
Nate Barbettini about 8 yearsThis is why
DateTime
sucks. :( It would not necessarily still be GMT-5, it would depend on the time zone of your machine. If your machine is also GMT-5, then yes. -
Nate Barbettini about 8 yearsNo problem. If possible, it's highly recommended to switch everything over to
DateTimeOffset
. -
Stephen H. Anderson about 8 yearsNate, I have a problem with the code given. Please see my edit (I'm publishing it in 5 minutes)