Мы разрабатываем приложение на 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
Как нам приспособиться к дополнительному часу? Это можно сделать программно или это какая-то настройка на ПК?





TimeZone.CurrentTimeZone.ToLocalTime(date);
Это работает, только если система знает, что дата, из которой конвертируется, находится в UTC. Пожалуйста, посмотрите мой ответ.
Но UTC по умолчанию, не так ли? Следовательно, он работает для «неопределенного», как в ответе CJ7.
В ответ на предложение Даны:
Теперь пример кода выглядит так:
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; вид был местным
Пожалуйста, посмотрите мой ответ для объяснения этого.
У меня была проблема с тем, что он находился в наборе данных, передаваемом по сети (веб-сервис на клиент), который автоматически изменялся, потому что поле DateType DataColumn было установлено на локальное. Убедитесь, что вы проверили, что такое DateType, если вы проталкиваете DataSets.
Если вы не хотите, чтобы он изменялся, установите для него значение «Не указано».
Я просто хотел бы добавить общее предостережение.
Если все, что вам нужно сделать, это получить текущее время от внутренних часов компьютера, чтобы отобразить дату / время на дисплее или в отчете, то все в порядке. Но если вы используете экономия информацию о дате / времени для дальнейшего использования или вычисление дату / время, будьте осторожны!
Допустим, вы определили, что круизный лайнер прибыл в Гонолулу 20 декабря 2007 года в 15:00 UTC. И вы хотите знать, какое это было местное время. 1. Здесь, вероятно, задействовано как минимум три «местных». Местный может означать Гонолулу, или это может означать, где находится ваш компьютер, или это может означать местоположение, где находится ваш клиент. 2. Если вы используете встроенные функции для преобразования, вероятно, это будет неправильно. Это связано с тем, что на вашем компьютере (вероятно) сейчас действует летнее время, но НЕ действовало в декабре. Но Windows этого не знает ... все, что у нее есть, - это один флаг, чтобы определить, действует ли в настоящее время летнее время. И если он действует в настоящее время, то с радостью прибавит час даже к дате в декабре. 3. Переход на летнее время по-разному (или не реализован вообще) в разных административных единицах. Не думайте, что только потому, что ваша страна изменится в определенный день, это изменится и в других странах.
На самом деле №2 не совсем правильный. На самом деле существуют правила перехода на летнее время в каждом часовом поясе, который ваш компьютер будет знать, если информация была установлена (и обновлена). Для многих зон эти правила установлены. Другие реализуют «динамическое летнее время». Бразилия - моя любимая мозоль за это. Таким образом, ваш компьютер может определить, будет ли ваше местное время в декабре летним временем, при условии, что в период с этого момента никакие изменения не будут внесены в закон.
Даже если вы не живете в Бразилии, DST является «динамичным», так как политики могут изменить его в любое время (как это было сделано несколько лет назад в США). Поскольку большая часть программного обеспечения написана с расчетом на будущее, важно понимать, что НЕ существует практического, предсказуемого или даже теоретического способа узнать, какие правила DST будут действовать. Вы можете приблизиться, но избавьте себя от разочарования, отказавшись от совершенства.
Не забывайте, что если у вас уже есть объект 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 / неуказанный).
Я бы рассмотрел использование класса 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. Это просто ненужная сложность. См. Мой ответ для более подробной информации.
И если кому-то нужно, вот список часовых поясов, которые я нашел для TimeZoneInfo.FindSystemTimeZoneById - codeproject.com/Messages/3867850/…
Блестяще! Спасибо за этот пост, Дэн. Искал это исправление 3 дня.
Для таких строк, как 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);
разве это не ToLocalTime ()? @Brad - твои родители не подходят.
Учитывает ли это решение летнее время? Когда пробую, у меня не хватает часа.
@BobHorn, да, должно. Здесь, в Лондоне, это учитывает GMT / BST, поскольку они переключаются между сезонами. Возможно, пройдитесь по вашему коду в отладчике и проверьте свойство Kind значений DateTime в процессе.
Шаг изменения Kind в DateTime с Unspecified на UTC не требуется. Unspecified считается UTC для целей ToLocalTime: msdn.microsoft.com/en-us/library/…
@ CJ7: Да, но явное выражение особенно полезно для других разработчиков, которым, возможно, придется поддерживать код.
Что, если мы укажем DateTimeKind.Local во втором фрагменте?
Я столкнулся с этим вопросом, так как у меня возникла проблема с датами 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.
@TimeZoneInfo.ConvertTimeFromUtc(timeUtc, TimeZoneInfo.Local)
Этот блок кода использует универсальное время для преобразования текущего объекта DateTime, а затем преобразует его обратно в локальный DateTime. Идеально работает для меня, надеюсь, это поможет!
CreatedDate.ToUniversalTime().ToLocalTime();
время
Zотносится к UTC, а не по Гринвичу. Эти два значения могут отличаться до 0,9 секунды.