none
DateTime und IsDayLightSavingsTime RRS feed

  • Frage

  • Hallo zusammen,

    ich habe ein etwas seltsames Verhalten, welches ich mir momentan nicht erklären kann. Folgender Code zeigt mir für den Tag der Umstellung von Sommerzeit auf Normalzeit im letzten Herbst an, ob es sich bei dem Datum noch um Sommer- oder schon um Normalzeit handelt. Zudem lasse ich mir von der Zeitzoneninfo ausgeben, wo denn die Grenze zwischen Sommer- und Winterzeit liegt.

    DateTime d = DateTime.SpecifyKind(Convert.ToDateTime("25.10.2009 01:00"), DateTimeKind.Local);

    for (int i = 0; i < 12; i++)
    {
       d = d.AddMinutes(10);
       Console.WriteLine(d.ToString("dd.MM.yyyy HH:mm") + " " + d.IsDaylightSavingTime() + " - " + TimeZone.CurrentTimeZone.GetDaylightChanges(2009).End.ToString("dd.MM.yyyy HH:mm"));
    }

    Normalerweise möchte man annehmen, dass genau an der selben Stelle, an der IsDaylightSavingTime() auf "false" umschlägt, auch die von der CurrentTimeZone gemeldete Grenze liegt. Aber weit gefehlt! IsDaylightSavingTime() springt bei 2 Uhr um, die angegebene Grenze liegt bei 3 Uhr.

    Warum ist das an der Stelle uneinheitlich? Was habe ich übersehen, oder ist da tatsächlich was Faul im .Net Framework?

    Grüße,

    Alex
    Freitag, 15. Januar 2010 17:15

Antworten

  • Hallo Alex,

    bei einer lokalen Zeit kann man während der Zeitumstellung nicht feststellen,
    ob es nun 2.00A oder 2.00B Uhr ist.
    Das ist genauso, wenn Du nachts aufwachst und auf Deinen analogen Funkwecker guckst,
    dann weisst Du das auch nicht.

    Eine Addition in einer Schleife ändert daran nichts nichts.
    Dabei entsteht jeweils eine neue DateTime Instanz, die einen Zeitpunkt
    in einer Zeitzone repräsentiert.
    Dort ist kein "Gedächtnis" vorhanden, welche vorherige Zeit gegolten hat.

    Eine Anwendung, die unabhängig von Zeitzonen und Sommerzeiten
    funktionieren muß, sollte deswegen durchgängig mit UTC arbeiten
    Und für die Darstellung jeweils eine Umwandlung vornehmen.

    Mit DateTimeOffset gibt es dazu eine Klasse, die die Zeitzone verwaltet.
    Da bekämst Du die Unterschiede zu sehen:

                DateTimeOffset d = new DateTimeOffset(DateTime.SpecifyKind(Convert.ToDateTime("25.10.2009 01:00"), DateTimeKind.Local));
    
                for (int i = 0; i < 12; i++)
                {
                    d = d.AddMinutes(15);
                    Console.WriteLine(d.ToLocalTime().ToString());
                }
    
    Gruß Elmar

    Samstag, 16. Januar 2010 10:32
    Beantworter

Alle Antworten

  • Hallo Alex,

    Die DaylightTime existiert je Zeitzone nur einmalig pro Jahr und gibt einen Bereich an -
    siehe auch das Beispiel bei der Klasse selbst.

    Deswegen kann für eine konkretes Datum nichts "umschlagen";
    zumal die CurrentTimeZone ändert sich nicht, sondern verweist weiterhin
    auf die Systemzeitzone des Rechners.

    Der Ausdruck ist also in der Schleife fehlplatziert.

    Gruß Elmar
    Freitag, 15. Januar 2010 17:38
    Beantworter
  • Hallo Elmar,

    der Ausdruck zu CurrentTimezone steht nur als Vergleich in der Schleife. Das es dieses Datum pro Jahr nur einmal gibt, ist mir durchaus bewusst. Es schlägt aber die Eigenschaft "IsDaylightSavingTime()" für die Datumswerte um und zwar nicht synchron zu der Uhrzeit, welche die Methode "GetDaylightChanges" ausgibt. Exakt dieses seltsame Verhalten ist immer noch meine Frage.

    Vielleicht führst du den Code mal aus, dann verstehst du auch mein Problem?!?

    Viele Grüße,

    Alex
    Freitag, 15. Januar 2010 18:25
  • Hallo Alex,

    Dein Problem ist ein sehr allgemeines mit den Zeiten, die während der Umstellung gültig sind. Bei der Umstellung im Herbst wird um 3 Uhr die Uhr um eine Stunde zurückgestellt. Ergo, haben wir dann zwei mal "2 Uhr". Von welchem Zeitpunkt möchtest Du jetzt wissen, ob er in der Sommerzeit liegt oder ob es bereits die "zweite Runde" in Normalzeit ist? Eigentlich müsste IsDaylightSavingTime hier einen TriState zurückgeben: True, False und Indeterminate, der aussagt, dass keine Bestimmung auf Sommer- oder Normalzeit möglich ist.

    Siehe dazu auch:
    Coding Best Practices Using DateTime in the .NET Framework
    Dealing with Daylight Savings Time



    Thorsten Dörfler
    Microsoft MVP Visual Basic
    Freitag, 15. Januar 2010 19:31
    Beantworter
  • Hallo Alex,

    ja ich hatte den Code ausgeführt und die Dokumentation (erneut) gelesen...

    IsDaylightSavingTime entspricht dem Aufruf von TimeZone.IsDaylightSavingTime
    Und wie dort dokumentiert ist die Methode eingeschränkt. Eine Änderung ist
    aus Kompatibilität nicht möglich.

    Die neuere (seit 3.5)  TimeZoneInfo.IsDaylightSavingTime-Methode liefert akkuratere
    Ergebnisse. Und hier ist die Doppeldeutigkeit auch abfragbar, bau z. B. ein:
             + "Info: " + TimeZoneInfo.Local.IsDaylightSavingTime(d) + " "
             + "Ambigous: " + TimeZoneInfo.Local.IsAmbiguousTime(d) + " "
    
    was für 2A und 2B Uhr nunmal unvermeidlich ist, siehe Sommerzeit .

    Gruß Elmar
    Freitag, 15. Januar 2010 19:43
    Beantworter
  • Hallo Thorsten,

    wie die Zeitumstellung funktioniert, weiß ich schon. Zudem muss ich leider wiedersprechen. In meinem Code habe ich absichtlich dafür gesorgt, dass die DateTime-Instanz in der Schleife vom DateTimeKind.Local ist. Meines logischen empfinden nach sollte es also genau eine 2:00 Uhr geben, die bei IsDaylightSavingsTime true zurückliefert und eine, die false ergibt. Das ist ja genau der Unterschied zwischen diesen beiden Zeitpunkten in Sommer und Normalzeit. Sonst wären diese Zeitpunkte ja nicht voneinander zu unterscheiden.

    Leider wird durch die AddMinutes Anweisung in der Schleife aber nur genau eine Zeitinstanz mit 2:00 Uhr erzeugt. Bei einer LocalTime Zeitinstanz hätte ich eigentlich auch erwartet, dass die Uhrzeit automatisch wieder um 3:00 Uhr auf 2:00 Uhr zurückspringt.

    Grüße,

    Alex
    Samstag, 16. Januar 2010 09:55
  • Hallo Alex,

    bei einer lokalen Zeit kann man während der Zeitumstellung nicht feststellen,
    ob es nun 2.00A oder 2.00B Uhr ist.
    Das ist genauso, wenn Du nachts aufwachst und auf Deinen analogen Funkwecker guckst,
    dann weisst Du das auch nicht.

    Eine Addition in einer Schleife ändert daran nichts nichts.
    Dabei entsteht jeweils eine neue DateTime Instanz, die einen Zeitpunkt
    in einer Zeitzone repräsentiert.
    Dort ist kein "Gedächtnis" vorhanden, welche vorherige Zeit gegolten hat.

    Eine Anwendung, die unabhängig von Zeitzonen und Sommerzeiten
    funktionieren muß, sollte deswegen durchgängig mit UTC arbeiten
    Und für die Darstellung jeweils eine Umwandlung vornehmen.

    Mit DateTimeOffset gibt es dazu eine Klasse, die die Zeitzone verwaltet.
    Da bekämst Du die Unterschiede zu sehen:

                DateTimeOffset d = new DateTimeOffset(DateTime.SpecifyKind(Convert.ToDateTime("25.10.2009 01:00"), DateTimeKind.Local));
    
                for (int i = 0; i < 12; i++)
                {
                    d = d.AddMinutes(15);
                    Console.WriteLine(d.ToLocalTime().ToString());
                }
    
    Gruß Elmar

    Samstag, 16. Januar 2010 10:32
    Beantworter
  • Hallo Alex,

    mir scheint, Du verwechselst hier einen Zeitpunkt mit einer Uhr. Eine Uhr besitzt die Logik, um zu unterscheiden, ob der Zeitpunkt gerade in der Sommerzeit oder Normalzeit liegt. Beim Zeitpunkt ist das nicht möglich. Der DateTime Datentyp stellt immer einen Zeitpunkt dar, daher "springt" da auch nichts zurück. Das wäre sogar fatal, wenn das so wäre.

    Zum Thema Logik vielleicht noch deutlicher: Liegt folgender Zeitpunkt in der Sommer- oder in der Normalzeit?

    DateTime d = DateTime.SpecifyKind(Convert.ToDateTime("25.10.2009 02:00"), DateTimeKind.Local);



    Thorsten Dörfler
    Microsoft MVP Visual Basic
    Samstag, 16. Januar 2010 12:46
    Beantworter