2008-10-07 23 views
35

Ich kenne die System.TimeZone Klasse sowie die vielen Anwendungen der DateTime.ToString() Methode. Was ich nicht finden konnte, ist eine Möglichkeit, eine DateTime in eine Zeichenkette zu konvertieren, die zusätzlich zu den Zeit- und Datumsinformationen die aus drei Buchstaben bestehende Zeitzonenabkürzung enthält (in der Tat ähnlich wie die Tooltips von StackOverflow für relative) Zeitanzeige funktioniert).Wie wird DateTime mit einer verkürzten Zeitzone angezeigt?

Um ein Beispiel zu geben, das für jeden einfach zu befolgen und zu konsumieren ist, fahren wir mit dem StackOverflow-Beispiel fort. Wenn Sie sich die QuickInfo ansehen, die zu den relativen Zeiten angezeigt wird, werden das vollständige Datum, die Uhrzeit einschließlich der Sekunden im 12-Stunden-Format, eine AM/PM-Bezeichnung und dann die aus drei Buchstaben bestehende Zeitzonenabkürzung (in diesem Fall Koordiniert) angezeigt Weltzeit). Ich weiß, dass ich GMT oder UTC leicht mit den eingebauten Methoden bekommen könnte, aber was ich wirklich will, ist die Zeit, wie es in diesem Fall lokal ist, auf einem Webserver —.

Wenn unser Webserver Windows Server 2k3 ausführt und seine Zeitzone auf CST eingestellt ist (oder bis daylight saving zurückschaltet, CDT ist das?), Möchte ich, dass unsere ASP.NET-Webanwendung DateTimes relativ zu anzeigt Diese Zeitzone sowie formatiert, um eine "CST" am Ende anzuzeigen. Mir ist klar, dass ich das leicht programmieren kann, aber im Interesse der Robustheit würde ich wirklich eine Lösung bevorzugen, die auf dem Server basiert, auf dem die BS-Umgebungseinstellungen des Codes laufen.

Gerade jetzt, ich habe alles, aber die Zeitzone Abkürzung mit dem folgenden Code:

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

Welche zeigt:

10/07/2008 15.40.31

Alle ich will (und es ist nicht viel, versprochen!) ist es zu sagen:

10/07/2008 03.40.31 CDT

Ich kann System.TimeZone.CurrentTimeZone verwenden und es verwenden, um "Central Daylight Time" korrekt anzuzeigen, aber ... das ist der Kürze halber etwas zu lang. Bin ich dann fest und schreibe eine String-Manipulationsroutine, um Leerzeichen und alle nicht-großgeschriebenen Buchstaben zu entfernen? Während das funktionieren könnte, scheint das unglaublich hacken zu mir ...

Googling und sah sich um hier nicht etwas zu meiner spezifischen Frage anwendbar.

Antwort

1

Es hängt von der Stärke der Robustheit ab, die Sie benötigen.

Sie werden wahrscheinlich eine Art von Hack in beide Richtungen benötigen. Ein einfacher Weg wäre, die Zeichenfolge durch Leerzeichen aufzuteilen und dann den ersten Buchstaben jedes Wortes zu verketten. d. h.

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

Das funktioniert nicht für jede Zeitzone auf dem Planeten, aber es funktioniert für die meisten von ihnen. Wenn Sie es robuster benötigen, müssen Sie wahrscheinlich eine Karte erstellen, die die Zeitzonennamen ihren Abkürzungen zuordnet.

2

Ich würde eine Nachschlagetabelle erstellen, die Zeitzonenname in seine Abkürzung umwandelt. Wenn die Übereinstimmung nicht gefunden wird, können Sie den vollständigen Zonennamen zurückgeben.

Siehe time zone abbreviations.

6

Es gibt eine frei verfügbare Bibliothek, TZ4NET, die diese Abkürzungen zur Verfügung stellt. Vor .NET 3.5 war dies eine der wenigen Alternativen für die Konvertierung zwischen Zeitzonen.

Wenn Sie keine separate Bibliothek wünschen, können Sie mit den TimeZoneInfo-Klassen sicherlich eine Übersicht über sinnvolle Abkürzungen erstellen und diese dann Ihrem Benutzer zur Verfügung stellen.

19

Hier ist meine schnelle Hack-Methode, die ich gerade gemacht habe, um dies zu umgehen.

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

Dieser Ansatz hat einige Fehler. Zum Beispiel in Arizona, wo sie Mountain Standard Time verwenden und keine Sommerzeit beobachten, hat .NET einen DaylightName und einen StandardName von "US Mountain Standard Time", der "UMST" mit Ihrer Methode anzeigt. Ich würde erwarten, stattdessen "MST" zu sehen (sowohl im Sommer als auch im Winter). Leider scheint das .NET-Framework hier zu kurz zu kommen, so dass ich auf eine statische Lookup-Tabelle zurückgegriffen habe. – codemonkey

+0

Dies funktioniert nicht für so viele Zeitzonen, z. ** ACT ** _Acre Time_ (UTC-5) – Tanmay

2

Wenn ziehen die Abkürzung vom DaylightName/Standardname, wirst du besser dran, den Bau der Zeichenfolge, um einen Stringbuilder verwenden, für Strings unveränderlich sind.

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(); 
    } 

Natürlich ist ein Array mit KeyValuePairs wahrscheinlich am besten für ein multinationales Unternehmen. Wenn Sie ein paar Minuten aus einer engen Frist rasieren wollen, und Sie bei einer US-Firma sind, funktioniert das.

+1

Ich denke, dass die String-Verkettung von drei Zeichen nicht so schlecht ist und es nicht rechtfertigt, hier einen StringBuilder zu verwenden, vor allem, weil du ohnehin Strings links und rechts gehst. – Martijn

0

Ok, es ist 4 Jahre gewesen (und fast eine Woche), ist es Zeit, dass wir LINQ in die Diskussion gebracht ...

Die Zusammen Criag der und Ideen Bob ...

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

Es sei denn, Sie vertrauen kann Time-Zone nie einen String mit zwei aufeinander folgenden Leerzeichen zurück:

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

Wenn Sie < = verwenden .Net 3.0 dann herunterladen TZ4Net und verwendet OlsonTimeZone.CurrentTimeZone .StandardAbbreviation für> .Net 3.0 verwenden NodaTime oder andere. Die Zeitzonennamen entsprechen keiner Konvention, bei der Sie sich auf einfache Stringmanipulation verlassen können, um die Abkürzung aus einem Akronym zu konstruieren. Falsche 5% der Zeit ist immer noch falsch.

+0

Werden Sie in 95% der Fälle davon profitieren? – micahhoover

2

Verwenden Sie nodatime.

Die folgende Funktion nimmt eine DateTime in UTC-Zeit und formatiert sie mit abgekürzter lokaler Systemzeitzone. Verwenden Sie x in Formatzeichenfolge für abgekürzte Zeitzone. Suchen Sie nach benutzerdefinierten Formatierung .

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); 
    }