11. díl - Datum a čas v C#

C# .NET Objektově orientované programování Datum a čas v C# American English version English version

V minulém tutoriálu našeho seriálu o C# jsme si ukázali vlastnosti. Ty dnes budeme potřebovat, ukážeme si totiž, jak se v .NET pracuje s datem a časem.

DateTime

Pro práci s datem a časem slouží v .NET frameworku třída DateTime. Použijeme ji jako datový typ pro uložení data nebo času. Když se zamyslíme nad pojetím data a času, tak vše je v podstatě čas, uběhnutý od nějakého počátečního bodu. Proto Microsoft zvolil jeden společný typ pro datum i pro čas. Třída je poměrně chytrá a má mnoho užitečných vlastností a metod. My si je zde dnes ukážeme.

Vytvoření instance

Začněme tím, jak lze instanci DateTime vytvořit. Vytvoříme si projekt s názvem DatumACas. Nejprve si vytvoříme instanci pomocí bezparametrického konstruktoru:

DateTime datumCas = new DateTime();
Console.WriteLine(datumCas);
Console.ReadKey();

Výstupem programu bude něco takového:

1.1.0001 0:00:00

Nyní si ukažme 2 nezákladnější konstruktory, pomocí kterých můžeme instanci DateTime vytvořit.

Nejprve vytvořme samotné datum bez času (tedy přesněji čas se nebude nastavovat a zůstane 0:00:00). Specifikujeme rok, měsíc a den:

DateTime datumCas = new DateTime(2016, 7, 15);
Console.WriteLine(datumCas);

A výstup:

15.7.2016 0:00:00

Pokud si budeme přát zadat i datum i čas, můžeme čas připsat ve formátu:

DateTime datumCas = new DateTime(2016, 7, 15, 3, 15, 0);

Nyní je čas nastaven na 3:15 ráno.

Určitě je důležité vědět, jak se dostaneme k aktuálnímu datu a času. Slouží k tomu statická vlastnost Now, která nám vrátí instanci DateTime, nastavenou na současný čas. Voláme ji pochopitelně přímo na třídě. Čas v této instanci již neběží, když potřebujeme po nějaké době opět aktuální čas, musíme si vytvořit pomocí Now novou instanci. Pojďme si to zkusit:

DateTime datumCas = DateTime.Now;
Console.WriteLine("Dnes je: {0}", datumCas);
Console.ReadKey();

A výstup:

Aktuální datum a čas v C# .NET

Podobná je vlastnost Today, která vrátí aktuální datum a čas nastavený na 0:00:00.

Další vlastnosti

Jak již bylo řečeno, DateTime má mnoho vlastností, které slouží k přístupu k jednotlivým složkám data a času:

  • Day
  • Month
  • Year
  • Hour
  • Minute
  • Second
  • Millisecond

Můžeme se zeptat ještě na tzv. Ticks, ve kterých je datum a čas vlastně interně uložen. Jedná se o velmi vysoké číslo, jeden tick reprezentuje sto nanosekund, tedy desetimiliontinu vteřiny. Může se vám to někdy hodit pro velmi přesné výpočty.

Kromě složek nám .NET umožňuje zjistit:

  • DayOfWeek - Vrací den v týdnu v tzv. výčtovém typu, který si vysvětlíme v dalších dílech seriálu. Zatím si řekneme, že výstupní hodnotou může být např. DayOfWeek.Monday. Při výpisu se podle regionálního nastavení systému převede do stringu.
  • DayOfYear - Den v roce, tedy vrací hodnoty 1 - 366.

Z DateTime můžeme oddělit složku s časem a nastavit ho na 0:00:00, slouží k tomu vlastnost Date, která vrátí DateTime s původním datem a bez času. Může to být užitečné, když pracujeme s celými dny a čas by nám způsoboval nepřesnosti.

Vyzkoušejme si vlastnosti na dalším programu:

DateTime datumCas = DateTime.Now;
Console.WriteLine("Dnes je {0} {1}.", datumCas.DayOfWeek, datumCas.Day);
Console.WriteLine("Je {0}. měsíc a rok {1}.", datumCas.Month, datumCas.Year);
Console.WriteLine("{0} hodin, {1} minut a {2} sekund.", datumCas.Hour, datumCas.Minute, datumCas.Second);
Console.ReadKey();

Výsledek:

Aktuální datum a čas v C# .NET

Díky tomu, že mám anglický operační systém, C# vrací i anglická jména dní. Vy je budete mít česká. Toto je výhodné, protože se nemusíme starat o to, aby se každému zobrazily správně, dle jeho regionálního nastavení, C# to za nás udělá.

Metody

Nyní se podívejme na metody. Pozor, metody nemění instanci DateTime, ale vrací novou, ve které jsou dané změny provedeny!

Změna vnitřní hodnoty

S vnitřní hodnotou data a času můžeme velmi jednoduše manipulovat pomocí metod, které přidávají různé časové úseky. Jako parametr berou počet úseků (např. dní), které chceme přidat. Pokud je chceme naopak ubrat, použijeme zápornou hodnotu. Za účelem změny hodnoty tedy slouží metody:

  • AddDays()
  • AddMonths()
  • AddYears()
  • AddHours()
  • AddMinutes()
  • AddSecond()
  • AddMilliseconds()
  • AddTicks()

Můžeme se zeptat, zda je daná instance DateTime ve formátu letního času:

  • IsDaylightSavin­gTime()
Statické metody

Samotná třída má na sobě také statické metody:

  • DaysInMonth() - Statická metoda vracející počet dní v zadaném měsíci. Parametry jsou je rok a měsíc (rok proto, že mohl být přestupný únor).
  • IsLeapYear() - Vrací true pro přestupný rok, parametrem je rok.
Parsování a převod na text

Asi se nám bude často stávat, že budeme chtít po uživateli zadat nějaké datum, případně i čas. DateTime má pro tyto účely jak metodu Parse(), tak i TryParse().

V nejjednodušší podobě načteme datum a čas takto:

DateTime datum = DateTime.Parse(Console.ReadLine());

Formát data a času potom závisí na regionálním nastavení, většinou se očekává např. 1.1.2012 13:00. Když nezadáme čas, nic se nestane, jen tam bude 0:00:00.

Když chceme zadávaný formát ovlivnit, použijeme k tomu tzv. pattern. Ten může mít např. následující podobu:

string pattern = "dd.M.yyyy";

Tabulka těchto hodnot je poněkud vyčerpávající, zájemce odkáži na oficiální dokumentaci, kde jsou vysvětleny jednotlivé složky patternu: http://msdn.microsoft.com/…kb3ddd4.aspx

K parsování poté použijeme metodu ParseExact() a předáme jí náš pattern takto:

DateTime datum = DateTime.ParseExact(Console.ReadLine(), pattern, null);

I ta má samozřejmě podobnou metodu TryParseExact.

Nyní se podívejme na převod data do textu, ten nám bude užitečný zejména při výpisu data.

Samozřejmě funguje metoda ToString(), která je bez parametrů a C# ji volá implicitně.

Metodě můžeme dát jako parametr pattern, aby vrátila datum v námi požadovaném formátu:

datumCas.ToString("MMMM dd, yyyy");

Předpřipravené máme dva 4 formáty, 2 pro výpis jen data a 2 pro výpis jen času. Vypisovat můžeme v dlouhém nebo krátkém formátu:

  • ToShortDateStrin­g()
  • ToShorTimeStrin­g()
  • ToLongDateStrin­g()
  • ToLongTimeStrin­g()

Data i čas můžeme běžně porovnávat pomocí operátorů > < == (interně je to vlastně velmi vysoké číslo s počtem ticks, data je tedy velmi jednoduché porovnávat).

Určitě se podívejte na cvičení k této lekci, obsahuje několik důležitých úloh na nejčastější operace s datem a časem.

Pozn. Jak jistě víte, čas může být vyjádřen jako lokální (tak, jak je v naší časové zóně) nebo jako mezinárodní (tzv. formát UTC). Tutoriál nepředpokládá práci s mezinárodním časem. Pokud si budete přát zjistit aktuální čas v UTC, použijte statickou vlastnost UtcNow. Jakého typu je hodnota v DateTime se můžeme zeptat pomocí vlastnosti Kind. Pro vytvoření DateTime v UTC použijeme konstruktor jako se zadáním času, avšak zadáme i další parametr s kind. Typ DateTime můžeme změnit pomocí statické metody SpecifyKind(). Zatím se tím zde nebudeme zabývat, jen jsem chtěl navést případné zájemce na správné metody. Mezi těmito dvěma časy můžeme také převádět pomocí metod ToLocalTime() a ToUniversalTime().

TimeSpan

S DateTime souvisí ještě TimeSpan. Ten slouží k uchovávání rozdílu mezi dvěma daty. Rozdíl oproti DateTime je v tom, že DateTime reprezentuje celé datum, TimeSpan reprezentuje pouze nějaký interval (ať už jsou to roky nebo vteřiny).

Na DateTime existuje vlastnost TimeOfDay, která vrátí TimeSpan s časem a datum zahodí.

TimeSpan vznikne, když odečteme 2 DateTime. Můžeme také TimeSpan k DateTime přičíst pomocí metody Add() na instanci DateTime.

Vlastnosti

K jednotlivým složkám TimeSpanu se dostaneme pomocí vlastností (stejně, jako u DateTime, pouze jsou v množném čísle):

  • Days
  • Hours
  • Minutes
  • Seconds
  • Milliseconds
  • Ticks

Pokud chceme celý interval vyjádřit v jedné jednotce, použijeme vlastnosti předsazené "Total". Na rozdíl od výše uvedených vrací double, nikoli int:

  • TotalDays
  • TotalHours
  • TotalMinutes
  • TotalSeconds
  • TotalMilliseconds

Metody

TimeSpan má několik konstruktorů, ukážeme si dva nejzákladnější:

TimeSpan ts = new TimeSpan(hodiny, minuty, sekundy);
TimeSpan ts = new TimeSpan(dny, hodiny, minuty, sekundy);

Metody jsou podobné, jako na třídě DateTime, opět tu máme metodu Add(), která přidá k TimeSpanu další TimeSpan. TimeSpan můžeme vytvořit statickými metodami z intervalu v různých jednotkách:

  • FromDays()
  • FromHours()
  • FromMinutes()
  • FromSeconds()
  • FromMillisecon­ds()

Pro Parse() a ToString() platí to samé, jako pro DateTime.

Pojďme si udělat ještě jeden příklad. Zeptáme se uživatele na jeho datum narození a z toho vypočítáme jeho věk. Řekneme mu i, kolik mu je dní a hodin. Výpočet věku uděláme zjednodušený. TimeSpan bohužel neposkytuje zjištění let (kvůli tomu, že rok má vždy jiný počet dní), dostaneme se pouze k počtu dní v intervalu. Dny vydělíme 365.255 a zaokrouhlíme dolů. Pro nepatrné množství dat narození to nemusí fungovat, ale to nás nyní příliš nezatěžuje, jen si chceme TimeSpan vyzkoušet:

Console.WriteLine("Zadej datum narození: ");
DateTime narozen = DateTime.Parse(Console.ReadLine());
TimeSpan vek = DateTime.Today - narozen;
Console.WriteLine("Je ti {0} let", Math.Floor(vek.Days/365.255));
Console.WriteLine("To je ve dnech {0} a v hodinách {1}", vek.TotalDays, vek.TotalHours);
Console.ReadKey();
Spočítání věku v C# .NET

Všimněte si, že TimeSpan vznikne opravdu pouhým odečtením dvou DateTime. Až budeme zas někdy tvořit objekty uživatelů, budeme u nich ukládat místo věku datum narození. Z něj poté dokážeme věk jednoduše spočítat a tak bude stále aktuální. Můžete si to zkusit.

Příště si ukážeme kolekci, do které lze narozdíl od pole jednoduše přidávat a odebírat záznamy. Vytvoříme si jednoduchou databázi.


 

Stáhnout

Staženo 660x (61.88 kB)
Aplikace je včetně zdrojových kódů v jazyce C#

 

  Aktivity (3)

Článek pro vás napsal David Čápka
Avatar
Autor pracuje jako softwarový architekt a pedagog na projektu ITnetwork.cz (a jeho zahraničních verzích). Velmi si váží svobody podnikání v naší zemi a věří, že když se člověk neštítí práce, tak dokáže úplně cokoli.
Unicorn College Autor se informační technologie naučil na Unicorn College - prestižní soukromé vysoké škole IT a ekonomie.

Jak se ti líbí článek?
Celkem (14 hlasů) :
4.428574.428574.428574.42857 4.42857


 


Miniatura
Předchozí článek
Vlastnosti
Miniatura
Následující článek
Cvičení k 11. lekci OOP v C# .NET

 

 

Komentáře
Zobrazit starší komentáře (30)

Avatar
Milan Křepelka
Redaktor
Avatar
Milan Křepelka:

Obecně to není moc dobrý nápad jak to tady šíříte. Jednou je to kvůli tečkám, tak to překlopíte vlákno na anglický a pak doporučíte kvůli datumům překlápět na český vlákno. Jak vidíte, jako univerzální návod na všechno je to na houbelec.

 
Odpovědět 2.10.2015 14:03
Avatar
patrik.valkovic
Šéfredaktor
Avatar
Odpovídá na Milan Křepelka
patrik.valkovic:

Samozřejmě, protože máme jiný formát.
V jednom případě je vstupní i výstupní formát formátu anglického (tedy desetinné tečka místo čárky) - tedy veškerá komunikace probíhá v anglickém formátu.
V tomto případě zase chceme výstup český. Z toho jsem pochopil, že chce celý výstup v českém prostředí (včetně desetinných čárek, které se u nás využívají).
Pokud se jedná pouze o část programu, samozřejmě nemůže změnit CultureInfo celého vlákna, ale v případě, kdy se jedná o celou aplikaci, nevidím v tom problém.

Odpovědět 2.10.2015 14:23
Nikdy neumíme dost na to, abychom se nemohli něco nového naučit.
Avatar
Michal Gros
Redaktor
Avatar
Michal Gros :

Dobrý den, tak to bohužel nefunguje dal jsem

class TestCeskyDenVTydnu
{
    static private DateTime datumCas = DateTime.Now;

    public static void zobrazimeCeskyDen()
    {
        Console.WriteLine("aktualni nastaveni jazyka - default :" + CultureInfo.CurrentCulture.TextInfo);
        Console.WriteLine("Dnes je {0}.", datumCas.DayOfWeek);
        Thread.CurrentThread.CurrentCulture = new CultureInfo("en-EN");
        Console.WriteLine("aktualni nastaveni jazyka:"+ CultureInfo.CurrentCulture.TextInfo);
        Console.WriteLine("Dnes je {0}.", datumCas.DayOfWeek);
        Thread.CurrentThread.CurrentCulture =  new CultureInfo("cs-CZ");
        Console.WriteLine("aktualni nastaveni jazyka:" +  CultureInfo.CurrentCulture.TextInfo);
        Console.WriteLine("Dnes je {0}.", datumCas.DayOfWeek);
    }
}

Tusime kde je chyba

Odpovědět 3.10.2015 10:50
Jestli jste dobří nahrnou na Vás spoustu práce. Jestli jste sakra dobří, tak se jí dokážete zbavit.
Avatar
patrik.valkovic
Šéfredaktor
Avatar
Odpovídá na Michal Gros
patrik.valkovic:

https://msdn.microsoft.com/….110%29.aspx

...it does not reflect a system's regional and language settings. To retrieve a string representing a localized weekday name for a particular date, call one of the overloads of the ToString...

Musíš využít přetížení metody ToString, DayOfWeek nastavení nereflekutje.

datumCas.ToString(dddd);
Odpovědět 3.10.2015 11:02
Nikdy neumíme dost na to, abychom se nemohli něco nového naučit.
Avatar
Milan Křepelka
Redaktor
Avatar
Milan Křepelka:

To je dobrá pastička. Řešením je tohle.

DateTimeForma­tInfo.CurrentIn­fo.GetDayName(da­tumCas.DayOfWe­ek)

 
Odpovědět  +2 3.10.2015 11:15
Avatar
Michal Gros
Redaktor
Avatar
Odpovídá na patrik.valkovic
Michal Gros :

jo jo - to jsem našel viz kód výše

Odpovědět 4.10.2015 12:44
Jestli jste dobří nahrnou na Vás spoustu práce. Jestli jste sakra dobří, tak se jí dokážete zbavit.
Avatar
David Novák
Člen
Avatar
David Novák:

Ošetření uživatelského vstupu pomocí while cyklu u parsování uživatelem vkládaného Data
Ahojte,

Prosím o radu jak doplnit další povinné parametry v závorce abych mohl ošetřit uživatelský vstup takto:(tímto způsobem ošetřuju všechny uživatelské vstupy číselných hodnot, chtěl jsem to použít i zde):

static void Main()
{
string pattern = "dd.M.yyyy";Da­teTime datum;
while (!DateTime.Try­ParseExact(Con­sole.ReadLine(),pat­tern,out datum))
Console.Write­Line(datum);
}

Hlásí mi to chybějící parametry - viz příloha nápověda Visual Studia, kterou jsem žel nepochopil.
V kurzu je pouze tento příklad (viz níže)

string pattern = "dd.M.yyyy";
DateTime datum = DateTime.Parse­Exact(Console­.ReadLine(), pattern, null);
Console.Write­Line(datum);
který funguje ale neošetřuje vstupy. V úkolech ke kapitole je parsování, ale žel bez ošetření uživatelského vstupu :-(. Předem děkuji, David

 
Odpovědět 19. ledna 7:18
Avatar
Petr Stastny
Redaktor
Avatar
Petr Stastny:

Ahoj, mám problém. Programuji jednu aplikaci a tam načítám různé časy z souborů. (string ve formátu HH:mm). Tohle převádím na DateTime, kde tomu přičtu čas a poté to převedu kvůli porovnání na TimeSpan. A tohle mi vyšlo:

http://prntscr.com/b5786n

Pro přehled, tohle jsou počáteční hodnoty

17:00=;19:35=;19:50=;20:10=;23:00=

Používám tento kód:

TimeSpan CasTedka = TimeSpan.Parse(DateTime.Now.ToString("HH:mm"));
                            TimeSpan CasHodiny = TimeSpan.Parse(DateTime.Parse(LajnVSouboru.Split('=')[0]).AddHours(1).ToString("HH:mm"));
                            TimeSpan CasDesetMinut = TimeSpan.Parse(DateTime.Parse(LajnVSouboru.Split('=')[0]).AddMinutes(10).ToString("HH:mm"));
                            TimeSpan CasDveMinuty = TimeSpan.Parse(DateTime.Parse(LajnVSouboru.Split('=')[0]).AddMinutes(2).ToString("HH:mm"));
                            Console.WriteLine(CasHodiny + CasDesetMinut + CasDveMinuty + CasTedka);

Tedy ideálně, aby vyšlo
18:00 (1. cas + 1h)
17:10 (1. cas + 10min)
17:02 (1. cas + 2min)
19:50 (muj aktualni cas)

Jak to mám jednoduše udělat? Mám vůbec používát ten TimeSpan? Jediné, co potřebuji, je to dostat čas ve formátu HH:mm (třeba 21:04) a to porovnávat v podmínce (pomocí >, <).

Editováno 17. května 19:51
 
Odpovědět 17. května 19:49
Avatar
jozef_i
Člen
Avatar
jozef_i:

Ja by som to nehal ako DateTime a na ten by som aplikoval metódu ToShortTimeStrin­g().
Potom máš výstup napr. 8:49

 
Odpovědět 18. května 8:54
Avatar
David Javůrek:

Můžete mi někdo vysvětlit, proč když napíšu

datumCas.DayOfWeek

vrátí se mi den týdnu v angličtině (přitom vše ostatní je v češtině)?
Do kódu jsem zkusil přidat

Thread.CurrentThread.CurrentCulture =  new CultureInfo("cs-CZ");

a vůbec to nepomohlo. Až zápis

DateTimeFormatInfo.CurrentInfo.GetDayName(datumCas.DayOfWeek)

funguje, ale nerozumím tomu.
Děkuji za radu.

 
Odpovědět 10. července 23:02
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 10 zpráv z 40. Zobrazit vše