为什么不能解析 UTC 日期

为什么它不能解析这个:

DateTime.Parse("Tue, 1 Jan 2008 00:00:00 UTC")
162445 次浏览

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

Good luck.

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'.

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

or use the AdjustToUniversal DateTimeStyle in a call to

DateTime.ParseExact(String, String[], IFormatProvider, DateTimeStyles)

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

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.

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.

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.

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"))

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.