Artykuł

freeimages.com freeimages.com
paź 04 2014
0

Czas w .Net cz. 3 - Czas a baza danych

Witajcie w kolejnym i zarazem ostatnim odcinku cyklu poświęconego opowieściom o czasie. W poprzednich dwóch, opowiedziałem Wam o trzech istotnych klasach występujących w .Net, które są powiązane z tym tematem. Jak pokazały oba wpisy, każda z nich ma swoje miejsce. I wszystko byłoby naprawdę w porządku, gdyby nie bazy danych...

Bazy danych zmieniają sporo, ponieważ niektóre właściwości obiektów nie przenoszą się do bazy danych, mimo tego że w bazie SQL od Microsoftu, istnieją typy o identycznych nazwach. Jak sobie zatem z tym poradzić? Wszystko zależy od tego, czy naszą aplikację kierujemy do użytkowników globalnych, czy też będzie ona dostępna w jednej, wybranej strefie czasowej. Nie mniej jednak opcji jest kilka;-)

Typ DateTime

O klasie DateTime mówiłem sporo w pierwszym odcinku cyklu, gdzie przedstawiłem wady i zalety tego rozwiązania. Klasa DateTime ma swój korespondencyjny typ również w bazie danych. Niestety w tym przypadku tracimy część informacji - przede wszystkim właściwość Kind. Innymi słowy sami musimy zatroszczyć się oto co pójdzie do bazy danych.

Jak pamiętacie właściwość Kind ma 3 możliwe wartości:

  • Utc
  • Local
  • Unspecified

Oczywiście nietrudno się domyślić, że najlepiej trzymać się pierwszego formatu, ponieważ później czas można łatwo skonwertować do interesującej nas strefy czasowej i nie musimy się domyślać w jakim formacie została wcześniej zapisana data (o tym jak pracować ze strefami czasowymi pisałem w drugiej części cyklu).

Oprócz tego że musimy dbać oto w jaki sposób zapisywana jest data, to w większości rozwiązań typu ORM, musimy również zwrócić uwagę na zwrócony rodzaj, który domyślnie określany jest na Unspecified, a my przecież potrzebujemy UTC. Co zrobić w takim przypadku? Można spróbować zastosować poniższy kod*:

DateTime dtUns = new DateTime(2014, 09, 14, 15, 0, 0);
// 2014-09-14 15:00:00 (UTC)
DateTime dtUtc = DateTime.SpecifyKind(dtUns, DateTimeKind.Utc);

Dzięki temu zostanie utworzony nowy obiekt, z tą samą wartością czasu i daty, ale z nową wartością właściwości Kind ustawioną na UTC.

Posiadając datę w formacie UTC, łatwo możemy ją skonwertować do czasu lokalnego, bądź też do czasu w wybranej strefie czasowej.

* Pracując z Entity Frameworkiem warto pokusić się o zastosowanie rozwiązania przedstawionego na StackOverflow.

Typ DateTimeOffset

Klasa DateTimeOffset po raz pierwszy pojawiła się w .Net Frameworku w wersji 3.5 i od razu powstał też korespondencyjny dla niej typ w bazie danych (od wersji 2008). Był to bardzo dobry ruch ze strony Microsoftu, ponieważ dzięki temu praca z czasem stała się dużo prostsza.

Tak jak pisałem wcześniej, typ DateTimeOffset uwzględnia przesunięcie do strefy czasowej UTC. Dzięki temu niezależnie od tego w jaki sposób data zostanie zapisana, my nie utracimy istotnych informacji, tak jak miało to miejsce w przypadku zapisu obiektu DateTime do bazy danych.

Co wybrać?

Wszystko zależy od przeznaczenia naszej aplikacji. Spójrzcie na poniższe warianty:

  • Aplikacja z bazą danych działająca lokalnie - w obrębie komputera/sieci firmowej - w takim przypadku można zastosować zarówno wariant z DateTime (Utc i Local - należy pamiętać o określaniu rodzaju) oraz DateTimeOffset. W takiej sytuacji strefy czasowe praktycznie nie mają znaczenia, dlatego nie ma konieczności wykorzystywania klasy TimeZoneInfo
  • Aplikacja międzynarodowa wykorzystująca czas użytkownika - w takim przypadku najlepiej skorzystać z typu DateTimeOffset. Aczkolwiek warto tutaj zwrócić uwagę. W przypadku gdy mamy do czynienia ze stroną WWW, nie możemy zaufać właściwościom typu DateTime.Now/DateTimeOffset.Now, ponieważ zwrócą one czas lokalny, ale będzie to czas serwera... Konieczne może być tutaj wykorzystanie JavaScriptu, który zawsze działa po stronie klienta
  • Aplikacja międzynarodowa wykorzystująca informacje o strefie czasowej. Mój ulubiony wariant. Pozwalamy użytkownikowi na wybór jego strefy czasowej, a następnie zapisujemy tę informację np. w profilu. Teraz w bazie można zapisać zarówno typ DateTime (koniecznie sprowadzony do czasu UTC!) jak i DateTimeOffset

Jak widać możliwości jest sporo, aczkolwiek widać że zdecydowanym liderem jest typ DateTimeOffset, który sprawdzić się może w praktycznie każdym rozwiązaniu. Oczywiście warto pamiętać że jest on odrobinę bardziej złożony od obiektu typu DateTime.

Podsumowanie

Przyszła na pora na krótkie podsumowanie cyklu o czasie w .Net. Na przestrzeni ostatnich 3 tygodni, starałem się Wam przekazać podstawową wiedzę związaną z klasami odpowiedzialnymi za przechowywanie daty i czasu w Microsoftowym Frameworku. Dopełnieniem tego materiału były informacje o tym, jak zapisywać czas w bazie danych. W końcu duża liczba aplikacji dąży do zapisywania czasu w bazie danych, prawda;-)?

Jeśli macie jakieś pytania/uwagi/zastrzeżenia, to zapraszam do komentarzy poniżej;-)

Cykl

Podoba Ci się ten wpis? Powiedz o tym innym!

Send to Kindle

Komentarze

blog comments powered by Disqus