it-swarm.com.de

Erstellen einer DateTime in einer bestimmten Zeitzone in c #

Ich versuche, einen Komponententest zu erstellen, um den Fall zu testen, dass sich die Zeitzone auf einem Computer ändert, weil sie falsch eingestellt und dann korrigiert wurde.

Im Test muss es mir möglich sein, DateTime-Objekte in einer nicht lokalen Zeitzone zu erstellen, um sicherzustellen, dass Personen, die den Test ausführen, dies unabhängig von ihrem Standort erfolgreich ausführen können.

Nach dem, was ich im DateTime-Konstruktor sehen kann, kann ich die Zeitzone entweder auf die lokale Zeitzone, die UTC-Zeitzone oder auf die nicht angegebene Zeitzone einstellen.

Wie erstelle ich eine DateTime mit einer bestimmten Zeitzone wie PST?

133
Jack Hughes

Jons Antwort spricht über TimeZone , aber ich würde vorschlagen, stattdessen TimeZoneInfo zu verwenden.

Persönlich mag ich es, Dinge in UTC zu halten, wo es möglich ist (zumindest für die Vergangenheit; Speichern von UTC für die Zukunft hat potenzielle Probleme ) Ich würde also eine Struktur wie diese vorschlagen:

public struct DateTimeWithZone
{
    private readonly DateTime utcDateTime;
    private readonly TimeZoneInfo timeZone;

    public DateTimeWithZone(DateTime dateTime, TimeZoneInfo timeZone)
    {
        var dateTimeUnspec = DateTime.SpecifyKind(dateTime, DateTimeKind.Unspecified);
        utcDateTime = TimeZoneInfo.ConvertTimeToUtc(dateTimeUnspec, timeZone); 
        this.timeZone = timeZone;
    }

    public DateTime UniversalTime { get { return utcDateTime; } }

    public TimeZoneInfo TimeZone { get { return timeZone; } }

    public DateTime LocalTime
    { 
        get 
        { 
            return TimeZoneInfo.ConvertTime(utcDateTime, timeZone); 
        }
    }        
}

Vielleicht möchten Sie die "TimeZone" -Namen in "TimeZoneInfo" ändern, um die Dinge klarer zu machen - ich bevorzuge die kürzeren Namen selbst.

187
Jon Skeet

Die DateTimeOffset-Struktur wurde für genau diese Art der Verwendung erstellt.

Siehe: http://msdn.Microsoft.com/en-us/library/system.datetimeoffset.aspx

Hier ein Beispiel zum Erstellen eines DateTimeOffset-Objekts mit einer bestimmten Zeitzone:

DateTimeOffset do1 = new DateTimeOffset(2008, 8, 22, 1, 0, 0, new TimeSpan(-5, 0, 0));

45
Clever Human

Die anderen Antworten hier sind nützlich, beziehen sich jedoch nicht speziell auf den Zugriff auf den Pazifik.

public static DateTime GmtToPacific(DateTime dateTime)
{
    return TimeZoneInfo.ConvertTimeFromUtc(dateTime,
        TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time"));
}

Obwohl "Pacific Standard Time" normalerweise etwas anderes bedeutet als "Pacific Daylight Time", bezieht es sich in diesem Fall auf die pazifische Zeit im Allgemeinen. Wenn Sie FindSystemTimeZoneById verwenden, um es abzurufen, ist eine der verfügbaren Eigenschaften ein Bool, der Ihnen mitteilt, ob sich diese Zeitzone derzeit in der Sommerzeit befindet oder nicht.

Sie können allgemeinere Beispiele dafür in einer Bibliothek sehen, die ich zusammen geworfen habe, um mit DateTimes umzugehen, die ich in verschiedenen Zeitzonen benötige, je nachdem, woher der Benutzer fragt, usw.:

https://github.com/b9chris/TimeZoneInfoLib.Net

Dies funktioniert nicht außerhalb von Windows (z. B. Mono unter Linux), da die Zeitliste aus der Windows-Registrierung stammt: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones\

Darunter finden Sie Schlüssel (Ordnersymbole im Registrierungseditor); Die Namen dieser Schlüssel werden an FindSystemTimeZoneById übergeben. Unter Linux muss ein separater Satz von Zeitzonendefinitionen verwendet werden, die ich nicht ausreichend untersucht habe.

33
Chris Moschini

Ich änderte Jon Skeet antwortete ein bisschen für das Web mit der Erweiterungsmethode. Es funktioniert auch auf Azure wie ein Zauber.

public static class DateTimeWithZone
{

private static readonly TimeZoneInfo timeZone;

static DateTimeWithZone()
{
//I added web.config <add key="CurrentTimeZoneId" value="Central Europe Standard Time" />
//You can add value directly into function.
    timeZone = TimeZoneInfo.FindSystemTimeZoneById(ConfigurationManager.AppSettings["CurrentTimeZoneId"]);
}


public static DateTime LocalTime(this DateTime t)
{
     return TimeZoneInfo.ConvertTime(t, timeZone);   
}
}
6
Jernej Novak

Ich mag die Antwort von Jon Skeet, möchte aber eins hinzufügen. Ich bin nicht sicher, ob Jon damit gerechnet hat, dass der ctor immer in der lokalen Zeitzone übergeben wird. Aber ich möchte es für Fälle verwenden, in denen es etwas anderes als lokal ist.

Ich lese Werte aus einer Datenbank und weiß, in welcher Zeitzone sich diese Datenbank befindet. Im ctor gebe ich also die Zeitzone der Datenbank ein. Aber dann möchte ich den Wert in Ortszeit. Jons LocalTime gibt nicht das ursprüngliche Datum zurück, das in ein lokales Zeitzonen-Datum konvertiert wurde. Es gibt das Datum zurück, das in die ursprüngliche Zeitzone konvertiert wurde (was auch immer Sie in den ctor eingegeben haben).

Ich denke, diese Eigenschaftsnamen klären es auf ...

public DateTime TimeInOriginalZone { get { return TimeZoneInfo.ConvertTime(utcDateTime, timeZone); } }
public DateTime TimeInLocalZone    { get { return TimeZoneInfo.ConvertTime(utcDateTime, TimeZoneInfo.Local); } }
public DateTime TimeInSpecificZone(TimeZoneInfo tz)
{
    return TimeZoneInfo.ConvertTime(utcDateTime, tz);
}
2
Gabe Halsmer

Dazu müssen Sie ein benutzerdefiniertes Objekt erstellen. Ihr benutzerdefiniertes Objekt enthält zwei Werte:

Nicht sicher, ob es bereits einen von CLR bereitgestellten Datentyp gibt, der diesen Datentyp enthält, aber zumindest die TimeZone-Komponente ist bereits verfügbar.

2
Jon Limjap