С# Разобрать строку в DateTime с определенным часовым поясом

Я немного боролся с этим, поэтому я перейду к 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);
    }

@PrasadTelkikar Я не понимаю вопроса. Эти строки всегда будут датой CST/CDT. Мне нужно проанализировать их в DateTimes в приложении, которое мне нужно запустить локально на моем ноутбуке (который работает в CST/CDT), а также в Azure PaaS.

cobolstinks 01.07.2019 19:52

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

Matt Johnson-Pint 01.07.2019 20:20
Стоит ли изучать 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 называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
2
1 930
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Вы можете использовать:

DateTime.ParseExact(...)


public static DateTime ParseExact (string s, string format, IFormatProvider provider);

У этой даты и времени нет метаданных о часовом поясе. Вы можете конвертировать в UTC, и тогда вы будете уверены, что сможете конвертировать во все часовые пояса.

Если я использую это локально (на машине с CST) по сравнению с работой в Azure PaaS (где, насколько я понимаю, местный часовой пояс — UTC), не будут ли у меня разные даты?

cobolstinks 01.07.2019 19:49

если вы знаете, что дата, которую вы хотите проанализировать, верна в UTC, вы должны проанализировать ее как UTC, и тогда все будет в порядке. Я не знаю об эффективном способе, но, например, вы можете проанализировать ее на любую дату, тогда вы создайте новую дату и время, где вы будете устанавливать галочки из первого проанализированного времени даты и установите DateTimeKind на UtcKind..... или другим способом является использование пакета nuget нода время

Peter M. 01.07.2019 19:52

Используйте метод 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 предоставляет такую ​​​​функциональность.

Вау, спасибо! это именно та информация, которая мне была нужна. Спасибо, что развеяли мои заблуждения.

cobolstinks 01.07.2019 20:22

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