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

Мы разрабатываем приложение на 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 Offset

Standard time zone: UTC/GMT +12 hours
Daylight saving time: +1 hour
Current time zone offset: UTC/GMT +13 hours

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

время Z относится к UTC, а не по Гринвичу. Эти два значения могут отличаться до 0,9 секунды.

mc0e 27.02.2017 07:30
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
314
1
428 062
12

Ответы 12

TimeZone.CurrentTimeZone.ToLocalTime(date);

Это работает, только если система знает, что дата, из которой конвертируется, находится в UTC. Пожалуйста, посмотрите мой ответ.

Drew Noakes 08.06.2009 11:44

Но UTC по умолчанию, не так ли? Следовательно, он работает для «неопределенного», как в ответе CJ7.

NickG 12.06.2013 18:06

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

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

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

Пожалуйста, посмотрите мой ответ для объяснения этого.

Drew Noakes 08.06.2009 11:46

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

Если вы не хотите, чтобы он изменялся, установите для него значение «Не указано».

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

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

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

На самом деле №2 не совсем правильный. На самом деле существуют правила перехода на летнее время в каждом часовом поясе, который ваш компьютер будет знать, если информация была установлена ​​(и обновлена). Для многих зон эти правила установлены. Другие реализуют «динамическое летнее время». Бразилия - моя любимая мозоль за это. Таким образом, ваш компьютер может определить, будет ли ваше местное время в декабре летним временем, при условии, что в период с этого момента никакие изменения не будут внесены в закон.

Roger Willcocks 16.06.2011 16:04

Даже если вы не живете в Бразилии, DST является «динамичным», так как политики могут изменить его в любое время (как это было сделано несколько лет назад в США). Поскольку большая часть программного обеспечения написана с расчетом на будущее, важно понимать, что НЕ существует практического, предсказуемого или даже теоретического способа узнать, какие правила DST будут действовать. Вы можете приблизиться, но избавьте себя от разочарования, отказавшись от совершенства.

DaveWalley 15.05.2014 00:45

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

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

How do we adjust for the extra hour?

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

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

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

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

Система справится с этой сложностью за вас, если вы сообщите системе, какой у вас «тип» (локальный / utc / неуказанный).

Drew Noakes 08.06.2009 11:47

Я бы рассмотрел использование класса 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);

Если вы работаете в своем часовом поясе (в данном случае en-NZ), вам не нужно иметь дело с TimeZoneInfo. Это просто ненужная сложность. См. Мой ответ для более подробной информации.

Drew Noakes 08.06.2009 11:45

И если кому-то нужно, вот список часовых поясов, которые я нашел для TimeZoneInfo.FindSystemTimeZoneById - codeproject.com/Messages/3867850/…

nikib3ro 25.04.2011 23:54

Блестяще! Спасибо за этот пост, Дэн. Искал это исправление 3 дня.

Kevin Moore 13.01.2017 18:17

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

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

  • Неопределенные
  • Местный
  • Универсальное глобальное время

ПРИМЕЧАНИЕЕсли вы хотите представить дату / время, отличные от 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();

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

просто еще один способ указать вид: DateTime convertedTime = new DateTime(DateTime.Parse(dateStr).Ticks), DateTimeKind.Utc);

Brad 06.10.2010 18:37

разве это не ToLocalTime ()? @Brad - твои родители не подходят.

TrueWill 10.02.2011 01:50

Учитывает ли это решение летнее время? Когда пробую, у меня не хватает часа.

Bob Horn 19.09.2012 00:41

@BobHorn, да, должно. Здесь, в Лондоне, это учитывает GMT / BST, поскольку они переключаются между сезонами. Возможно, пройдитесь по вашему коду в отладчике и проверьте свойство Kind значений DateTime в процессе.

Drew Noakes 19.09.2012 04:26

Шаг изменения Kind в DateTime с Unspecified на UTC не требуется. Unspecified считается UTC для целей ToLocalTime: msdn.microsoft.com/en-us/library/…

CJ7 14.11.2012 10:43

@ CJ7: Да, но явное выражение особенно полезно для других разработчиков, которым, возможно, придется поддерживать код.

Ryan 18.01.2013 03:20

Что, если мы укажем DateTimeKind.Local во втором фрагменте?

Faisal Mq 24.12.2018 16:12

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

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

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

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

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

Следовательно, чтобы получить местное время объекта UnspecifiedDateTime, вам просто нужно сделать следующее:

convertedDate.ToLocalTime();

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

И наоборот: convertedDate.FromLocalTime(); преобразуется в UTC.

R. Schreurs 24.08.2017 16:56

@TimeZoneInfo.ConvertTimeFromUtc(timeUtc, TimeZoneInfo.Local)

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

CreatedDate.ToUniversalTime().ToLocalTime();

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