Вопрос

[Обновить: Спецификаторы формата - это не то же самое, что форматные строки;спецификатор формата - это часть строки пользовательского формата, где строка формата является "стандартной" и не обеспечивает настройку.Моя проблема связана со спецификаторами, а не с форматами]

Я пытался выполнить обратные преобразования даты и времени с помощью строки формата, которая использует спецификатор формата 'zzz', который, как я знаю, привязан к местному времени.Итак, если я попытаюсь выполнить обход с указанием даты UTC, это вызовет исключение DateTimeInvalidLocalFormat, которое и должно быть, с таким текстом:

Дата-время UTC преобразуется в текст в формате, который корректен только для местного времени.Это может произойти при вызове DateTime .toString с использованием спецификатора формата 'z', который будет включать в выходные данные смещение локального часового пояса. В этом случае либо используйте спецификатор формата 'Z', который обозначает время UTC, или используйте строку формата 'o', которая является рекомендуемым способом сохранения даты и времени в тексте.Это также может произойти при передаче DateTime для сериализации с помощью XmlConvert или DataSet.Если вы используете XmlConvert.toString, передайте в XmlDateTimeSerializationMode.RoundtripKind для правильной сериализации.Если используется DataSet, установите DateTimeMode для объекта DataColumn в DataSetDateTime.Utc.

Основываясь на этом предложении, все, что мне нужно сделать, чтобы заставить мой код работать, - это заменить "zzz" на "ZZZ", чтобы я мог использовать формат UTC.Проблема в том, что 'Z' нигде не встречается в документации, и любая комбинация форматов 'Z', которую я пробую, т.е.'Z', 'ZZ', 'ZZZ', всегда просто преобразует экземпляр DateTime с теми Z, которые обрабатываются как литералы.

Кто-то забыл реализовать 'Z', не сообщив автору сообщения об исключении, или я не понимаю, как заменить действительное смещение по местному времени на "+ 0000" без взлома?

Пример кода:

// This is the format with 'zzzzz' representing local time offset
const string format = "ddd MMM dd HH:mm:ss zzzzz yyyy";

// create a UTC time
const string expected = "Fri Dec 19 17:24:18 +0000 2008";
var time = new DateTime(2008, 12, 19, 17, 24, 18, 0, DateTimeKind.Utc);

// If you're using a debugger this will rightfully throw an exception
// with .NET 3.5 SP1 because 'z' is for local time only; however, the exception
// asks me to use the 'Z' specifier for UTC times, but it doesn't exist, so it
// just spits out 'Z' as a literal.
var actual = time.ToString(format, CultureInfo.InvariantCulture);

Assert.AreEqual(expected, actual);
Это было полезно?

Решение

Возможно, спецификатор формата "K" был бы как-то полезен.Это единственное, в котором, кажется, упоминается использование заглавной буквы "Z".

Буква "Z" - это своего рода уникальный случай для DateTimes.Буква "Z" на самом деле является частью стандарта даты и времени ISO 8601 для обозначения времени UTC.Когда "Z" (Zulu) ставится в конце времени, это указывает на то, что это время UTC, так что на самом деле литерал Z является частью времени.Вероятно, это создает несколько проблем для библиотеки формата даты в .NET, поскольку на самом деле это литерал, а не спецификатор формата.

Другие советы

Когда вы используете DateTime, вы можете хранить дату и время внутри переменной.

Дата может быть местным или временем UTC, это зависит от вас.

Например, я в Италии (+2 UTC)

var dt1 = new DateTime(2011, 6, 27, 12, 0, 0); // store 2011-06-27 12:00:00
var dt2 = dt1.ToUniversalTime()  // store 2011-06-27 10:00:00

Итак, что происходит, когда я печатаю dt1 и dt2, включая часовой пояс?

dt1.ToString("MM/dd/yyyy hh:mm:ss z") 
// Compiler alert...
// Output: 06/27/2011 12:00:00 +2

dt2.ToString("MM/dd/yyyy hh:mm:ss z") 
// Compiler alert...
// Output: 06/27/2011 10:00:00 +2

dt1 и dt2 содержат только информацию о дате и времени. dt1 и dt2 не содержат смещения часового пояса.

Итак, где " + 2 " откуда оно, если оно не содержится в переменных dt1 и dt2?

Это зависит от настроек часов вашей машины.

Компилятор сообщает вам, что когда вы используете формат 'zzz', вы пишете строку, которая объединяет " DATE + TIME " (которые хранятся в dt1 и dt2) + " TIMEZONE OFFSET " (это не содержится в dt1 и dt2, потому что они имеют тип DateTyme) и будет использовать смещение сервера, на котором выполняется код.

Компилятор сообщает вам "Предупреждение: вывод вашего кода зависит от смещения часов компьютера"

Если я выполню этот код на сервере, расположенном в Лондоне (+1 UTC), результат будет совершенно другим: вместо " +2 " будет написано +1 "

...
dt1.ToString("MM/dd/yyyy hh:mm:ss z") 
// Output: 06/27/2011 12:00:00 +1

dt2.ToString("MM/dd/yyyy hh:mm:ss z") 
// Output: 06/27/2011 10:00:00 +1

Правильное решение - использовать тип данных DateTimeOffset вместо DateTime. Он доступен в SQL Server, начиная с версии 2008, и в .Net Framework, начиная с версии 3.5.

Даты циклического отключения через строки всегда были проблемой ... но документы, указывающие на то, что спецификатор 'o' - это тот, который используется для циклического отключения, которое фиксирует состояние UTC. После анализа результат обычно будет иметь вид == Utc, если оригинал был UTC Я обнаружил, что лучше всего всегда нормализовать даты в UTC или локально перед сериализацией, а затем указать анализатору, какую нормализацию вы выбрали.

DateTime now = DateTime.Now;
DateTime utcNow = now.ToUniversalTime();

string nowStr = now.ToString( "o" );
string utcNowStr = utcNow.ToString( "o" );

now = DateTime.Parse( nowStr );
utcNow = DateTime.Parse( nowStr, null, DateTimeStyles.AdjustToUniversal );

Debug.Assert( now == utcNow );

На этой странице в MSDN перечислены стандартные строки формата DateTime, не включая строки, использующие 'Z'.

Обновление: вам необходимо убедиться, что остальная часть строки даты также соответствует правильному шаблону (вы не предоставили пример того, что вы отправили, поэтому трудно сказать, сделали ли вы это или нет). Чтобы формат UTC работал, он должен выглядеть следующим образом:

// yyyy'-'MM'-'dd HH':'mm':'ss'Z'
DateTime utcTime = DateTime.Parse("2009-05-07 08:17:25Z");
Label1.Text = dt.ToString("dd MMM yyyy | hh:mm | ff | zzz | zz | z");

выведет:

07 Mai 2009 | 08:16 | 13 | +02:00 | +02 | +2

Я нахожусь в Дании, мое смещение от GMT составляет +2 часа, ведьма верна.

если вам нужно смещение клиента , я рекомендую вам проверить Маленькая хитрость , которую я сделал. Страница находится на сервере в Великобритании, где время по Гринвичу +00: 00, и, как вы можете видеть, вы получите местное смещение по Гринвичу.

<Ч>

Что касается вашего комментария, я сделал:

DateTime dt1 = DateTime.Now;
DateTime dt2 = dt1.ToUniversalTime();

Label1.Text = dt1.ToString("dd MMM yyyy | hh:mm | ff | zzz | zz | z");
Label2.Text = dt2.ToString("dd MMM yyyy | hh:mm | FF | ZZZ | ZZ | Z");

и я получаю это:

07 Mai 2009 | 08:24 | 14 | +02:00 | +02 | +2
07 Mai 2009 | 06:24 | 14 | ZZZ | ZZ | Z 

Я не получаю никаких исключений, просто ... он ничего не делает с большой буквы Z: (

Извините, но я что-то упустил?

<Ч>

Внимательно читайте MSDN в пользовательских строках формата даты и времени

нет поддержки заглавных букв 'Z'.

Я имел дело с DateTimeOffset и, к сожалению, с " o " распечатывает "+ 0000" не "Z".

Итак, я закончил с

dateTimeOffset.UtcDateTime.ToString("o")
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top