Czas UTC a DateTime.Kind

time zones

Ostatnio pierwszy raz w życiu miałem okazję ustawiać nagłówki HTTP odnośnie cachowania. Pogłębiłem trochę temat i okazało się, że trzeba myśleć nie w kategoriach czasu lokalnego, tylko czasu uniwersalnego. Na nasze: zamiast DateTime.Now trzeba używać DateTime.UtcNow.

Wstęp: Przechowujesz datę i czas? Może warto w UTC?

DateTime ma właściwość Kind typu DateTimeKind:

public enum DateTimeKind
{
  Unspecified,
  Utc,
  Local,
}

GMT to dla naszych potrzeb to samo co UTC. Nasz czas lokalny to GMT + 1. Kod poniżej ilustruje różne zachowania związane z DateTime.Kind.

var now = DateTime.Now;
Console.WriteLine(now.Hour); // 18
Console.WriteLine(now.Kind); // Local

var utcNow = DateTime.UtcNow;
Console.WriteLine(utcNow.Hour); // 17
Console.WriteLine(utcNow.Kind); // Utc

var changedToUniversal = now.ToUniversalTime(); // checks Kind internally
Console.WriteLine(changedToUniversal.Hour); // 17
Console.WriteLine(changedToUniversal.Kind); // Utc

var myDate = new DateTime(2014, 3, 8, 18, 0, 0);
Console.WriteLine(myDate.Kind); // Unspecified

var myDateIsLocal = new DateTime(2014, 3, 8, 18, 0, 0, DateTimeKind.Local);
Console.WriteLine(myDateIsLocal.Kind); // Local

Gdy pewna metoda oczekuje czas uniwersalnego, może dzięki Kind wyciągnąć sobie ten czas nawet z daty w czasie lokalnym. Dzieję się tak na przykład podczas ustawiania nagłówków HTTP dla cachowania:

cache.SetExpires(DateTime.UtcNow); // calls ToUniversalTime() internally
cache.SetExpires(DateTime.Now); // calls ToUniversalTime() internally
// Now and UtcNow produce the same output

Zmiana czasu

Teraz mamy zimę (można się było domyślić patrząc na różnicę między godziną 18 a 17). Jeśli jednak mamy czas letni (można to sprawić przestawiajac czas w Windowsie) to output będzie:

var now = DateTime.Now;
Console.WriteLine(now.Hour); // 18
Console.WriteLine(now.Kind); // Local

var utcNow = DateTime.UtcNow;
Console.WriteLine(utcNow.Hour); // 16
Console.WriteLine(utcNow.Kind); // Utc

Wtedy różnica między UTC a lokalnym będzie wynosić 2 godziny. Podczas operacji zmiany czas zimowy->letni (czy w drugą strone) UtcNow będzie się liniowo zmieniać, natomiast Now przeskoczy sobie w nocy o godzinkę. W niektórych zastosowaniach operowanie czas lokalnym sprawi wiele problemów.

BTW przechodzenie na czas letni/zimowy w dziesiejszych czasach straciło sens i powoduje wymierne straty.

Reklamy
Ten wpis został opublikowany w kategorii Programowanie i oznaczony tagami , , , , . Dodaj zakładkę do bezpośredniego odnośnika.

3 odpowiedzi na „Czas UTC a DateTime.Kind

  1. Maciek pisze:

    DateTime.Now praktycznie nigdy nie ma sensu. Nawet jeśli mamy aplikacje która ten czas wyświetla tylko lokalnemu użytkownikowi (co eliminuje wszystkie webowe), to i tak lepiej wszystko liczyć na czasach utc, a przy wyświetlaniu zrobić ToLocal. Niezły post na ten temat: http://codeofmatt.com/2013/04/25/the-case-against-datetime-now/

  2. Pingback: DateTimeOffset zamiast DateTime | Show me the code

  3. Pingback: dotnetomaniak.pl

Możliwość komentowania jest wyłączona.