185

I've found how to turn a DateTime into an ISO 8601 format, but nothing on how to do the reverse in C#.

I have 2010-08-20T15:00:00Z, and I want to turn it into a DateTime object.

I could separate the parts of the string myself, but that seems like a lot of work for something that is already an international standard.

Liam
  • 27,717
  • 28
  • 128
  • 190
Ripter
  • 2,020
  • 2
  • 14
  • 9
  • 1
    possible duplicate of [Convert String to Date in .NET](http://stackoverflow.com/questions/2188585/convert-string-to-date-in-net) – abatishchev Aug 24 '10 at 12:02
  • 8
    @abatishchev, and that is why it is not a duplicate. The answer in the "duplicate" does not handle 8601. – Spiralis Nov 03 '16 at 15:30
  • 3
    Yes this is not a duplicate. This question is specific to parsing the ISO 8601 format. – Jose Feb 13 '20 at 04:59

7 Answers7

208

This solution makes use of the DateTimeStyles enumeration, and it also works with Z.

DateTime d2 = DateTime.Parse("2010-08-20T15:00:00Z", null, System.Globalization.DateTimeStyles.RoundtripKind);

This prints the solution perfectly.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Mamta D
  • 6,310
  • 3
  • 27
  • 41
  • @Mamta Dalal: try `DateTime.ParseExact("2010-08-20T15:00:00Z", "s", CultureInfo.InvariantCulture);` It fails. – Roatin Marth Dec 06 '11 at 15:11
  • 4
    The edited solution of `DateTime d2= DateTime.Parse("2010-08-20T15:00:00Z", null, DateTimeStyles.RoundtripKind);` seems to work nicely. – j3ko Dec 18 '12 at 22:23
  • 7
    Anyone wish to elaborate on this `DateTimeStyles.RoundtripKind?` MSDN description is blank. – Steve Parish Oct 28 '15 at 16:24
  • This is also applicable to the `System.DateTimeOffset` structure. – Vladimir Svyatski Oct 28 '15 at 18:04
  • 12
    it seems this question was edited to reflect a better answer but since @MamtaD overwrote the original answer, the comments become very misleading. At the beginning I was not sure that the answer is correct due to the comments on top but then I realized that incorrect answer was latter replaced with correct one – Aidin Nov 20 '15 at 21:40
  • This throws a System.Format Exception for the string `"06-03-2016T06:42:44.252Z"`. How can I convert that string into a datetime? – user95227 Jun 10 '16 at 17:39
  • @user95227 the question on this page pertains to the ISO8601 format whereas your string is not in that format. Hence, the correct answer to the question asked originally may not be the correct answer to yours as the context are different. – Mamta D Jun 13 '16 at 10:24
  • Tested id with "2017-10-31T06:03:05+01:00". Does work too.. Thanks a lot! – Oswald Oct 31 '17 at 06:24
  • 9
    Doesn't work for me with fractional digits. `2018-06-19T14:56:14.123Z` is parsed as local time, not UTC. I use `CultureInfo.InvariantCulture` instead of null. – Erik Hart Jun 19 '18 at 12:46
  • 1
    For more info on `DateTimeStyles.RoundTripKind`, see https://stackoverflow.com/q/39572395/2014893 – Robert K. Bell Jul 06 '18 at 06:18
  • I'm using DateTime.Parse("2010-08-20T15:00:00Z", CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind) since is ISO 8601 can't be afected by the culture. For DateTimeOffSet should be the same right? DateTimeOffset.Parse(value, CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind) – João Antunes Apr 17 '19 at 17:35
42

Although MSDN says that "s" and "o" formats reflect the standard, they seem to be able to parse only a limited subset of it. Especially it is a problem if the string contains time zone specification. (Neither it does for basic ISO8601 formats, or reduced precision formats - however this is not exactly your case.) That is why I make use of custom format strings when it comes to parsing ISO8601. Currently my preferred snippet is:

static readonly string[] formats = { 
    // Basic formats
    "yyyyMMddTHHmmsszzz",
    "yyyyMMddTHHmmsszz",
    "yyyyMMddTHHmmssZ",
    // Extended formats
    "yyyy-MM-ddTHH:mm:sszzz",
    "yyyy-MM-ddTHH:mm:sszz",
    "yyyy-MM-ddTHH:mm:ssZ",
    // All of the above with reduced accuracy
    "yyyyMMddTHHmmzzz",
    "yyyyMMddTHHmmzz",
    "yyyyMMddTHHmmZ",
    "yyyy-MM-ddTHH:mmzzz",
    "yyyy-MM-ddTHH:mmzz",
    "yyyy-MM-ddTHH:mmZ",
    // Accuracy reduced to hours
    "yyyyMMddTHHzzz",
    "yyyyMMddTHHzz",
    "yyyyMMddTHHZ",
    "yyyy-MM-ddTHHzzz",
    "yyyy-MM-ddTHHzz",
    "yyyy-MM-ddTHHZ"
    };

public static DateTime ParseISO8601String ( string str )
{
    return DateTime.ParseExact ( str, formats, 
        CultureInfo.InvariantCulture, DateTimeStyles.None );
}

If you don't mind parsing TZ-less strings (I do), you can add an "s" line to greatly extend the number of covered format alterations.

Alexey Biryukov
  • 649
  • 8
  • 15
  • 4
    I would add `"yyyyMMdd"` in the `formats` array for accuracy reduced to days, as this is sometimes the case when an RFC 5545 RRULE will rely on a DTSTART to provide the time. – Kyle Falconer Aug 01 '14 at 15:31
  • 1
    Using `K` allows you to roll your different time-zone handlings together. I've a more extensive variant at http://stackoverflow.com/a/31246449/400547 but it's if anything too extensive (accepts stuff that's valid ISO 8601 but not used in the more common profiles) but it does show how `K` can reduce the size by a third. – Jon Hanna Jul 06 '15 at 12:59
25
using System.Globalization;

DateTime d;
DateTime.TryParseExact(
    "2010-08-20T15:00:00",
    "s",
    CultureInfo.InvariantCulture,
    DateTimeStyles.AssumeUniversal, out d);
abatishchev
  • 98,240
  • 88
  • 296
  • 433
22

Here is one that works better for me (LINQPad version):

DateTime d;
DateTime.TryParseExact(
    "2010-08-20T15:00:00Z",
    @"yyyy-MM-dd\THH:mm:ss\Z",
    CultureInfo.InvariantCulture,
    DateTimeStyles.AssumeUniversal, 
    out d);
d.ToString()

produces

true
8/20/2010 8:00:00 AM
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Reb.Cabin
  • 5,426
  • 3
  • 35
  • 64
  • Currently using this to verify in my unit tests that all strings I expect to be dates are of Iso8601 format. Thanks! – anthv123 Jan 27 '15 at 05:19
  • 1
    Why does this return a timestamp not in UTC?! Quite a large violation of the Principle of Least Astonishment since "Invariant culture" with "AssumeUniversal" should not be doing this because DST differs so wildly across the world, so returning in your local prevailing time zone might introduce bugs if you start running the code on a server with different settings! – Elaskanator Jul 19 '19 at 20:40
10

It seems important to exactly match the format of the ISO string for TryParseExact to work. I guess Exact is Exact and this answer is obvious to most but anyway...

In my case, Reb.Cabin's answer doesn't work as I have a slightly different input as per my "value" below.

Value: 2012-08-10T14:00:00.000Z

There are some extra 000's in there for milliseconds and there may be more.

However if I add some .fff to the format as shown below, all is fine.

Format String: @"yyyy-MM-dd\THH:mm:ss.fff\Z"

In VS2010 Immediate Window:

DateTime.TryParseExact(value,@"yyyy-MM-dd\THH:mm:ss.fff\Z", CultureInfo.InvariantCulture,DateTimeStyles.AssumeUniversal, out d);

true

You may have to use DateTimeStyles.AssumeLocal as well depending upon what zone your time is for...

AlexB
  • 7,302
  • 12
  • 56
  • 74
9

This works fine in LINQPad4:

Console.WriteLine(DateTime.Parse("2010-08-20T15:00:00Z"));
Console.WriteLine(DateTime.Parse("2010-08-20T15:00:00"));
Console.WriteLine(DateTime.Parse("2010-08-20 15:00:00"));
Zar Shardan
  • 5,675
  • 2
  • 39
  • 37
-1

DateTime.ParseExact(...) allows you to tell the parser what each character represents.

abatishchev
  • 98,240
  • 88
  • 296
  • 433
Jerod Houghtelling
  • 4,783
  • 1
  • 22
  • 30