web-dev-qa-db-fra.com

Abréviations de fuseau horaire

TimeZoneInfo ne fournit pas d'abréviation ni de nom abrégé pour un fuseau horaire donné. La seule bonne façon de le faire est d'avoir un dictionnaire qui mappera les abréviations sur les propriétés Timezone.id, StandardName ou DaylightName. Cependant, toutes les sources que j'ai recherchées pour la liste des abréviations ont des noms de fuseau horaire différents, c'est-à-dire différents de ceux de Windows.

Comment montrer à un utilisateur un nom complet, un identifiant ou tout autre nom dans .NET? Je ne veux pas l'UtcOffset mais l'abréviation du fuseau horaire - PST pour le Pacifique, UTC - pour Universal, EST - pour Eastern Standard et etc. Existe-t-il une liste ou une base de données compatible C # avec tous les fuseaux horaires possibles et leurs abréviations compatibles avec ceux qui TimeZoneInfo.GetSystemTimeZones() vous donne?

47
iLemming

Il s'agit d'une exigence délicate, le mieux que vous puissiez faire est d'obtenir la liste de votre choix et de créer une méthode d'extension/d'assistance pour obtenir l'abréviation de TimeZoneInfo donné.

Une fois que l'endroit pour commencer est à http://www.timeanddate.com/library/abbreviations/timezones/ qui a une version de liste qui couvre les zones que je connais.

Le problème serait de sélectionner une abréviation appropriée lorsqu'il en existe plusieurs pour un fuseau horaire donné. Par exemple [~ # ~] utc [~ # ~] peut être représenté par [~ # ~] utc [~ # ~] ou HUMIDE (heure d'Europe occidentale) ou WEZ (Westeuropäische Zeit) ou WT (Western Sahara Standard Time) .

Vous voudrez peut-être convenir avec vos parties prenantes de la convention de dénomination que vous allez suivre avec les choix donnés.

13
user474407

RÉPONSE MISE À JOUR

Ma réponse d'origine est ci-dessous et est toujours valide. Cependant, il existe désormais un moyen plus simple d'utiliser la bibliothèque TimeZoneNames . Après avoir installé depuis Nuget , vous pouvez effectuer les opérations suivantes:

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

L'objet résultant aura les propriétés similaires à:

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

Vous pouvez également utiliser cette même bibliothèque pour obtenir les noms entièrement localisés des fuseaux horaires. La bibliothèque utilise une copie autonome intégrée des données CLDR.

RÉPONSE ORIGINALE

Comme d'autres l'ont mentionné, les abréviations des fuseaux horaires sont ambiguës. Mais si vous en voulez vraiment un pour l'affichage, vous avez besoin d'une base de données de fuseaux horaires IANA/Olson.

Vous pouvez également passer d'un fuseau horaire Windows à un fuseau horaire IANA/Olson et dans l'autre sens. Mais sachez qu'il peut y avoir plusieurs zones IANA/Olson pour une zone Windows donnée. Ces mappages sont conservés dans le CLDR ici .

NodaTime possède à la fois la base de données et les mappages. Vous pouvez passer d'un .Net DateTime ou DateTimeOffset avec un TimeZoneInfo, à un NodaTime Instant et DateTimeZone. De là, vous pouvez obtenir le nom de l'abréviation.

// 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's better and easier to use the following:
// var instant = SystemClock.Instance.Now;


// Now let's 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's 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);
64

Votre question n'indique pas dans quels fuseaux horaires votre application doit fonctionner, mais dans mon cas particulier, je n'ai besoin que de me préoccuper des fuseaux horaires des États-Unis et de l'UTC.

Les abréviations des fuseaux horaires américains sont toujours les premiers caractères de chaque mot du nom du fuseau horaire. Par exemple, l'abréviation de "Mountain Standard Time" est "MST" et l'abréviation de "Eastern Daylight Time" est "EDT".

Si vous avez des exigences similaires, vous pouvez facilement dériver l'abréviation de fuseau horaire du fuseau horaire local directement du nom du fuseau horaire local, comme suit (remarque: ici, je détermine le nom correct en fonction de la date et de l'heure actuelles):

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

string timeZoneAbbrev = GetTzAbbreviation(timeZoneName);

Le code de la fonction GetTzInitials() est assez simple. Une chose à noter est que certains fuseaux horaires peuvent être définis sur le Mexique ou le Canada, et les noms de fuseau horaire pour ceux-ci viendront avec le nom du pays entre parenthèses, comme "Pacific Standard Time (Mexico)". Pour y faire face, toutes les données entre parenthèses sont renvoyées directement. L'abréviation renvoyée pour ce qui précède sera "PST (Mexique)", qui fonctionne pour moi.

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;
}
12
STLDev

Voici un autre extrait utilisant 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);

Sur mon système, cela donne: "4/11/2013 5:03:23 PM CDT (UTC-05: 00 America/Chicago)"

(Merci à la réponse de Matt Johnson pour l'indice que l'abréviation vit dans TimeZoneInterval)

Ce serait plus facile si NodaTime.ZonedDateTime avait une méthode GetZoneInterval, mais peut-être que je manque quelque chose.

2
BrandonLWhite

J'ai eu un problème similaire, mais je ne voulais pas utiliser une bibliothèque tierce (comme la plupart de ces réponses le suggèrent). Si vous souhaitez uniquement prendre en charge les noms de fuseau horaire de .Net et décidez d'utiliser une table de recherche, jetez un œil à ma réponse ici , qui s'appuie sur PHP pour aider générer une liste d'abréviations. Vous pouvez y adapter l'extrait de code et le tableau en fonction de vos besoins.

1
QuickDanger

Ceci est utile pour toute personne utilisant Xamarin pour iOS ou Android car selon la documentation "Le nom d'affichage est localisé en fonction de la culture installée avec le système d'exploitation Windows." Lorsque vous l'utilisez dans le Central Fuseau horaire, pour le DateTime "2016-09-01 12:00:00 GMT", cette fonction renvoie "CDT" qui est exactement ce dont j'avais besoin quand je suis tombé sur cette question.

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

    return timeZoneAbbr;
}
1
Gandalf458

Je stocke toutes mes dates en UTC et je dois souvent les afficher à l'heure locale, j'ai donc créé une méthode d'extension 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;
    }

exemple d'utilisation:

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

Ou, si vous souhaitez simplement obtenir une chaîne de date formatée à partir d'un objet 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;
}

et utilisez comme suit:

string formattedDate = myDateTimeObject.ToLocalTimeWithTimeZoneAbbreviation()

sortie: 2019-06-24 02:26:31 EST

0
Adam Hey