DateTimeOffset v .NET Frameworku

3. díl - DateTimeOffset v .NET Frameworku

Tomáš Jecha, MVP, MCSD       26.06.2012       C#, VB.NET, .NET       12168 zobrazení

DateTimeOffset je méně využívanou alternativou struktury DateTime v .NET Frameworku. Navíc dovoluje ukládat časové pásmo a pohodlně s ním pracovat.

Pokud jste nikdy nepotřebovali pracovat s časovými pásmy, pravděpodobně jste nepoužili ani datový typ DateTimeOffset. Jeho použití je velmi podobné typu DateTime. Také uchovává čas a datum, je možné ho porovnávat, přičítat časové úseky, zjistit den v týdnu a podobně.

Základním rozdílem je přítomnost vlastnosti Offset (typ TimeSpan) nesoucí údaj o časové zóně ve které byl tento čas zaznamenán. Ve zkratce – do DateTimeOffset lze krom data a času uložit také časovou zónu.

Podívejte se na textovou reprezentaci hodnot DateTimeOffset.Now a DateTimeOffset.UtcNow vracející při textovém výpisu i příslušnou časovou zónu (“+02:00” znamená “UTC+2” a “+00:00” znamená “UTC”):

// vrací například: 22.6.2012 15:27:02 +02:00
Console.WriteLine(DateTimeOffset.Now);

// vrací například: 22.6.2012 13:27:02 +00:00
Console.WriteLine(DateTimeOffset.UtcNow);

Obě vlastnosti mají stejný význam jako stejně pojmenované vlastnosti u struktury DateTime (viz předchozí díl seriálu). Navíc však získáváme v hodnotě uloženou časovou zónu a díky tomu lze snadno zkonvertovat do UTC, ať už byla vytvořena v rámci jakékoliv zóny. A zároveň známe původní lokální čas. To je mimochodem i důvod, proč DateTimeOffset na rozdíl od DateTime nemá vlastnost Kind – k ničemu by nebyla. Jestli se totiž jedná o UTC nebo lokální čas určuje časová zóna. Ve skutečnosti máme ještě více možností, protože lze uchovávat časy i pro jiné časové zóny, než je jen lokální a UTC.

Je dobré si uvědomit, že DateTimeOffset uchovává pouze časovou zónu, nikoliv pravidla pro letní čas a proto musíme případný letní čas do vlastnosti Offset přímo zahrnout. Toto za nás naštěstí automaticky zařídí “DateTimeOffset.Now”, jenž respektuje nastavení zóny v systému. Pro Českou Republiku vrací tedy během letního času OffsetUTC+2” a mimo letní čas “UTC+1”.

Dostupné funkce a vlastnosti

Krom již probírané vlastnosti Offset existuje nad strukturou DateTimeOffset řada konverzních metod. Jsou to především následující:

var now = DateTimeOffset.Now;

// Vrací například: 22.6.2012 16:00:39 +02:00
Console.WriteLine(now);

// Vrací například: 22.6.2012 16:00:39 +02:00
Console.WriteLine(now.ToLocalTime());

// Vrací například: 22.6.2012 14:00:39 +00:00
Console.WriteLine(now.ToUniversalTime());

// Vrací například: 22.6.2012 15:00:39 +01:00
Console.WriteLine(now.ToOffset(TimeSpan.FromHours(1)));
  • Metoda ToLocalTime() vrací DateTimeOffset převedený na lokální časové pásmo. V příkladu je výsledek stejný jako vstupní hodnota, protože ta lokální časové pásmo UTC+2 má již nastavené.
  • Metoda ToUniversalTime() vrací DateTimeOffset převedený na UTC+0 časové pásmo. Zde se v příkladu čas posunuje o 2 hodiny dozadu a vyrovnává se tím tak časové pásmo z UTC+2 na UTC+0.
  • Metoda ToOffsetTime(TimeSpan) vrací DateTimeOffset převedený na časové pásmo určené parametrem. V příkladu na pásmo UTC+1, protože předávám 1 hodinu.

Dále je možné použít metody pro získání DateTime hodnoty v lokálním časovém pásmu nebo UTC. Jejich použití demonstruje další příklad.

var now = DateTimeOffset.Now;

// Vrací například: 22.6.2012 16:00:39
Console.WriteLine(now.LocalDateTime);

// Vrací například: 22.6.2012 14:00:39
Console.WriteLine(now.UtcDateTime);

Porovnávání

Při porovnávání bere DateTimeOffset v potaz také časové pásmo. Díky tomu lze relevantně porovnat dvě data v různých pásmech bez nutnosti konvertovat na stejné UTC. Následující kód to dokazuje. Obě data představují stejný datum a čas, pouze se liší v časové zóně.

var date1 = new DateTimeOffset(2012, 6, 22, 18, 0, 0, TimeSpan.FromHours(2));
var date2 = new DateTimeOffset(2012, 6, 22, 16, 0, 0, TimeSpan.FromHours(0));

// 22.6.2012 18:00:00 +02:00
Console.WriteLine(date1);

// 22.6.2012 16:00:00 +00:00
Console.WriteLine(date2);

// vrací True, časy jsou stejné i když pořízené v jiných pásmech
Console.WriteLine(date1 == date2);

Stejně tak snadno můžete zjišťovat rozdíl časů v různých pásmech. Příklad ukazuje, jak snadno zjistit rozdíl mezi časem 9:30:00 UTC-7 a 18:00:00 UTC+2. Z výsledku je patrné, že DateTimeOffset bere v potaz časová pásma a není tedy potřeba dopředu provádět konverzi například na UTC.

var date1 = new DateTimeOffset(2012, 6, 22, 18, 0, 0, TimeSpan.FromHours(2));
var date2 = new DateTimeOffset(2012, 6, 22, 9, 30, 0, TimeSpan.FromHours(-7));

// výsledek odečítání DateTimeOffset je TimeSpan s časovým údajem rozdílu
TimeSpan delta = date2 - date1;

// 0:30:00 - skutečný časový rozdíl je jen 30 minut
Console.WriteLine(delta);

Využití DateTimeOffset

Důvodů pro využití DateTimeOffset je obecně podstatně méně, než pro obyčejný DateTime. Obvykle jej využíváme v globálních aplikacích na údaje, kde nás zajímá přesný lokální čas, ale zároveň chceme mít možnost porovnávat záznam s daty i z jiných časových zón.

Cvičení

Pokud si chcete procvičit použití DateTimeOffset, zkuste vypracovat následující úlohu.

Úvod: Získáváte pole hodnot DateTimeOffset s hodnotami časů s různými časovými pásmy. Všechny tyto časy spadají do minulosti. Proveďte nad nimi následující operace:

Zadání 1: Zjistěte, kolik minut zbývá do “2012-7-1 00:00:00 UTC+0” nejnovějšímu záznamu v poli.

Zadání 2: Vytvořte z pole nové pole obsahující hodnoty DateTime s časy převedenými do lokální časové zóny.

Zadání 3: Zjistěte procentuální rozložení časů v poli podle denní doby na jednotlivé hodiny. Denní dobou se myslí aktuální čas záznamu podle jeho časového pásma.

Vstupní data (C#):

var data = new DateTimeOffset[]
{
    new DateTimeOffset(2012, 6, 15, 3, 0, 0, TimeSpan.FromHours(1)),
    new DateTimeOffset(2012, 6, 17, 6, 0, 0, TimeSpan.FromHours(1)),
    new DateTimeOffset(2012, 6, 18, 8, 0, 0, TimeSpan.FromHours(1)),
    new DateTimeOffset(2012, 6, 20, 9, 0, 0, TimeSpan.FromHours(1)),
    new DateTimeOffset(2012, 6, 20, 9, 30, 0, TimeSpan.FromHours(1)),
    new DateTimeOffset(2012, 6, 11, 8, 45, 0, TimeSpan.FromHours(2)),
    new DateTimeOffset(2012, 6, 8, 10, 30, 0, TimeSpan.FromHours(1)),
    new DateTimeOffset(2012, 6, 6, 18, 0, 0, TimeSpan.FromHours(1)),
    new DateTimeOffset(2012, 6, 8, 22, 0, 0, TimeSpan.FromHours(1)),
    new DateTimeOffset(2012, 6, 12, 18, 0, 0, TimeSpan.FromHours(-7)),
    new DateTimeOffset(2012, 6, 7, 5, 0, 0, TimeSpan.FromHours(-7)),
    new DateTimeOffset(2012, 6, 15, 12, 0, 0, TimeSpan.FromHours(-7)),
    new DateTimeOffset(2012, 6, 20, 8, 45, 0, TimeSpan.FromHours(-7)),
    new DateTimeOffset(2012, 6, 21, 9, 47, 0, TimeSpan.FromHours(-8))
};

Řešení cvičení

Řešení zveřejním za několik dnů. Pokud máte zájem porovnat výsledek, pošlete mi email s kódem (stačí textově, neposílejte celé projekty) a výstupem na: tomas [zavinuté-á] jecha.net

Do komentářů přidávejte otázky ke článku, nikoliv odpovědi na cvičení.

 

hodnocení článku

1 bodů / 1 hlasů       Hodnotit mohou jen registrované uživatelé.

 

Všechny díly tohoto seriálu

3. DateTimeOffset v .NET Frameworku 26.06.2012
2. DateTime v .NET Frameworku 24.06.2012
1. Úvod do časových pásem a letního času 22.06.2012

 

Mohlo by vás také zajímat

Jednoduchý scheduler v .NETu

Asi to znáte – máte nějaký složitější systém na zpracování velkého objemu dat a čas od času potřebujete vykovat nějakou automatizovanou údržbu – typicky smazat všechny položky starší než několika dní. Možností, jak toho dosáhnout, je hodně. Snažil jsem se vymyslet něco jednoduchého a efektivního.

Visual Studio 2017 je venku!

Integrační testy v ASP.NET Core pro REST API

 

 

Nový příspěvek

 

                       
Nadpis:
Antispam: Komu se občas házejí perly?
Příspěvek bude publikován pod identitou   anonym.

Nyní zakládáte pod článkem nové diskusní vlákno.
Pokud chcete reagovat na jiný příspěvek, klikněte na tlačítko "Odpovědět" u některého diskusního příspěvku.

Nyní odpovídáte na příspěvek pod článkem. Nebo chcete raději založit nové vlákno?

 

  • Administrátoři si vyhrazují právo komentáře upravovat či mazat bez udání důvodu.
    Mazány budou zejména komentáře obsahující vulgarity nebo porušující pravidla publikování.
  • Pokud nejste zaregistrováni, Vaše IP adresa bude zveřejněna. Pokud s tímto nesouhlasíte, příspěvek neodesílejte.

přihlásit pomocí externího účtu

přihlásit pomocí jména a hesla

Uživatel:
Heslo:

zapomenuté heslo

 

založit nový uživatelský účet

zaregistrujte se

 
zavřít

Nahlásit spam

Opravdu chcete tento příspěvek nahlásit pro porušování pravidel fóra?

Nahlásit Zrušit

Chyba

zavřít

feedback