11. díl - Datum a čas v Javě pomocí třídy Calendar

Java Objektově orientované programování Datum a čas v Javě pomocí třídy Calendar

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

Upozornění: Od Javy 8 je k dispozici nové API pro práci s časem. Více se o něm dočtete v našem článku.

Calendar

S datem a časem se v Javě dříve pracovalo pomocí třídy Date. Ta však byla označena za zastaralou a nyní se využívá třída Calendar. Pokud se v nějakých meteriálech setkáte s třídou Date, nepoužívejte ji. Název může Calendar může být poněkud matoucí, jedná se v podstatě o kalendář v paměti počítače, který si nastavíme na určitý datum a čas. Tímto způsobem se v Javě datum a čas ukládá. kalendář vždy obsahuje i čas, ten můžeme a nemusíme používat (např. ho nebudeme ani zadávat ani vypisovat, ale fyzicky tam bude přítomný).

Vytvoření instance s aktuálním datem a časem

Začněme tím, jak lze instanci Calendar vytvořit. Vytvoříme si projekt s názvem DatumACas. Do balíčku si přidáme import java.util.Calendar. V Javě je to s datem a časem trochu zamotané. Když chceme vytvořit novou instanci kalendáře, zavoláme na třídě Calendar statickou metodu getInstance():

Calendar kalendar = Calendar.getInstance();

Nyní naše proměnná kalendar obsahuje kalendář, nastavený na aktuální datum a čas. Pojďme si ho vypsat. Pokud napíšeme:

System.out.println(kalendar);

Vypíše se pouze ošklivá textová reprezentace objektu. Jakmile chceme instanci Calendar vypisovat, potřebujeme k tomu tzv. formatter. Přidáme import java.text.Sim­pleDateFormat a po vytvoření kalendáře vytvoříme formatter s následujícím formátem:

DateFormat formatData = new SimpleDateFormat("d.MMMM yyyy H:mm");

A vypíšeme:

System.out.println(formatData.format(kalendar.getTime()));

Výsledek:

Výpis aktuálního data a času v Javě

Úprava hodnoty

K existujícímu kalendáři můžeme přičítat určitý počet dní, hodin a podobně. Slouží k tomu metoda add(), která bere jako 1. parametr konstantu políčka kalendáře a jako druhý počet jednotek, které chceme přidat. Konstanty nalezneme na třídě Calendar, označují co chceme přidávat.

Zkusme si to a přidejme našemu kalendáři 3 dny v týdnu:

kalendar.add(Calendar.DAY_OF_MONTH, 3);

Výsledek:

4.duben 2013 18:45

Pokud bychom zadali zápornou hodnotu, dny bychom ubrali. V prvním parametru metody můžete použít mnoho konstant, budou to zejména:

  • DAY_OF_MONTH - Den v měsíci
  • HOUR_OF_DAY - Hodina
  • MILLISECOND - Milisekunda
  • MINUTE - Minuta
  • MONTH - Měsíc
  • YEAR - Rok

Nastavení hodnoty

Hodnotu kalendáře můžeme jednoduše nastavit pomocí metody set(). Má stejné parametry jako metoda add(), jen hodnoty nastavuje místo toho, aby je přičítala k existujícím. Zkusme si nastavit kalendář na programátorské vánoce, tedy na Halloween (ano, protože 31 OCT = 25 DEC).

kalendar.set(Calendar.DAY_OF_MONTH, 31);
kalendar.set(Calendar.MONTH, 9);
kalendar.set(Calendar.YEAR, 2013);

Výsledek:

31.říjen 2013 18:48

Může být matoucí, že měsíce začínají od nuly. Leden je tedy nultý a říjen je deváty! Pro jistotu můžeme při nastavování hodnoty použít konstantu OCTOBER (říjen):

kalendar.set(Calendar.MONTH, Calendar.OCTOBER);

Čtení hodnoty

Pro čtení určité hodnoty slouží opět konstanty, NetBeans vám jich v nabídce nabídne opravdu mnoho. Čtení probíhá metodou get(), která opět bere v parametru konstantu políčka. Ke konstantám, co jsem zmínil výše, můžeme přidat ještě:

  • DAY_OF_WEEK - Vrátí den v týdnu
  • WEEK_OF_YEAR - Týden v roce. Můžeme tak např. zjistit, zda je sudý nebo lichý týden.
  • HOUR - Hodina ve formátu 1-12. Jestli je 0 odpoledne nebo poledne označuje hodnota konstanty AM_PM.
  • AM_PM - Pokud je zde hodnota AM, hodnota v HOUR znamená před polednem. Hodnota PM označuje po poledni.

Zkusme si vypsat nějakou vlastnost našeho kalendáře:

System.out.printf("Hodina: %s\n", kalendar.get(Calendar.HOUR_OF_DAY));

Výstup:

Hodina: 5

Parsování data a času

Asi se nám bude často stávat, že budeme chtít po uživateli zadat nějaké datum, případně i čas. Formatter data nám k těmto účelům nabízí metodu parse(). Nechme uživatele zadat datum v textové podobě a poté ho převeďme do objektu Calendar a vypišme.

Scanner sc = new Scanner(System.in, "Windows-1250");

Calendar kalendar = Calendar.getInstance();

System.out.print("Zadej datum ve formátu 1.1.2000 13:14:");
formatData = new SimpleDateFormat("d.M.yyyy H:mm");
try {
    kalendar.setTime(formatData.parse(sc.nextLine()));
    System.out.println("Zadal jsi datum: " + formatData.format(kalendar.getTime()));
} catch (ParseException ex) {
    Logger.getLogger(DatumACas.class.getName()).log(Level.SEVERE, null, ex);
}

Výsledek:

Parsování data a času v Javě

Parsování musíme obalit blokem try a přidat blok catch, NetBeans nám tuto úpravu nabídne a udělá ji za nás. K výjimkám (try a catch) se v seriálu dostaneme později. Parsování musí být v try bloku z toho důvodu, že uživatel může zadat nesprávný formát. Parsování se potom nepovede a program pokračuje v bloku catch, kde na chybu zareagujeme.

Bude potřeba přidat importy java.text.Par­seException a několik dalších k loggeru, NetBeans by to měl udělat za vás nebo použijte Fix Imports.

Tabulka jednotlivých znaků, které v řetězci formatteru můžeme použít a jejich význam je poněkud vyčerpávající, zájemce odkáži na oficiální dokumentaci, kde jsou vysvětleny jednotlivé složky patternu: http://docs.oracle.com/…eFormat.html

Jednotlivé kalendáře můžeme porovnávat pomocí metody compareTo(). Hotový projekt se vším, co jsme v článku dělali, naleznete jako vždy v příloze.

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


 

Stáhnout

Staženo 545x (16.67 kB)
Aplikace je včetně zdrojových kódů v jazyce java

 

  Aktivity (2)

Č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 (7 hlasů) :
55555


 


Miniatura
Předchozí článek
Gettery a settery v Javě
Miniatura
Následující článek
Cvičení k 11. lekci OOP v Javě

 

 

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

Avatar
Tom Barbořík:

Čau,
teď je v Java 8 nové api pro práci s časem a datem.
http://docs.oracle.com/…summary.html
Přišlo mi dobré to zmínit.

 
Odpovědět 26.7.2014 23:35
Avatar
Petr.Matras
Člen
Avatar
Petr.Matras:

Navazuju na dotaz Matěje Kripnera - jaký je smysl ukládání objektu podtřídy SimpleDateFormat do reference typu jeho abstraktního předka DateFormat?

DateFormat formatData = new SimpleDateFormat("d.MMMM yyyy H:mm");

Chápu, že to dědičnost umožnuje, ale plynou z toho v tomto případě nějaké výhody pro další práci s tímto objektem? Odpověď na Matějův dotaz, že až bude umět víc OOP, tak to pochopí, se mi jeví lehce nedostačující :)
A jak bylo zmíněno, v textu lekce by bylo potřeba doplnit informaci, že je potřeba naimportovat také java.text.Date­Format, když už se používá reference tohoto typu.

Editováno 25.4.2015 2:26
Odpovědět  +2 25.4.2015 2:24
Sometimes you just do things. - Scott Jurek
Avatar
Marcel Smolik:

Jsem zmaten mam se ucit celendr nebo API abych to nečet zbytečně.

 
Odpovědět 11.7.2015 1:00
Avatar
Odpovídá na Marcel Smolik
Marcel Smolik:

Pardon oprava mam číst tento článek nebo ten nový se zaměřením na datum a čas.

 
Odpovědět 11.7.2015 1:02
Avatar
secretcode
Člen
Avatar
secretcode:

Chyba v riadku

formatData = new SimpleDateFormat("d.M.yyyy H:mm");

Chyba tam typ deklaracie premennej formatData

SimpleDateFormat formatData = new SimpleDateFormat("d.M.yyyy H:mm");
Editováno 3. března 16:09
 
Odpovědět 3. března 16:09
Avatar
Debrax
Člen
Avatar
Debrax:

Menší preklep v úvode
Název může Calendar může být poněkud matoucí...

..a pozerám, že chyba formatData.. už bola spomenutá :)

 
Odpovědět 26. dubna 12:17
Avatar
Pavel Habžanský:

Naštěstí inteligentnější IDE jako IntelliJ (nevím, jak NetBeans) to sami naimportujou, jakmile se pokusíš vytvořit instanci třídy, ke které potřebuješ daný balíček :-)

Odpovědět 27. května 14:39
Čím větší výzva, tím větší zkušenost
Avatar
Roman Duchoň:

No... ač mi fungují, zatím nerozumím příkazům try a catch. Takový složitě vypadají příkazy a oni neumí ošetřit, když zadám něco špatně? Mlčím. Třeba jen má neznalost.

A co to odčítá datumů (zde na stránkách schválně použit tento tvar)?
Zkusil jsem něco jako:

public int porovnej()    {
        ted.set(Calendar.MILLISECOND, 0);
        ted.set(Calendar.SECOND, 0);
        ted.set(Calendar.MINUTE, 0);
        ted.set(Calendar.HOUR_OF_DAY, 0);
        bude.set(Calendar.MILLISECOND, 0);
        bude.set(Calendar.SECOND, 0);
        bude.set(Calendar.MINUTE, 0);
        bude.set(Calendar.HOUR_OF_DAY, 0);
        long tedMili = ted.getTimeInMillis();
        long budeMili = bude.getTimeInMillis();
        long rozdilMili = budeMili - tedMili;
        long denMili = 86400000;
        int dnu = (int) (rozdilMili / denMili);
        return dnu;
}

Opravdu to nejde jednodušeji? A co když budu chtít zapojit měsíce? Roky? Hodiny? A abych se nedostal do záporných hodnot?
Možná je to zbytečný dotaz, jen mě to trochu zarazilo. Občas jsem se i divil, jak jde něco jednoduše. Něco, co si dokáže člověk normálně představit programovací jazyk dokázal vystihnout líp, ale tohle...

Odpovědět 27. září 16:55
RD
Avatar
Atrament
Člen
Avatar
Odpovídá na Roman Duchoň
Atrament:

Tento článek už není příliš aktuální, je to uvedeno přímo v úvodu článku. Od Javy 8 je k dispozici komplet nové API na práci s časem, na zjištění počtu dní mezi dvěma datumy se dá použít ChronoUnit

LocalDate ted = LocalDate.now();
LocalDate potom = LocalDate.of(2016, 11, 19);
ChronoUnit.DAYS.between(ted, potom);
 
Odpovědět  +2 28. září 11:07
Avatar
Odpovídá na Atrament
Roman Duchoň:

Úžasné! :) Dík.

Pozn. pro budoucí čtenáře:

import java.time.LocalDate;
import java.time.temporal.ChronoUnit;

edit: Měl jsem si přečíst ten článek, na který se odkazuje na začátku.
Ono asi neplatí, že když se učím základy, neměl bych řešit novinky...

Editováno 29. září 12:26
Odpovědět 29. září 12:23
RD
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 39. Zobrazit vše