Подтвердить что ты не робот

Сокращения временной зоны

TimeZoneInfo не содержит аббревиатуры или краткое имя для данного часового пояса. Единственный хороший способ сделать это - иметь словарь, который будет отображать сокращения для свойств Timezone.id, StandardName или DaylightName. Тем не менее, все источники, которые я искал для списка сокращений, имеют разные названия часовых поясов, то есть не то же самое, что и в Windows.

Как вы показываете пользователю не полное имя, id или любое другое имя в .NET? Я не хочу, чтобы UtcOffset, но сокращение от Timezone - PST для Pacific, UTC - для Universal, EST - для Восточного стандарта и т.д. Есть ли список совместимых с С# или база данных со всеми возможными часовыми поясами и их сокращения, которые совместимы с теми, что TimeZoneInfo.GetSystemTimeZones() дает вам?

4b9b3361

Ответ 1

Это сложное требование, лучшее, что вы можете сделать, это получить список по вашему выбору и создать метод расширения/помощника, чтобы получить аббревиатуру для данного TimeZoneInfo.

Как только место для начала находится в http://www.timeanddate.com/library/abbreviations/timezones/, у которого есть версия списка, которая охватывает зоны, о которых я знаю.

Проблема заключается в выборе подходящей аббревиатуры, где для данного часового пояса существует более одного. Например, UTC может быть представлен как UTC или WET (западноевропейское время) или WEZ (Westeuropäische Zeit) или WT (стандартное время Западной Сахары).

Возможно, вы захотите согласиться с вашими заинтересованными сторонами в соглашении об именах, которое вы собираетесь следовать с выбранными вариантами.

Ответ 2

ОБНОВЛЕННЫЙ ОТВЕТ

Мой первоначальный ответ ниже, и он по-прежнему действителен. Однако теперь есть более простой способ, используя библиотеку TimeZoneNames. После установки из Nuget вы можете сделать следующее:

string tzid = theTimeZoneInfo.Id;                // example: "Eastern Standard time"
string lang = CultureInfo.CurrentCulture.Name;   // example: "en-US"
var abbreviations = TZNames.GetAbbreviationsForTimeZone(tzid, lang);

Результирующий объект будет иметь свойства, похожие на:

abbreviations.Generic == "ET"
abbreviations.Standard == "EST"
abbreviations.Daylight == "EDT"

Вы также можете использовать эту же библиотеку, чтобы получить полностью локализованные имена часовых поясов. Библиотека использует встроенную автономную копию данных CLDR.

ОРИГИНАЛЬНЫЙ ОТВЕТ

Как уже упоминалось, сокращения абзацев часовых поясов неоднозначны. Но если вы действительно хотите его отображать, вам нужна база данных часовых поясов IANA/Olson.

Вы можете перейти из часового пояса Windows в часовой пояс IANA/Olson и в другое направление. Но имейте в виду, что для любой зоны Windows может быть несколько зон IANA/Olson. Эти сопоставления сохраняются в CLDR здесь.

NodaTime имеет как базу данных, так и сопоставления. Вы можете перейти от .Net DateTime или DateTimeOffset с помощью TimeZoneInfo к NodaTime Instant и DateTimeZone. Оттуда вы можете получить название аббревиатуры.

// starting with a .Net TimeZoneInfo
var timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time");

// You need to resolve to a specific instant in time - a noda Instant
// For illustrative purposes, I'll start from a regular .Net UTC DateTime
var dateTime = DateTime.UtcNow;
var instant = Instant.FromDateTimeUtc(dateTime);

// note that if we really wanted to just get the current instant,
// it better and easier to use the following:
// var instant = SystemClock.Instance.Now;


// Now let map the Windows time zone to an IANA/Olson time zone,
// using the CLDR mappings embedded in NodaTime.  This will use
// the *primary* mapping from the CLDR - that is, the ones marked
// as "territory 001".

// we need the NodaTime tzdb source.  In NodaTime 1.1.0+:
var tzdbSource = TzdbDateTimeZoneSource.Default;

// in previous NodaTime releases:
// var tzdbSource = new TzdbDateTimeZoneSource("NodaTime.TimeZones.Tzdb");

// map to the appropriate IANA/Olson tzid
var tzid = tzdbSource.MapTimeZoneId(timeZoneInfo);

// get a DateTimeZone from that id
var dateTimeZone = DateTimeZoneProviders.Tzdb[tzid];


// Finally, let figure out what the abbreviation is
// for the instant and zone we have.

// now get a ZoneInterval for the zone and the instant
var zoneInterval = dateTimeZone.GetZoneInterval(instant);

// finally, you can get the correct time zone abbreviation
var abbreviation = zoneInterval.Name;

// abbreviation will be either PST or PDT depending
// on what instant was provided
Debug.WriteLine(abbreviation);

Ответ 3

В вашем вопросе не указывается, какие часовые пояса должны действовать в вашей заявке, но в моем конкретном случае мне нужно иметь дело только с часовыми поясами Соединенных Штатов и UTC.

Аббревиатуры часовых поясов США всегда являются первыми символами каждого слова в названии часового пояса. Например, аббревиатура "Горное стандартное время" - это "MST", а аббревиатура "Eastern Daylight Time" - "EDT".

Если у вас есть аналогичные требования, вы можете легко получить сокращенное название часового пояса локального часового пояса из имени локального часового пояса, как указано ниже (примечание: здесь я определяю собственное имя на основе текущей даты и времени ):

string timeZoneName = TimeZone.CurrentTimeZone.IsDaylightSavingTime(DateTime.Now)
                          ? TimeZone.CurrentTimeZone.DaylightName 
                          : TimeZone.CurrentTimeZone.StandardName;

string timeZoneAbbrev = GetTzAbbreviation(timeZoneName);

Код для функции GetTzInitials() довольно прост. Стоит упомянуть, что некоторые часовые пояса могут быть установлены в Мексике или Канаде, а названия часовых поясов для них будут иметь название страны в скобках, например "Стандартное тихоокеанское время (Мексика)". Чтобы справиться с этим, любые данные в скобках передаются обратно напрямую. Аббревиатура, возвращаемая для вышеуказанного, будет "PST (Мексика)", которая работает для меня.

string GetTzAbbreviation(string timeZoneName) {
    string output = string.Empty;

    string[] timeZoneWords = timeZoneName.Split(' ');
    foreach (string timeZoneWord in timeZoneWords) {
        if (timeZoneWord[0] != '(') {
            output += timeZoneWord[0];
        } else {
            output += timeZoneWord;
        }
    }
    return output;
}

Ответ 4

Вот еще один фрагмент с использованием NodaTime:

NodaTime.ZonedDateTime hereAndNow = NodaTime.SystemClock.Instance.Now.InZone(
    NodaTime.DateTimeZoneProviders.Tzdb.GetSystemDefault());

System.TimeSpan zoneOffset = hereAndNow.ToDateTimeOffset().Offset;

string sTimeDisplay = string.Format("{0:G} {1} (UTC{2}{3:hh\\:mm} {4})", 
    hereAndNow.ToDateTimeOffset(), 
    hereAndNow.Zone.GetZoneInterval(hereAndNow.ToInstant()).Name, 
    zoneOffset < TimeSpan.Zero ? "-" : "+", 
    zoneOffset, 
    hereAndNow.Zone.Id);

В моей системе это дает: "4/11/2013 5:03:23 PM CDT (UTC-05: 00 America/Chicago)"

(Спасибо Мэтту Джонсону за то, что аббревиатура живет в TimeZoneInterval)

Было бы проще, если бы у NodaTime.ZonedDateTime был метод GetZoneInterval, но, возможно, мне что-то не хватает.

Ответ 5

У меня была аналогичная проблема, но я не хотел использовать стороннюю библиотеку (как подсказывает большинство из этих ответов). Если вы хотите только поддерживать имена часовых поясов .Net и решить использовать таблицу поиска, посмотрите мой ответ здесь, который опирается на PHP, чтобы помочь создать Список сокращений. Вы можете адаптировать фрагмент и таблицу в соответствии с вашими потребностями.

Ответ 6

Это полезно для тех, кто использует Xamarin для iOS или Android, потому что согласно документации "Отображаемое имя локализовано на основе культуры, установленной в операционной системе Windows". При использовании этого в Центральном часовом поясе для DateTime "2016-09-01 12:00:00 GMT" эта функция возвращает "CDT", что именно то, что мне нужно, когда я столкнулся с этим вопросом.

public static string GetTimeZoneAbbreviation(DateTime time)
{
    string timeZoneAbbr;
    if(time.IsDaylightSavingTime() == true)
    {
        timeZoneAbbr = TimeZoneInfo.Local.DaylightName;
    }
    else
    {
        timeZoneAbbr = TimeZoneInfo.Local.StandardName;
    }

    return timeZoneAbbr;
}

Ответ 7

Я храню все свои даты в UTC и часто должен отображать их по местному времени, поэтому я создал метод расширения ToAbbreviation()

    public static string ToAbbreviation(this TimeZone theTimeZone)
    {

        string timeZoneString = theTimeZone.StandardName;
        string result = string.Concat(System.Text.RegularExpressions.Regex
           .Matches(timeZoneString, "[A-Z]")
           .OfType<System.Text.RegularExpressions.Match>()
           .Select(match => match.Value));

        return result;
    }

пример использования:

string tz = TimeZone.CurrentTimeZone.ToAbbreviation();
string formattedDate = String.Format("{0:yyyy/MM/dd hh:mm:ss} {1}", myDate, tz);

Или, если вы хотите просто получить отформатированную строку даты из объекта DateTime:

public static string ToLocalTimeWithTimeZoneAbbreviation(this DateTime dt)
{
    DateTime localtime = dt.ToLocalTime();
    string tz = TimeZone.CurrentTimeZone.ToAbbreviation();

    string formattedDate = String.Format("{0:yyyy/MM/dd hh:mm:ss} {1}", localtime, tz);
    return formattedDate;
}

и использовать следующим образом:

string formattedDate = myDateTimeObject.ToLocalTimeWithTimeZoneAbbreviation()

выходной: 2019-06-24 02:26:31 EST