Конвертировать время UTC / GMT по местному времени - PullRequest
281 голосов
/ 07 октября 2008

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

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

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

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

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

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

UTC / GMT смещение

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

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

Ответы [ 11 ]

361 голосов
/ 08 июня 2009

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

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

  • Неизвестно
  • Местное
  • 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();

Это даст вам требуемый результат.

114 голосов
/ 19 января 2009

Я хотел бы изучить использование класса 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);
48 голосов
/ 07 октября 2008
TimeZone.CurrentTimeZone.ToLocalTime(date);
21 голосов
/ 16 ноября 2012

DateTime объекты имеют Kind из 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

15 голосов
/ 26 октября 2011

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

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() находятся в секундах , тогда как остальные в миллисекундах .

14 голосов
/ 08 октября 2008

Я просто хотел бы добавить общее предупреждение:

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

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

4 голосов
/ 08 октября 2008

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

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.

2 голосов
/ 28 мая 2017
@TimeZoneInfo.ConvertTimeFromUtc(timeUtc, TimeZoneInfo.Local)
2 голосов
/ 07 октября 2008

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

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

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; вид был местный

1 голос
/ 03 октября 2009

Я сталкивался с этим вопросом, так как у меня была проблема с датами UTC, которые вы возвращаете через твиттер API (поле made_at в статусе); Мне нужно конвертировать их в DateTime. Ни один из ответов / примеров кода в ответах на этой странице не был достаточным для того, чтобы я не получил ошибку «Строка не была распознана как действительный DateTime» (но это самый близкий способ найти правильный ответ на SO)

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

...