2015-10-09 1 views
4

Я выполняю условные запросы в веб-службе. Бэкэнд может легко получить последнюю измененную дату объекта, поэтому я отправляю Last-Modified и возвращаюсь If-Modified-Since. RFC for HTTP Dates определяет формат, который совпадает с "R" format specifier in .NET.Почему не DateTime.ToString ("R") и DateTime.TryParseExact в оба конца?

Проблема заключается в том, что DateTime.ToString("R") форматирует дату правильно, но проходя "R" к ParseExact не читает часовой пояс обратно (есть «Туда и обратно» спецификатор, "O", но это не в формате, мне нужно). Вот пример в LINQPad:

DateTime lastModified = new DateTime(2015, 10, 01, 00, 00, 00, DateTimeKind.Utc); 
string lastModifiedField = lastModified.ToString("R"); // Thu, 01 Oct 2015 00:00:00 GMT 
DateTime ifModifiedSince = DateTime.ParseExact(
    lastModifiedField, "R", CultureInfo.InvariantCulture); 

ifModifiedSince.Kind.Dump(); // Unspecified 

Я могу, конечно, использовать методы разобранного DateTime, чтобы заставить его в формат, я хочу, но как я могу получить структуру, чтобы использовать данные, которые уже есть?

ответ

7

Я наткнулся на источник ссылок, который объясняет это, поэтому спрашивает и отвечает на мой собственный вопрос.

source to datetimeparse.cs указывает, что это ошибка, которая не может быть исправлена ​​для совместимости.

// The "r" and "u" formats incorrectly quoted 'GMT' and 'Z', respectively. We cannot 
// correct this mistake for DateTime.ParseExact for compatibility reasons, but we can 
// fix it for DateTimeOffset.ParseExact as DateTimeOffset has not been publically released 
// with this issue. 

Так что код этот комментарий предшествует вызывается как DateTime.ParseExact и DateTimeOffset.ParseExact, и предлагает в том, что DateTimeOffset.ParseExact является более правильным. Действительно, в соответствии с документацией на choosing between DateTime and DateTimeOffset:

Эти варианты использования значений DateTimeOffset гораздо чаще, чем те, для значений DateTime. В результате DateTimeOffset следует рассматривать как тип даты и времени по умолчанию для разработки приложения.

Поэтому идеальным решением является переключение на DateTimeOffset, но если вам все еще нужно DateTime:

DateTime lastModified = new DateTime(2015, 10, 01, 00, 00, 00, DateTimeKind.Utc); 
string lastModifiedField = lastModified.ToString("R"); 
DateTimeOffset ifModifiedSinceOffset = DateTimeOffset.ParseExact(
    lastModifiedField, "R", CultureInfo.InvariantCulture); 
DateTime ifModifiedSince = ifModifiedSinceOffset.UtcDateTime; 

ifModifiedSince.Kind.Dump(); // Utc 

Что правильно определяет часовой пояс GMT/UTC, и, таким образом, устанавливает правильное свойство на DateTime ,

+0

Да, это хорошо - за исключением того, что окончательный 'Kind' будет * всегда * быть' Utc', так как вы получили его из '.UtcDateTime'. Но по крайней мере разбор правилен. Вам будет интересно также заметить, что 'DateTime.Parse' * does * работает - по крайней мере, это происходит, когда вы передаете' DateTimeStyles.RoundtripKind'. Это только 'DateTime.ParseExact', которого нет. –

+0

Конечно - было бы предпочтительнее использовать ISO8601 вместо этого ужасающего формата, но все же - хороший улов! –

+0

Кроме того, вы можете зарегистрировать это на https://github.com/dotnet/coreclr/issues - кажется глупым, чтобы не исправить это. –

Смежные вопросы