C # Parse String в DateTime с определенным часовым поясом - PullRequest
0 голосов
/ 01 июля 2019

Я боролся с этим немного, поэтому я собираюсь сделать так.

У меня есть приложение, в котором мне нужно разобрать строки в datetime. Строки выглядят так:

"201503131557"

(они всегда будут в этом формате "ггггМддЧЧмм") и всегда будут в центральном стандартном времени (или центральном летнем времени в зависимости от даты), даже если они не указывают его.

Когда я разбираю их, я понимаю, что они разбираются по местному времени. Я работаю в Azure PaaS и не хочу менять его для запуска в CST просто для поддержки этой операции.

Как написать код, работающий как локально, так и в PaaS Azure, который будет правильно анализировать эти даты в 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);
    }

Ответы [ 3 ]

3 голосов
/ 01 июля 2019

Чтобы проанализировать строку, поскольку у вас есть только дата и время, и вы знаете, в каком формате будут находиться строки, сделайте следующее:

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" (или использовать мою библиотеку TimeZoneConverter , чтобы использовать любой идентификатор на любой платформе).

Следующий шаг - выяснить, что вы хотите сделать с этим значением.Вы можете сделать с ним несколько разных вещей:

  • Если вы хотите преобразовать его в эквивалентное значение UTC, представленное как DateTime, то вы можете сделать это:

    DateTime utc = TimeZoneInfo.ConvertTimeToUtc(dt, tz);
    
  • Если вам нужно представление DateTimeOffset, которое содержит введенный вами ввод и смещение от UTC, так как оно относится к центральному времени США, вы можете сделать это:

    TimeSpan offset = tz.GetUtcOffset(dt);
    DateTimeOffset dto = new DateTimeOffset(dt, offset);
    

    Имейте в виду, что время ввода может быть недопустимым или неоднозначным, если оно близко к переходу DST.В таких случаях метод GetUtcOffset возвращает стандартное смещение 1035 *.Если вам нужно другое поведение, у вас есть больше кода для написания (выходит за рамки этого поста).

  • Есть и другие вещи, которые вы можете сделать, все из которых предоставляются TimeZoneInfo class.

Обратите внимание, что "Azure PaaS" может относиться к нескольким различным вещам, и хотя в службе приложений Azure есть параметр WEBSITE_TIME_ZONE -Я не рекомендую вам опираться на это.Считайте, что это последнее средство, которое можно использовать только тогда, когда вы не можете контролировать код.В большинстве случаев лучше писать код, чтобы он никогда не зависел от настройки часового пояса системы, в которой он работает.Это означает никогда не вызывать DateTime.Now, или TimeZoneInfo.Local, DateTime.ToLocalTime, или даже DateTime.ToUniversalTime (поскольку он конвертирует из местного часового пояса) и т. Д. Вместо этого полагайтесь на методы, которые работают явно сили UTC или определенный часовой пояс или смещение.Тогда вам больше не нужно заботиться о том, где размещено ваше приложение.

Наконец, следует понимать, что ни типы DateTime, ни DateTimeOffset не способны понять, что значение привязано к определенному часовому поясу.Для этого вам нужно либо написать свой собственный класс, либо обратиться к библиотеке Noda Time , класс ZonedDateTime которой обеспечивает такую ​​функциональность.

0 голосов
/ 01 июля 2019

Используйте метод DateTime.TryParseExact (...) с DateTimeStyles.RoundtripKind, чтобы избежать преобразования.

DateTime dt;
DateTime.TryParseExact("201503131557", "yyyyMMddHHmm", null, System.Globalization.DateTimeStyles.RoundtripKind, out dt);

Если вам нужно конвертировать, вам нужно перейти в UTC, тогда используйте методы конвертации TimeZoneInfo с TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time").

0 голосов
/ 01 июля 2019

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

DateTime.ParseExact (...)


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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...