Отформатируйте Local DateTime с соответствующим местным часовым поясом с поддержкой DST (например, PST или PDT) в зависимости от времени года - PullRequest
0 голосов
/ 10 февраля 2019

Учитывая значение Local DateTime на компьютере, настроенном для PST (которое неявно изменится на PDT 10 марта, когда DST вступит в силу), как можно получить строку, включающую соответствующий часовой пояс - напримерPST / PDT, не смещено!- в выводе?

DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss ???")

Ожидаемые выходные строки, например:

"2019-02-09 13:04:22 PST"  // right after lunch today
"2019-04-09 13:04:22 PDT"  // right after lunch in two months

На странице MSDN DateTime Custom Format Strings показаны примеры явного жесткого кодирования "PST "в выходной, что будет неверно в течение полугода и / или при изменении местного TZ.Компьютеры и люди перемещаются, поэтому жесткое кодирование значений TZ просто «не подходит».

Предпочтительно это можно сделать с помощью просто строки форматирования, позволяющей указывать значения DateTime до отображенияфаза / to-string - хотя, похоже, нет формата 'ZZZ'.Я указал 'Local' DateTime Kind, чтобы, надеюсь, уменьшить некоторые дополнительные причуды.

Ответы [ 2 ]

0 голосов
/ 10 февраля 2019

Поскольку экземпляр DateTime не хранит информацию о часовом поясе, это невозможно сделать с помощью пользовательских строк формата даты и времени."zzz" спецификатор предназначен для Смещение UTC значение, DateTime.Kind с "K", спецификатор также не отражает сокращение часового пояса.И то, и другое бесполезно для вашего случая.

Тем не менее, существует пакет nuget с именем TimeZoneNames , который написан специалистом по часовым поясам Мэттом Джонсоном , что вы можете получить сокращения часового пояса.имя (поддерживает IANA и идентификатор часового пояса Windows)

var tz = TZNames.GetAbbreviationsForTimeZone("Pacific Standard Time", "en-US");
Console.WriteLine(tz.Standard); // PST
Console.WriteLine(tz.Daylight); // PDT

Если вы хотите получить программный идентификатор часового пояса Windows, вы можете использовать TimeZoneInfo.Local.Id свойство , если вы хотите получить текущий код языка, вы можете использовать CultureInfo.CurrentCulture.Name свойство между прочим.

var tz = TZNames.GetAbbreviationsForTimeZone(TimeZoneInfo.Local.Id, CultureInfo.CurrentCulture.Name);

Но перед этим вы должны проверить, что местное время - летнее времячтобы выбрать, какое сокращение добавить вашу отформатированную строку.

DateTime now = DateTime.Now;
bool isDaylight = TimeZoneInfo.Local.IsDaylightSavingTime(now);

Если isDaylight равно true, вы должны использовать результат свойства TimeZoneValues.Daylight, в противном случае вам следует использовать свойство TimeZoneValues.Standardпервая часть кода.

В конце необходимо добавить одну из этих аббревиатур в конце строки DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss).

Для важной заметки Мэтта на странице пакета;

TСокращения в некоторых зонах иногда противоречивы и не обязательно правильно локализованы для каждого часового пояса.В большинстве случаев вы должны использовать сокращения только для отображения конечного пользователя.Не пытайтесь использовать сокращения при разборе ввода.

Второе важное замечание из Комментарий Мэтта ;

Что заставляет вас думать, что сокращение часового поясана самом деле существует для каждого часового пояса и каждого языка в мире?Даже тогда, что заставляет вас думать, что сокращение часового пояса достаточно для определения часового пояса?Подсказка - оба вопроса аморфны.Рассмотрим «CST» или «IST» - у каждого есть три или четыре места в мире, которым они могут принадлежать.Много-много-много других случаев ...

0 голосов
/ 10 февраля 2019

TimeZoneInfo может помочь здесь: https://docs.microsoft.com/en-us/dotnet/api/system.timezoneinfo.standardname?view=netframework-4.7.2

Похоже, что TimeZoneInfo дает полные имена («Тихоокеанское стандартное время» / «Тихоокеанское летнее время»), а не сокращения («PST»)."/"ТИХООКЕАНСКОЕ ЛЕТНЕЕ ВРЕМЯ").Это проблема, вам все равно нужно найти источник для коротких имен.Вот несколько идей о том, как это сделать: Сокращения часовых поясов

using System;
using Xunit;

namespace Q54610867
{
    public class TimeZoneTests
    {
        // I'm on Mac/Unix. If you're on Windows, change the ID to "Pacific Standard Time"
        // See: https://github.com/dotnet/corefx/issues/2538
        readonly TimeZoneInfo pacificStandardTime = TimeZoneInfo.FindSystemTimeZoneById("America/Los_Angeles");

        [Fact]
        public void Today()
        {
            var today = new DateTime(2019, 2, 9, 13, 4, 22, DateTimeKind.Local);

            Assert.Equal("2019-02-09 13:04:22 Pacific Standard Time", ToStringWithTz(today, pacificStandardTime));
        }

        [Fact]
        public void future()
        {
            var future = new DateTime(2019, 4, 9, 13, 4, 22, DateTimeKind.Local);

            Assert.Equal("2019-04-09 13:04:22 Pacific Daylight Time", ToStringWithTz(future, pacificStandardTime));
        }

        static string ToStringWithTz(DateTime dateTime, TimeZoneInfo tz)
            => $"{dateTime.ToString("yyyy-MM-dd HH:mm:ss")} {(tz.IsDaylightSavingTime(dateTime) ? tz.DaylightName : tz.StandardName)}";
    }
}
...