Umíme to s Delphi, 33. díl – rutiny pro obsluhu systémového data a času

V dnešním dílu seriálu se podíváme, jak v Delphi pracovat se systémovým datem a časem. Až uvidíte, kolik procedur a funkcí v této souvislosti Delphi přináší, budete možná překvapeni. Na závěr dílu vytvoříme aplikaci, která umožní změnit systémové datum. Tato aplikace využije komponentu Calendar, kterou jsme popsali před týdnem.
Kapitoly článku
Než společně vytvoříme slíbenou ukázkovou aplikaci demonstrující práci s komponentou Calendar (která byla podrobně popsána v minulém díle seriálu), uvedeme si několik málo informací o práci s datumem a časem.

V Delphi existuje jeden základní datový typ pro uchování datumu a času: typ TDateTime. Je deklarovaný v jednotce System (je tedy implicitně přístupný bez nutnosti přidávat tuto jednotku do sekce Uses). Pokud očekáváte, že TDateTime je nějaký „bláznivý záznam“, možná budete překvapeni, zjistíte-li, že TDateTime je „obyčejný“ double:

  type  TDateTime = type Double;

Představte si, že máte v některé proměnné typu TDateTime uložen například aktuální čas. Situace je pak taková, že celá část čísla označuje počet dní, které uplynuly od 30.12.1899. Desetinná část pak znamená poměrnou část dne (jaká část z 24 hodin uplynula od půlnoci). Příklady několika hodnot TDateTime:

Hodnota TDateTime Odpovídající datum a čas
0 30.12.1899 00:00
2.75 1.1.1900 18:00
-1.25 29.12.1899 06:00
35065 1.1.1996 00:00

Je tedy zřejmé, že potřebujeme-li najít počet dnů mezi dvěma datumy, jednoduše příslušné údaje odečteme, apod.

Poznámka pro pokročilé uživatele: Delphi 1.0 počítalo datum od roku 1 místo roku 1899. Potřebujete-li zkonvertovat datum z Delphi 1.0 do současného formátu , odečtěte od hodnoty datumu Delphi 1.0 číslo 693594,0. Tato hodnota je mimochodem definována v jednotce SysUtils celočíselnou konstantou DateDelta.

Nyní tedy víme, jak ukládá datum a čas Delphi. Delphi také přináší mnoho metod pracujících s údaji typu TDateTime. Nicméně občas potřebujeme pro práci s datumem a časem použít některou funkci Windows API (například v aplikaci z následujícího odstavce budeme nastavovat systémový čas pomocí funkce Windows API SetSystemTime). V takovém případě ovšem potřebujeme uchovávat čas ve formátu, který se „líbí“ Windows API. Tímto formátem je v Delphi typ TSystemTime. Dále je deklarován typ PSystemTime, což je ovšem jen ukazatel na TSystemTime.

Poznámka: Je-li v Delphi před názvem nějakého typu proměnné písmeno „P“ (např. zmíněné PSystemTime), je to znamení, že jde vždycky o ukazatel (pointer). Je to zaběhlá (a po všech stránkách dobrá!) konvence a snažte se ji dodržovat i v identifikátorech, které sami vytváříte. Na první pohled je pak zřejmé, že nejde o „normální“ datový objekt, ale jen ukazatel na určité místo v paměti.

Podíváme-li se na deklaraci typu TSystemTime, už spatříme zřejmě očekávaný záznam:

type
  TSystemTime = record

    wYear: Word;
    wMonth: Word;
    wDayOfWeek: Word;
    wDay: Word;
    wHour: Word;
    wMinute: Word;
    wSecond: Word;
    wMilliseconds: Word;
  end;

Nyní zbývá vyřešit otázku, jak v případě potřeby zkonvertovat hodnotu TDateTime na údaj typu TSystemTime a naopak. K tomu slouží dvě konverzní funkce (lépe řečeno jedna procedura a jedna funkce):

Funkce SystemTimeToDateTime Tato funkce s příšerným názvem (zkuste si to párkrát vyťukat na klávesnici:-)) konvertuje hodnotu TSystemTime na reprezentaci TDateTime (je to funkce, takže hodnotu TDateTime přímo vrací):

function SystemTimeToDateTime(const SystemTime: TSystemTime): TDateTime;

Procedura DateTimeToSystemTime Opak předchozí funkce, nicméně odlišnost spočívá v tom, že jde o proceduru, takže údaj TSystemTime vrací v parametru předaném odkazem:

procedure DateTimeToSystemTime(DateTime: TDateTime;
  var SystemTime: TSystemTime);

Nyní již víme, jak údaje mezi sebou převádět a můžeme se stručně podívat na několik metod, pomocí kterých získáváme a zpracováváme časové a datumové údaje (nečiním si nárok býti konkrétní, jedná se pouze o výběr těch, které jsou podle mě nejpoužitelnější. Chybí-li vám zde některá metoda, uveďte ji prosím do diskuse):

Metoda Procedura/

Funkce

Popis
Date Funkce Vrací aktuální systémové datum.
DateTimeToFileDate Funkce Konvertuje údaj typu TDateTime na údaj udávající datum a čas vytvoření souboru.
DateTimeToStr Funkce Konvertuje hodnotu TDateTime na řetězec.
DateTimeToString Funkce Konvertuje hodnotu TDateTime na řetězec s možností zadat formát řetězce (parametr Format). Zadávání formátu má mnoho možností, doporučuji prostudovat nápovědu.
DateTimeToSystemTime Procedura Konvertuje údaj TDateTime na údaj TSystemTime, viz popis nad tabulkou.
DateToStr Funkce Konvertuje datum z údaje typu TDateTime na řetězec.
DayOfWeek Funkce Vrací den v týdnu ze zadaného údaje typu TDateTime. Výsledkem je číslo mezi 1 (neděle) a 7 (sobota).
DecodeDate Procedura „Dekóduje“ údaj typu TDateTime a „rozkouskuje“ jej na rok, měsíc a den.
DecodeTime Procedura „Dekóduje“ údaj typu TDateTime a „rozkouskuje“ jej na hodiny, minuty, sekundy a milisekundy.
EncodeDate Funkce Ze zadaného dne, měsíce a roku „vyrobí“ údaj typu TDateTime.
EncodeTime Funkce Ze zadaných hodin, minut, sekund a milisekund „vyrobí“ údaj typu TDateTime.
FormatDateTime* Funkce Podle zadaného formátovacího řetězce konvertuje údaj TDateTime na řetězec. Výsledkem je řetězec v zadaném formátu. Formátovacích možností je celá řada, částečný popis naleznete pod tabulkou, pro podrobnosti však doporučuji prostudovat nápovědu.
IncMonth Funkce Přičte k zadanému datu (ve formátu TDateTime) zadaný počet měsíců a vrátí nové datum.
IsLeapYear Funkce Logická funkce zjišťující, zda zadaný rok (údaj typu Word) je přestupný.
Now Funkce Vrací aktuální systémové datum a čas.
ReplaceDate Procedura Proceduře je nutné předat dva údaje typu TDateTime. Výsledkem bude, že v prvním údaji se nahradí složka datumu údajem z druhého parametru. Je vhodná např. v okamžiku, kdy zjistíte čas funkcí Now a chcete změnit jen datum, nikoliv čas.
ReplaceTime Procedura Analogie s funkcí ReplaceDate, nahradí v zadaném údaji TDateTime složku času a datum ponechá.
StrToDate Funkce Konvertuje řetězec obsahující datum na údaj typu TDateTime. O možných formátech vstupního řetězce podrobně pojednává nápověda.
StrToDateTime Funkce Konvertuje řetězec obsahující datum a čas na údaj typu TDateTime. O možných formátech vstupního řetězce pojednává podrobně nápověda.
StrToTime Funkce Konvertuje řetězec obsahující čas na údaj typu TDateTime. O možných formátech vstupního řetězce pojednává podrobně nápověda.
SystemTimeToDateTime Funkce Konvertuje údaj typu TSystemTime na údaj TDateTime, podrobně viz popis nad tabulkou.
Time Funkce Vrací aktuální systémový čas.
TimeToStr Funkce Konvertuje čas z údaje typu TDateTime na řetězec.

V jednotce SysUtils jsou kromě vyjmenovaných metod definovány také tři užitečné konstanty:

Konstanta Význam
MSecsPerDay Udává počet milisekund za den (tedy 24 * 60 * 60 * 1000).
SecsPerDay Udává počet sekund za den (tedy 24 * 60 * 60).
DateDelta Udává počet dnů mezi 1.1.0001 a 31.12.1899 (tj. 693594).

Jednotka SysUtils dále obsahuje deklaraci mnoha proměnných, které souvisí s datumem a časem. Hodnoty těchto proměnných záleží zpravidla na nastavení systému a místních zvyklostí. Jednotka SysUtils obsahuje podobných proměnných celou řadu (nikoliv jen proměnných týkajících se datumu a času) a v některém z příštích dílů se podíváme i na zbývající.

Proměnná Typ Význam
DateSeparator Char Proměnná obsahuje znak, který se používá k oddělení jednotlivých částí datumu (den, měsíc, rok).
ShortDateFormat String Formátovací řetězec udávající, jak se bude zobrazovat datum v krátké formě vhodné k editaci. Používá se často ve spolupráci s funkcí FormatDateTime.
LongDateFormat String Formátovací řetězec udávající, jak se bude zobrazovat datum v delší formě vhodné k zobrazování, ale ne příliš k editaci. Používá se často ve spolupráci s funkcí FormatDateTime.
TimeSeparator Char Znak použitý k oddělování jednotlivých částí času (hodina, minuta, sekunda).
TimeAMString String Řetězec specifikující, jak se v daném kraji označuje dopoledne. Používá se především v angličtině – jistě znáte časový údaj typu 7.20AM. V českých podmínkách bývá obsahem této proměnné řetězec „dop.“, ale příliš často se nevyužívá.
TimePMStrin String Řetězec specifikující, jak se v daném kraji označuje odpoledne. Používá se především v angličtině – jistě znáte časový údaj typu 7.20PM. V českých podmínkách bývá obsahem této proměnné řetězec „odp.“, ale příliš často se nevyužívá.
ShortTimeFormat String Formátovací řetězec, který se používá k zobrazení času v krátké formě (jen hodiny a minuty).
LongTimeFormat String Formátovacíé řetězec, který se používá k zobrazení času v delší formě (hodiny, minuty, vteřiny).
ShortMonthNames Array [1..12] of String Pole řetězců obsahujících „krátké“ označení měsíců v roce. V českých podmínkách mívá často hodnoty římských čísel (tedy únor je II, apod.).
LongMonthNames Array [1..12] of String Pole řetězců obsahujících názvy měsíců v roce, např. LongMonthNames[2] = „únor“ – samozřejmě v českých podmínkách -, apod.
ShortDayNames Array [1..12] of String Pole řetězců obsahujících „krátké“ označení dnů v týdnu. V českých podmínkách např. ShortDayNames[2] = „po“, apod.
LongDayNames Array [1..12] of String Pole řetězců obsahujících názvy dnů v týdnu. V českých podmínkách např. LongDayNames[2] = „pondělí“, apod.

Pokud chcete vyzkoušet hodnotu některé proměnné na svém počítači, není nic snazšího, než si ji nechat „normálně“ vypsat, např:

  ShowMessage(LongDayNames[2]);

Musíte pouze zkontrolovat, že v sekci Uses příslušného modulu je uvedena jednotka SysUtils (a to ona určitě je:-)).

*FormatDateTime: tato funkce má tolik možností, že stojí za to věnovat jí samostatný odstaveček. Jak již řečeno, funkce konvertuje údaj typu TDateTime na řetězec podle zadaného formátovacího řetězce. Co je vlastně formátovací řetězec? Už jsme se s ním v některém z předchozích dílů setkali: je to speciální řetězec, který může obsahovat normální text, ale především specifikátory formátu. S jeho pomocí je tedy možné získat údaj o datumu a času takřka „jakkoliv“ – příklady: 25. 7. 2000, středa 23. května 1950 17:05, apod.

V následující tabulce uvedeme většinu formátovacích specifikátorů:

Specifikátor Význam Příklad výsledku
c Zobrazí datum ve formátu ShortDateFormat a čas ve formátu LongTimeFormat. 28.10.2001 16:11:47
d Zobrazí den jako číslo od 1 do 31. 5
dd Zobrazí den jako číslo od 01 do 31 (tedy vždy zobrazené na dvě místa). 05
ddd Zobrazí den jako zkratku podle proměnné ShortDayNames z jednotky SysUtils. po
dddd Zobrazí celý název dne podle proměnné LongDayName z jednotky SysUtils. pondělí
ddddd Zobrazí datum ve formátu ShortDateFormat z jednotky SysUtils. 28.10.2001
dddddd Zobrazí datum ve formátu LongDateFormat z jednotky SysUtils. 28. říjen 2001
… podobně pro měsíce (m, mm, mmm, mmmm)
… podobně pro roky (yy, yyyy)
… podobně pro hodiny, minuty a vteřiny (h, hh, n, nn, s, ss) – pozor pouze na to, že minuty se označují „n“, aby nedošlo ke kolizi s označením měsíců („m“)
… podobně pro milisekundy (z, zzz)
t Zobrazí čas ve formátu ShortTimeFormat z jednotky SysUtils 19:01
tt Zobrazí čas ve formátu LongTimeFormat z jednotky SysUtils 19:02:04
am/pm Spolupracuje se značkami h a hh. Napíšete-li např. „ham/pm“, zobrazí hodinu ve dvanáctihodinovém formátu a identifikátorem odpoledne/dopoledne. 7pm

Příklady: následující příklady ukazují, jak pracovat s funkcí FormatDateTime:

  ShowMessage(FormatDateTime(`c`, Now));
  ShowMessage(FormatDateTime(`dddddd`, Now));
  ShowMessage(FormatDateTime(`mm`, Now));
  ShowMessage(FormatDateTime(`hham/pm`, Now));

Poznámka: uvedete-li ve formátovacím řetězci nějaké znaky do uvozovek nebo apostrofů, budou zobrazeny tak, jak je uvedete a nebudou brány jako formátovací specifikátory.

Témata článku: , , , , , , , , , , , , , , , , , , , , , , , , ,