100

Why can't it parse this:

DateTime.Parse("Tue, 1 Jan 2008 00:00:00 UTC")
John Topley
  • 113,588
  • 46
  • 195
  • 237
David
  • 8,340
  • 7
  • 49
  • 71
  • 3
    IE9 is still incorrectly adding "UTC" when you use `new Date().toUTCString()` in Javascript – Chris S Jul 05 '12 at 10:16
  • For anyone coming to this post 2009, the answer to this issue is https://momentjs.com/ – Liam Jul 22 '19 at 11:00

10 Answers10

112

It can't parse that string because "UTC" is not a valid time zone designator.

UTC time is denoted by adding a 'Z' to the end of the time string, so your parsing code should look like this:

DateTime.Parse("Tue, 1 Jan 2008 00:00:00Z");

From the Wikipedia article on ISO 8601

If the time is in UTC, add a 'Z' directly after the time without a space. 'Z' is the zone designator for the zero UTC offset. "09:30 UTC" is therefore represented as "09:30Z" or "0930Z". "14:45:15 UTC" would be "14:45:15Z" or "144515Z".

UTC time is also known as 'Zulu' time, since 'Zulu' is the NATO phonetic alphabet word for 'Z'.

Neil N
  • 24,862
  • 16
  • 85
  • 145
Simon P Stevens
  • 27,303
  • 5
  • 81
  • 107
  • 1
    The date string in my example came from internet explorer – David Nov 18 '09 at 15:15
  • @Dave: When you say it came from IE, do you mean that you extracted it from a web page? You may have to write your own replacement for the DateTime parser that extracts the UTC and replaces it with a Z. – Simon P Stevens Nov 18 '09 at 15:17
  • Having being testing against FF, I had forgotten I called the toUTCString() method on the date I POST back to the server. FF sends GMT while IE sends UTC. So I cant blame IE... this time! – David Nov 18 '09 at 16:13
  • 117
    As other answers point out, the UTC date string with Z designator would indeed be successfully _parsed_, but it would also be converted to local time, i.e. it returns `DateTime` with a `Kind` of `Local` and adjusted timestamp. To always get UTC `DateTime`, one could use one of `DateTime.Parse("2008-01-01 00:00:00Z", CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal | DateTimeStyles.AssumeUniversal)`, as @crokusek suggests, or `DateTimeOffset.Parse("2008-01-01 00:00:00Z").UtcDateTime`, as @ruffin suggests. – Sergii Volchkov Dec 19 '16 at 13:30
  • In meta tag like `http-equiv="last-modified"` the format is ***2013-10-23@17:23:00 UTC***, is it possible? – PreguntonCojoneroCabrón Sep 08 '17 at 07:05
  • 8
    Strangely, `DateTime.Parse("Tue, 1 Jan 2008 00:00:00Z").Kind` returns `Local`, not `Utc`. – marsze Mar 12 '18 at 12:56
109

Assuming you use the format "o" for your datetime so you have "2016-07-24T18:47:36Z", there is a very simple way to handle this.

Call DateTime.Parse("2016-07-24T18:47:36Z").ToUniversalTime().

What happens when you call DateTime.Parse("2016-07-24T18:47:36Z") is you get a DateTime set to the local timezone. So it converts it to the local time.

The ToUniversalTime() changes it to a UTC DateTime and converts it back to UTC time.

James Skemp
  • 8,018
  • 9
  • 64
  • 107
David Thielen
  • 28,723
  • 34
  • 119
  • 193
  • Presume this is what happens when you sent it a Zulu to a web api and yet you see it being displayed as the local time. think something has just clicked, thanks – Andrew May 20 '20 at 08:50
  • Or without the `.ToUniversalTime()` conversion: `DateTime.Parse("2016-07-24T18:47:36Z", CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind);` – Marcel Wolterbeek Feb 06 '23 at 15:27
53

Just use that:

var myDateUtc = DateTime.SpecifyKind(DateTime.Parse("Tue, 1 Jan 2008 00:00:00"), DateTimeKind.Utc);

if (myDateUtc.Kind == DateTimeKind.Utc)
{
     Console.WriteLine("Yes. I am UTC!");
}

You can test this code using the online c# compiler:

http://rextester.com/

I hope it helps.

  • 2
    I'm actually kind of surprised there isn't a method of `DateTime.Parse("Some:Time:here", "Utc")` – tisaconundrum Mar 03 '22 at 17:21
  • This was exactly what I needed. We store UTC DateTime strings without any timezone definition to a Database and when we read them again in the application we need these to be parsed as UTC. – DVS Aug 23 '22 at 12:42
24

or use the AdjustToUniversal DateTimeStyle in a call to

DateTime.ParseExact(String, String[], IFormatProvider, DateTimeStyles)
user213809
  • 241
  • 1
  • 3
  • 7
    This actually works. I used this code and got correct UTC DateTime from UTC string: DateTime.TryParseExact("2012-01-30T00:28:00Z", "yyyy-MM-ddTHH:mm:ssZ", CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal, out timeValue)); – Roboblob Jan 30 '12 at 00:50
  • 28
    This one works too, Utc in and out, no format, no Z required: DateTime.Parse("8/3/2013 1:02:41 AM", CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal | DateTimeStyles.AssumeUniversal); – crokusek Oct 04 '13 at 02:10
  • I was dealing with a UTC time string similar to Roboblob, and used code similar to what Roboblob specified to maintain the UTC-ness of the value: DateTime.ParseExact(utcTimeStringINeededToParse, "yyyy-MM-ddTHH:mm:ss.0000000Z", System.Globalization.CultureInfo.InvariantCulture, System.Globalization.DateTimeStyles.AdjustToUniversal) – StackOverflowUser Feb 09 '16 at 20:33
  • This worked when the other solutions didn't for me. Note that there's also `DateTimeStyles.AssumeUniversal`, but this is NOT what you want, use AdjustToUniversal as suggested in the first comment! – Carlos Sanchez May 14 '22 at 07:31
19

You need to specify the format:

DateTime date = DateTime.ParseExact(
    "Tue, 1 Jan 2008 00:00:00 UTC", 
    "ddd, d MMM yyyy HH:mm:ss UTC", 
    CultureInfo.InvariantCulture);
Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
  • 2
    Nice suggestion, but this would fail if the provided date string didn't contain UTC at the end. Say instead you passed a date string that had +01 at the end, it would cause a FormatException. Depends what he is trying to do I suppose. – Simon P Stevens Nov 18 '09 at 15:22
11

To correctly parse the string given in the question without changing it, use the following:

using System.Globalization;

string dateString = "Tue, 1 Jan 2008 00:00:00 UTC";
DateTime parsedDate = DateTime.ParseExact(dateString, "ddd, d MMM yyyy hh:mm:ss UTC", CultureInfo.CurrentCulture, DateTimeStyles.AssumeUniversal);

This implementation uses a string to specify the exact format of the date string that is being parsed. The DateTimeStyles parameter is used to specify that the given string is a coordinated universal time string.

satbot
  • 424
  • 6
  • 13
  • 2
    According to the [docs](https://learn.microsoft.com/en-us/dotnet/api/system.datetime.parseexact?view=netstandard-2.1), "the `Kind` property of the returned `DateTime` value is `DateTimeKind.Local`." ParseExact correctly parses it as UTC, but then converts it to local time before returning it. Use `DateTimeStyles.RoundtripKind` if you want the returned value to be returned unmodified as UTC. – Daniel Schilling Nov 13 '19 at 18:18
7

It's not a valid format, however "Tue, 1 Jan 2008 00:00:00 GMT" is.

The documentation says like this:

A string that includes time zone information and conforms to ISO 8601. For example, the first of the following two strings designates the Coordinated Universal Time (UTC); the second designates the time in a time zone seven hours earlier than UTC:

2008-11-01T19:35:00.0000000Z

A string that includes the GMT designator and conforms to the RFC 1123 time format. For example:

Sat, 01 Nov 2008 19:35:00 GMT

A string that includes the date and time along with time zone offset information. For example:

03/01/2009 05:42:00 -5:00

HackerBaloo
  • 397
  • 2
  • 11
  • A simple replace of "UTC" with "GMT" in a date string similar to this format works great, thanks for the tip. – James Wilkins Apr 20 '15 at 16:43
  • 3
    Though note that this returns a `DateTime` with a `Kind` of `Local` for me. Looks like the workaround is to use [DateTimeOffset.Parse](http://stackoverflow.com/a/14774345/1028230) (and then `x.UtcDateTime`) if you want to ensure you're not falling off of the UTC wagon during your parse. – ruffin Nov 09 '16 at 17:02
2

I've put together a utility method which employs all tips shown here plus some more:

    static private readonly string[] MostCommonDateStringFormatsFromWeb = {
        "yyyy'-'MM'-'dd'T'hh:mm:ssZ",  //     momentjs aka universal sortable with 'T'     2008-04-10T06:30:00Z          this is default format employed by moment().utc().format()
        "yyyy'-'MM'-'dd'T'hh:mm:ss.fffZ", //  syncfusion                                   2008-04-10T06:30:00.000Z      retarded string format for dates that syncfusion libs churn out when invoked by ejgrid for odata filtering and so on
        "O", //                               iso8601                                      2008-04-10T06:30:00.0000000
        "s", //                               sortable                                     2008-04-10T06:30:00
        "u"  //                               universal sortable                           2008-04-10 06:30:00Z
    };

    static public bool TryParseWebDateStringExactToUTC(
        out DateTime date,
        string input,
        string[] formats = null,
        DateTimeStyles? styles = null,
        IFormatProvider formatProvider = null
    )
    {
        formats = formats ?? MostCommonDateStringFormatsFromWeb;
        return TryParseDateStringExactToUTC(out date, input, formats, styles, formatProvider);
    }

    static public bool TryParseDateStringExactToUTC(
        out DateTime date,
        string input,
        string[] formats = null,
        DateTimeStyles? styles = null,
        IFormatProvider formatProvider = null
    )
    {
        styles = styles ?? DateTimeStyles.AllowWhiteSpaces | DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal; //0 utc
        formatProvider = formatProvider ?? CultureInfo.InvariantCulture;

        var verdict = DateTime.TryParseExact(input, result: out date, style: styles.Value, formats: formats, provider: formatProvider);
        if (verdict && date.Kind == DateTimeKind.Local) //1
        {
            date = date.ToUniversalTime();
        }

        return verdict;

        //0 employing adjusttouniversal is vital in order for the resulting date to be in utc when the 'Z' flag is employed at the end of the input string
        //  like for instance in   2008-04-10T06:30.000Z
        //1 local should never happen with the default settings but it can happen when settings get overriden   we want to forcibly return utc though
    }

Notice the use of '-' and 'T' (single-quoted). This is done as a matter of best practice since regional settings interfere with the interpretation of chars such as '-' causing it to be interpreted as '/' or '.' or whatever your regional settings denote as date-components-separator. I have also included a second utility method which show-cases how to parse most commonly seen date-string formats fed to rest-api backends from web clients. Enjoy.

XDS
  • 3,786
  • 2
  • 36
  • 56
1

Just replace "UTC" with "GMT" -- simple and doesn't break correctly formatted dates:

DateTime.Parse("Tue, 1 Jan 2008 00:00:00 UTC".Replace("UTC", "GMT"))
Mike Godin
  • 3,727
  • 3
  • 27
  • 29
-6

Not sure why, but you can wrap DateTime.ToUniversalTime in a try / catch and achieve the same result in more code.

Good luck.

Ian P
  • 12,840
  • 6
  • 48
  • 70