Преобразование времени UTC/GMT в местное время

Мы разрабатываем приложение С# для клиента веб-сервиса. Это будет работать на ПК с Windows XP.

Одним из полей, возвращаемых веб-службой, является поле DateTime. Сервер возвращает поле в формате GMT, то есть с "Z" в конце.

Однако мы обнаружили, что .NET, похоже, делает какое-то неявное преобразование, и время было всегда 12 часов.

Следующий пример кода разрешает это до некоторой степени в том, что разница в 12 часов ушла, но она не учитывает летнее время NZ.

CultureInfo ci = new CultureInfo("en-NZ");
string date = "Web service date".ToString("R", ci);
DateTime convertedDate = DateTime.Parse(date);            

По этот сайт даты:

UTC/GMT Offset

Стандартный часовой пояс: UTC/GMT +12 часов
Переход на летнее время: +1 час
Текущее смещение часового пояса: UTC/GMT +13 часов

Как мы настраиваем дополнительный час? Можно ли это сделать программно или это какая-то настройка на ПК?

Ответ 1

Для строк, таких как 2012-09-19 01:27:30.000, DateTime.Parse не может указать, в каком часовом поясе указаны дата и время.

DateTime имеет свойство Kind, которое может иметь один из трех параметров часового пояса:

  • Не выбрано
  • Local
  • Utc

ПРИМЕЧАНИЕ Если вы хотите представить дату/время, отличное от UTC или вашего локального часового пояса, вы должны использовать DateTimeOffset.


Итак, для кода в вашем вопросе:

DateTime convertedDate = DateTime.Parse(dateStr);

var kind = convertedDate.Kind; // will equal DateTimeKind.Unspecified

Вы говорите, что знаете, что это такое, так скажите это.

DateTime convertedDate = DateTime.SpecifyKind(
    DateTime.Parse(dateStr),
    DateTimeKind.Utc);

var kind = convertedDate.Kind; // will equal DateTimeKind.Utc

Теперь, как только система узнает его в UTC, вы можете просто вызвать ToLocalTime:

DateTime dt = convertedDate.ToLocalTime();

Это даст вам результат, который вам нужен.

Ответ 2

Я бы изучил использование класса System.TimeZoneInfo, если вы в .NET 3.5. См. http://msdn.microsoft.com/en-us/library/system.timezoneinfo.aspx. Это должно учитывать правильность перехода на летнее время.

// Coordinated Universal Time string from 
// DateTime.Now.ToUniversalTime().ToString("u");
string date = "2009-02-25 16:13:00Z"; 
// Local .NET timeZone.
DateTime localDateTime = DateTime.Parse(date); 
DateTime utcDateTime = localDateTime.ToUniversalTime();

// ID from: 
// "HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Time Zone"
// See http://msdn.microsoft.com/en-us/library/system.timezoneinfo.id.aspx
string nzTimeZoneKey = "New Zealand Standard Time";
TimeZoneInfo nzTimeZone = TimeZoneInfo.FindSystemTimeZoneById(nzTimeZoneKey);
DateTime nzDateTime = TimeZoneInfo.ConvertTimeFromUtc(utcDateTime, nzTimeZone);

Ответ 3

TimeZone.CurrentTimeZone.ToLocalTime(date);

Ответ 4

DateTime объекты имеют Kind of Unspecified по умолчанию, который для целей ToLocalTime считается UTC.

Чтобы получить локальное время объекта Unspecified DateTime, вам просто нужно сделать это:

convertedDate.ToLocalTime();

Шаг изменения Kind DateTime от Unspecified до UTC не требуется. Unspecified предполагается UTC для целей ToLocalTime: http://msdn.microsoft.com/en-us/library/system.datetime.tolocaltime.aspx

Ответ 5

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

DateTime.Parse() может быть сложным - см. здесь, например.

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

DateTime.ParseExact(dateString, 
                   "MM/dd/yyyy HH:mm:ss", 
                   CultureInfo.InvariantCulture, 
                   DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal)

или, что еще лучше,

DateTime.TryParseExact(...)

Флаг AssumeUniversal сообщает парсеру, что дата/время уже UTC; комбинация AssumeUniversal и AdjustToUniversal подсказывает, что это не означает, что результат преобразовывается в "локальное" время, которое он попытается выполнить по умолчанию. (Я лично стараюсь работать исключительно с UTC на уровне бизнеса/приложения/службы), но в обход преобразования в местное время также ускоряется ситуация на 50% и более в моих тестах, см. Ниже.)

Вот что мы делали раньше:

DateTime.Parse(dateString, new CultureInfo("en-US"))

Мы профилировали приложение и обнаружили, что DateTime.Parse представляет собой значительный процент использования ЦП. (Кстати, конструктор CultureInfo не внес существенный вклад в использование ЦП.)

Итак, я настроил консольное приложение для синтаксического анализа строки даты/времени 10000 раз различными способами. Итог:
Parse() 10 сек
ParseExact() (преобразование в локальный) 20-45 мс
ParseExact() (не преобразование в локальный) 10-15 мс
... и да, результаты для Parse() находятся в секундах, а остальные - в миллисекундах.

Ответ 6

Я хотел бы добавить общую заметку о осторожности.

Если все, что вы делаете, получает текущее время от внутренних часов компьютера, чтобы поместить дату/время на дисплей или отчет, тогда все будет хорошо. Но если вы сохраняете информацию о дате/времени для последующей ссылки или время вычисляет, остерегайтесь!

Предположим, вы определили, что круизный корабль прибыл в Гонолулу 20 декабря 2007 года в 15:00 UTC. И вы хотите знать, что такое местное время. 1. Вероятно, есть, по крайней мере, три "локальных". Местный может означать Гонолулу, или это может означать, где находится ваш компьютер, или это может означать местоположение, где находится ваш клиент.
2. Если вы используете встроенные функции для преобразования, это, вероятно, будет ошибкой. Это связано с тем, что переход на летнее время (возможно) на данный момент действует на ваш компьютер, но в декабре не был установлен. Но Windows этого не знает... все, что у него есть, - это один флаг, чтобы определить, действует ли летнее время. И если это в настоящее время действует, то он с радостью добавит час даже до даты в декабре.
3. Летнее время осуществляется в разных политических подразделениях по-разному (или вообще отсутствует). Не думайте, что только потому, что ваша страна меняется в определенную дату, другие страны тоже будут.

Ответ 7

Не забывайте, что у вас уже есть объект DateTime и не уверены, что он UTC или Local, достаточно просто использовать методы непосредственно на объекте:

DateTime convertedDate = DateTime.Parse(date);
DateTime localDate = convertedDate.ToLocalTime();

Как настроить дополнительный час?

Если указанный .net не будет использовать настройки локального компьютера. Я бы прочитал: http://msdn.microsoft.com/en-us/library/system.globalization.daylighttime.aspx

По внешности код может выглядеть примерно так:

DaylightTime daylight = TimeZone.CurrentTimeZone.GetDaylightChanges( year );

И как уже упоминалось выше, дважды проверьте, в какой временной зоне установлен ваш сервер. В сети есть статьи о том, как безопасно влиять на изменения в IIS.

Ответ 8

@TimeZoneInfo.ConvertTimeFromUtc(timeUtc, TimeZoneInfo.Local)

Ответ 9

В ответ на предложение Даны:

Образец кода теперь выглядит следующим образом:

string date = "Web service date"..ToString("R", ci);
DateTime convertedDate = DateTime.Parse(date);            
DateTime dt = TimeZone.CurrentTimeZone.ToLocalTime(convertedDate);

Первоначальная дата была 20/08/08; вид был UTC.

Оба "convertDate" и "dt" одинаковы:

21/08/08 10:00:26; вид был локальным

Ответ 10

У меня возникла проблема с тем, что он находился в наборе данных, который проталкивался через провод (webservice к клиенту), что он автоматически изменился, потому что поле DataTolumn DateType было установлено на локальное. Убедитесь, что вы проверяете, что такое тип DateType, если вы нажимаете DataSets.

Если вы не хотите, чтобы он менялся, установите его в Unspecified

Ответ 11

Я столкнулся с этим вопросом, так как у меня возникла проблема с датами UTC, которые вы возвращаете через интерфейс twitter (created_at в статусе); Мне нужно преобразовать их в DateTime. Ни один из ответов/примеров кода в ответах на этой странице не был достаточным, чтобы я не получил сообщение "String не был признан допустимой ошибкой DateTime" (но это самое близкое, что мне нужно найти правильный ответ на SO)

Публикуя эту ссылку здесь, если это помогает кому-то другому - ответ, который мне нужен, был найден в этом сообщении в блоге: http://www.wduffy.co.uk/blog/parsing-dates-when-aspnets-datetimeparse-doesnt-work/ - в основном используйте DateTime.ParseExact со строкой формата вместо DateTime.Parse

Ответ 12

DateTime DTStamp = TimeZoneInfo.ConvertTimeFromUtc(System.DateTime.UtcNow, TimeZoneInfo.FindSystemTimeZoneById("Стандартное время Пакистана"));