2008-10-07 13 views
35

Je connais la classe System.TimeZone ainsi que les nombreuses utilisations de la méthode DateTime.ToString(). Ce que je n'ai pas réussi à trouver est un moyen de convertir un DateTime en une chaîne qui, en plus des informations d'heure et de date, contient l'abréviation de fuseau horaire à trois lettres (en fait, les info-bulles de StackOverflow l'affichage de l'heure fonctionne).Comment afficher DateTime avec un fuseau horaire abrégé?

Pour faire un exemple facile à suivre pour tout le monde, continuons avec l'exemple de StackOverflow. Si vous regardez l'infobulle qui s'affiche sur les heures relatives, elle affiche la date complète, l'heure, y compris les secondes au format 12 heures, une désignation AM/PM, puis l'abréviation du fuseau horaire à trois lettres (dans leur cas, Coordonnée Temps universel). Je me rends compte que je pourrais facilement obtenir GMT ou UTC en utilisant les méthodes intégrées, mais ce que je veux vraiment, c'est l'heure comme c'est — localement dans ce cas, sur un serveur web.

Si notre serveur Web exécute Windows Server 2k3 et que son fuseau horaire est défini sur CST (ou, jusqu'à ce que daylight saving repasse en arrière, CDT est-il?), J'aimerais que notre application Web ASP.NET affiche DateTimes par rapport à ce fuseau horaire ainsi que formaté pour afficher un "CST" à la fin. Je me rends compte que je pourrais facilement le coder en dur, mais dans l'intérêt de la robustesse, je préférerais vraiment une solution basée sur le serveur exécutant les paramètres d'environnement du système d'exploitation du code.

En ce moment, j'ai tout, mais l'abréviation de fuseau horaire en utilisant le code suivant:

myDateTime.ToString("MM/dd/yyyy hh:mm:ss tt") 

qui affiche:

10/07/2008 15:40:31

Tous Je veux (et ce n'est pas beaucoup, promesse!) Est pour qu'il dise:

10/07/2008 03:40:31 CDT

Je peux utiliser System.TimeZone.CurrentTimeZone et l'utiliser pour afficher correctement "Central Daylight Time" mais ... c'est un peu trop long par souci de brièveté. Suis-je alors obligé d'écrire une routine de manipulation de chaînes pour supprimer les espaces blancs et les lettres non majuscules? Alors que cela pourrait fonctionner, cela me semble incroyablement piraté ...

Googling et en regardant autour de là n'a pas produit quelque chose de applicable à ma question spécifique.

Répondre

1

Cela dépend du niveau de robustesse dont vous avez besoin.

Vous aurez probablement besoin d'une sorte de hack de toute façon. Un moyen facile serait de diviser la chaîne par des espaces, puis de concaténer la première lettre de chaque mot. C'est-à-dire

string[] words = tzname.Split(" ".ToCharArray()); 
string tzabbr = ""; 
foreach (string word in words) 
    tzabbr += word[0]; 

Cela ne fonctionnera pas pour tous les fuseaux horaires de la planète, mais cela fonctionnera pour la plupart d'entre eux. Si vous en avez besoin plus robuste, vous devrez probablement créer une carte qui mappe les noms de fuseaux horaires à leurs abréviations.

2

Je voudrais créer une table de conversion qui convertit le nom de fuseau horaire à son abréviation. Si la correspondance n'est pas trouvée, vous pouvez retourner le nom complet de la zone.

Voir time zone abbreviations.

6

Il existe une bibliothèque disponible gratuitement, TZ4NET, dont les abréviations sont disponibles. Avant .NET 3.5, c'était l'une des seules alternatives pour la conversion entre les fuseaux horaires.

Si vous ne voulez pas de bibliothèque séparée, vous pouvez certainement générer une carte d'abréviations raisonnables à l'aide des classes TimeZoneInfo, puis les fournir à votre utilisateur.

19

Voici ma méthode de hack rapide que je viens de faire pour contourner ce problème.

public static String TimeZoneName(DateTime dt) 
{ 
    String sName = TimeZone.CurrentTimeZone.IsDaylightSavingTime(dt) 
     ? TimeZone.CurrentTimeZone.DaylightName 
     : TimeZone.CurrentTimeZone.StandardName; 

    String sNewName = ""; 
    String[] sSplit = sName.Split(new char[]{' '}); 
    foreach (String s in sSplit) 
     if (s.Length >= 1) 
      sNewName += s.Substring(0, 1); 

    return sNewName; 
} 
+5

Cette approche présente quelques failles. Par exemple, en Arizona, où ils utilisent l'heure normale des montagnes et n'observent pas l'heure d'été, .NET a un DaylightName et un StandardName de "US Mountain Standard Time" qui montrera "UMST" avec votre méthode. Je m'attendrais à voir "MST" à la place (à la fois pendant l'été et l'hiver). Malheureusement, le framework .NET semble ne pas être à la hauteur, j'ai donc eu recours à une table de recherche statique. – codemonkey

+0

Cela ne fonctionnera pas pour autant de fuseaux horaires, par ex. ** ACT ** _Acre Time_ (UTC -5) – Tanmay

2

Si en tirant l'abréviation du DaylightName/StandardName, vous allez être mieux construire la chaîne en utilisant un StringBuilder, pour les chaînes sont immuables.

public static string ToCurrentTimeZoneString(this DateTime date) 
    { 
     string name = TimeZone.CurrentTimeZone.IsDaylightSavingTime(date) ? 
      TimeZone.CurrentTimeZone.DaylightName : 
      TimeZone.CurrentTimeZone.StandardName; 
     return name; 
    } 

    public static string ToCurrentTimeZoneShortString(this DateTime date) 
    { 
     StringBuilder result = new StringBuilder(); 

     foreach (string value in date.ToCurrentTimeZoneString().Split(' ')) 
     { 
      if (value.IsNotNullOrEmptyWithTrim()) 
      { 
       result.Append(char.ToUpper(value[0])); 
      } 
     } 

     return result.ToString(); 
    } 

Bien sûr, un tableau contenant KeyValuePair est probablement le meilleur pour une multinationale. Si vous voulez réduire de quelques minutes un délai serré et que vous êtes dans une entreprise américaine, cela fonctionne.

+1

Je pense que la concaténation de trois caractères n'est pas si mauvaise et ne justifie pas l'utilisation d'un StringBuilder ici, en particulier parce que vous marchez des chaînes gauche et droite de toute façon. – Martijn

0

Ok, il a été 4 ans (et presque une semaine), il est temps que nous LINQ dans la discussion ...

Mettant ensemble de Criag et les idées de Bob ...

public static String TimeZoneName2(DateTime dt) 
{ 
    var return ToCurrentTimeZoneShortString(dt) 
       .Split(new char[]{' '}, StringSplitOptions.RemoveEmptyEntries); 
    return sSplit.Aggregate("", (st,w)=> st +=w[0]); 
} 

À moins que vous peut faire confiance TimeZone de ne jamais retourner une chaîne avec deux espaces consécutifs:

public static String TimeZoneName3(DateTime dt) 
{ 
    return ToCurrentTimeZoneShortString(dt).Split(' ') 
       .Aggregate("", (st,w)=> st +=w[0]); 
} 
0

Si vous utilisez < = .Net 3.0, puis télécharger et utiliser TZ4Net OlsonTimeZone.CurrentTimeZone .Abonnement standard pour .Net 3.0 utiliser NodaTime ou autre. Les noms des fuseaux horaires ne sont pas conformes à une convention où vous pouvez compter sur une simple manipulation de chaîne pour construire l'abréviation à partir d'un acronyme. Mauvais 5% du temps est toujours faux.

+0

Allez-vous cesser de faire des profits 95% du temps? – micahhoover

2

Utilisez nodatime.

La fonction suivante prend un DateTime en heure UTC et le met en forme avec le fuseau horaire abrégé du système local. Utilisez x dans la chaîne de format pour le fuseau horaire abrégé. Recherchez le formatage personnalisé here.

public static string ConvertToFormattedLocalTimeWithTimezone(DateTime dateTimeUtc) 
    { 
     var tz = DateTimeZoneProviders.Tzdb.GetSystemDefault(); // Get the system's time zone 
     var zdt = new ZonedDateTime(Instant.FromDateTimeUtc(dateTimeUtc), tz); 
     return zdt.ToString("MM'/'dd'/'yyyy' 'hh':'mm':'ss' 'tt' 'x", CultureInfo.InvariantCulture); 
    }