Я немного боролся с этим, поэтому я перейду к SO.
У меня есть приложение, в котором мне нужно разобрать строки на дату и время. Строки выглядят так:
"201503131557"
(они всегда будут в формате «ггггММддЧЧмм») и всегда будут указывать центральное стандартное время (или центральное летнее время в зависимости от даты), даже если они не указывают его.
Когда я их разбираю, я понимаю, что он разбирает их по местному времени. Я использую Azure PaaS и не хочу изменять его для работы в CST только для поддержки этой операции.
Как написать код, работающий как локально, так и в Azure PaaS, который будет правильно анализировать эти даты в DateTimes, устанавливая их часовой пояс на CST?
Вот быстрый модульный тест, который я написал, чтобы доказать ответ Мэтта Джонсона.
[TestMethod]
public void DateTests()
{
var unSpecDt = DateTime.ParseExact("201503131557", "yyyyMMddHHmm", CultureInfo.InvariantCulture);
var tz = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time");
var utcDt = TimeZoneInfo.ConvertTimeToUtc(unSpecDt, tz);
var offset = tz.GetUtcOffset(unSpecDt);
var dto =new DateTimeOffset(unSpecDt, offset);
var cstDt = dto.DateTime;
Assert.IsTrue(cstDt.Hour - utcDt.Hour == offset.Hours);
}
Я думаю, что вопрос понятен, но я понимаю, почему некоторые могут понизить его, поскольку он не показывает усилий по исследованию. Если вы хотите улучшить вопрос, вы можете отредактировать его, чтобы показать, что вы пытались сделать, и объяснить, что вы хотите сделать с результатом.





Вы можете использовать:
public static DateTime ParseExact (string s, string format, IFormatProvider provider);
У этой даты и времени нет метаданных о часовом поясе. Вы можете конвертировать в UTC, и тогда вы будете уверены, что сможете конвертировать во все часовые пояса.
Если я использую это локально (на машине с CST) по сравнению с работой в Azure PaaS (где, насколько я понимаю, местный часовой пояс — UTC), не будут ли у меня разные даты?
если вы знаете, что дата, которую вы хотите проанализировать, верна в UTC, вы должны проанализировать ее как UTC, и тогда все будет в порядке. Я не знаю об эффективном способе, но, например, вы можете проанализировать ее на любую дату, тогда вы создайте новую дату и время, где вы будете устанавливать галочки из первого проанализированного времени даты и установите DateTimeKind на UtcKind..... или другим способом является использование пакета nuget нода время
Используйте метод DateTime.TryParseExact(...) с DateTimeStyles.RoundtripKind, чтобы избежать преобразования.
DateTime dt;
DateTime.TryParseExact("201503131557", "yyyyMMddHHmm", null, System.Globalization.DateTimeStyles.RoundtripKind, out dt);
Если вам нужно преобразовать, вам нужно будет перейти в UTC, а затем использовать методы преобразования TimeZoneInfo с TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time").
Чтобы разобрать строку, поскольку у вас есть только дата и время, и вы знаете конкретный формат, в котором будут строки, сделайте следующее:
DateTime dt = DateTime.ParseExact("201503131557", "yyyyMMddHHmm", CultureInfo.InvariantCulture);
Полученное значение будет иметь свойство Kind, установленное на DateTimeKind.Unspecified (не местное время, как вы думали). Этого следовало ожидать, поскольку вы не предоставили информации о том, как эта метка времени связана с UTC или местным временем.
Вы сказали, что значение представляет собой время по центральному стандартному времени. Вам понадобится объект TimeZoneInfo, который понимает этот часовой пояс.
TimeZoneInfo tz = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time");
Обратите внимание, что этот идентификатор представляет собой центральное время, наблюдаемое в США, включая как CST, так и CDT, в зависимости от того, что действует для данного значения (несмотря на слово «Стандарт» в его названии). Также обратите внимание, что это действительно только в операционных системах Windows. Если вы хотите использовать .NET Core в какой-либо другой ОС, вам нужно вместо этого передать идентификатор IANA "America/Chicago" (или использовать мою библиотеку Конвертер часового пояса для использования любого идентификатора на любой платформе).
Следующий шаг — выяснить, что вы хотите делать с этим значением. Вы можете делать с ним несколько разных вещей:
Если вы хотите преобразовать его в эквивалентное значение UTC, представленное как DateTime, вы можете сделать это:
DateTime utc = TimeZoneInfo.ConvertTimeToUtc(dt, tz);
Если вам нужно представление DateTimeOffset, которое содержит введенные вами данные и смещение от UTC по отношению к центральному времени США, вы можете сделать это:
TimeSpan offset = tz.GetUtcOffset(dt);
DateTimeOffset dto = new DateTimeOffset(dt, offset);
Имейте в виду, что время ввода может быть недопустимым или неоднозначным, если оно приближается к переходу на летнее время. В таких случаях метод GetUtcOffset вернет смещение стандартный. Если вы хотите другое поведение, вам нужно написать больше кода (это выходит за рамки этого поста).
Есть и другие вещи, которые вы можете делать, и все они предоставляются классом TimeZoneInfo.
Обратите внимание, что «Azure PaaS» может относиться к нескольким разным вещам, и хотя в службе приложений Azure есть параметр WEBSITE_TIME_ZONE, я не рекомендую вам полагаться на него. Считайте, что это последнее средство, которое можно использовать только тогда, когда вы не могу управляете кодом. В большинстве случаев лучше писать свой код так, чтобы он никогда не зависел от настройки часового пояса системы, в которой он работает. Это означает, что никогда нельзя вызывать DateTime.Now или TimeZoneInfo.Local, DateTime.ToLocalTime или даже DateTime.ToUniversalTime (поскольку он преобразует от в местный часовой пояс) и т. д. Вместо этого полагайтесь на методы, которые явно работают либо с UTC, либо с конкретным часовым поясом, либо смещением. Тогда вам никогда не придется заботиться о том, где размещено ваше приложение.
Наконец, поймите, что ни типы DateTime, ни DateTimeOffset не способны понять, что значение привязано к определенному часовому поясу. Для этого вам нужно либо написать свой собственный класс, либо обратиться к библиотеке Нода Время, чей класс ZonedDateTime предоставляет такую функциональность.
Вау, спасибо! это именно та информация, которая мне была нужна. Спасибо, что развеяли мои заблуждения.
@PrasadTelkikar Я не понимаю вопроса. Эти строки всегда будут датой CST/CDT. Мне нужно проанализировать их в DateTimes в приложении, которое мне нужно запустить локально на моем ноутбуке (который работает в CST/CDT), а также в Azure PaaS.