IT rekvalifikace s garancí práce. Seniorní programátoři vydělávají až 160 000 Kč/měsíc a rekvalifikace je prvním krokem. Zjisti, jak na to!
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

Lekce 3 - Dokončení knihovny DateUtils v PHP

V minulé lekci, Knihovna DateUtils pro český datum a čas v PHP, jsme rozpracovali jednoduchou utility třídu pro práci s datem a časem.

Dnes do knihovny DateUtils naprogramujeme formátování "hezkého času" a také se dostaneme k parsovací metodě.

Hezké datum a čas

Nevím, jestli má tato podoba data a času nějaký název, ale já jsem si metody implementoval jako prettyDateTime() a prettyDate(). Pokud je datum dnes, včera nebo zítra, vypíše se slovy, tedy např. Dnes. Pokud je někdy tento rok, vypíše se měsíc slovy, např. 2.ledna. Pokud je rok jiný než současný, vypíše se celé datum čísly, např. 2.1.2013. Případně se za hodnotu doplní ještě čas. Jistě uznáte, že toto je pro uživatele mnohem příjemnější, než hromada čísel. A s knihovnou to máte během okamžiku použité.

Nejprve si vytvořme privátní metodu, která nám převede nastavenou instanci DateTime na hezké datum:

private static function getPrettyDate(DateTime $dateTime): string
{
    $now = new DateTime();
    if ($dateTime->format('Y') != $now->format('Y'))
        return $dateTime->format('j.n.Y');
    $dayMonth = $dateTime->format('d-m');
    if ($dayMonth == $now->format('d-m'))
        return "Dnes";
    $now->modify('-1 DAY');
    if ($dayMonth == $now->format('d-m'))
        return "Včera";
    $now->modify('+2 DAYS');
    if ($dayMonth == $now->format('d-m'))
        return "Zítra";
    return $dateTime->format('j.') . self::$months[$dateTime->format('n') - 1];
}

V metodě si uložíme současné datum a pokud se roky současného a zadaného data různí, vrátíme číselně zapsané datum i s rokem. Pokud jsou den a měsíc stejné, vrátíme textový řetězec Dnes. Následně měníme současné datum a kontrolujeme, zda není včera nebo zítra. Jakmile vyčerpáme všechny možnosti, vrátíme den a měsíc slovy.

Konečně přidáme 2 veřejné metody, které nám datum naformátují do požadované podoby:

public static function prettyDate(string $date): string
{
    return self::getPrettyDate(self::getDateTime($date));
}

public static function prettyDateTime(string $date): string
{
    $dateTime = self::getDateTime($date);
    return self::getPrettyDate($dateTime) . $dateTime->format(' H:i:s');
}

Vše můžeme vyzkoušet převedením různých dat v různých formátech:

require_once('Utility/DateUtils.php');
echo(DateUtils::prettyDate(1376906152) . '<br />');
echo(DateUtils::prettyDateTime('2014-02-23 10:50') . '<br />');
echo(DateUtils::prettyDateTime('2014-02-22 10:50') . '<br />');
echo(DateUtils::prettyDate('24.2.2014') . '<br />');
echo(DateUtils::prettyDate('2014-02-01') . '<br />');
echo(DateUtils::prettyDate('2013/02/20') . '<br />');

Výsledek za předpokladu, že je dnes 23.2.2014:

Hezký datum a čas
localhost

Opět vidíme, jak naše metoda naformátuje naprosto cokoli na lidsky příjemně čitelnou hodnotu.

Parsování

Přejděme k parsovací metodě. Na vstupu ji dáme české datum (např. 15.1.2014) a formát, v jakém má být datum/čas zapsané. Metoda buď vyhodí výjimku nebo vrátí datum v DB formátu:

public static function parseDateTime(string $date, string $format = self::DATETIME_FORMAT): string
{
    if (mb_substr_count($date, ':') == 1)
        $date .= ':00';
    // Smaže mezery před nebo za separátory
    $a = array('/([\.\:\/])\s+/', '/\s+([\.\:\/])/', '/\s{2,}/');
    $b = array('\1', '\1', ' ');
    $date = trim(preg_replace($a, $b, $date));
    // Smaže nuly před čísly
    $a = array('/^0(\d+)/', '/([\.\/])0(\d+)/');
    $b = array('\1', '\1\2');
    $date = preg_replace($a, $b, $date);
    // Vytvoří instanci DateTime, která zkontroluje zda zadané datum existuje
    $dateTime = DateTime::createFromFormat($format, $date);
    $errors = DateTime::getLastErrors();
    // Vyvolání chyby
    if ($errors['warning_count'] + $errors['error_count'] > 0) {
        if (in_array($format, self::$errorMessages))
            throw new InvalidArgumentException(self::$errorMessages[$format]);
        else
            throw new InvalidArgumentException('Neplatná hodnota');
    }
    // Návrat data v MySQL formátu
    return $dateTime->format(self::$formatDictionary[$format]);
}

V metodě nejprve k řetězci s datem přidáme 00 sekund v případě, že je v něm jedna dvojtečka (uživatel zadává čas a nezadal vteřiny). Dále pomocí regulárních výrazů odstraníme bílé znaky před separátory, kterými jsou : a .. Díky tomu projde např. i datum 15.1. 2014 12:00, které se přeloží na 15.1.2014 12:00:00. Výsledný formát data a času je tedy vždy bez mezer a se vteřinami.

Tento formát můžeme předat třídě DateTime, validaci data provede za nás. Na internetu pod validací data naleznete zoufalá řešení, která na datum volají funkci explode() a podobně, která jsou vždy neúplná, zrovna kontrola rozsahů a zadání všech součástí data a času je poměrně náročná. Nikdy neprogramujte sami něco, co je součástí standardních knihoven jazyka! Nikdy to neuděláte tak kvalitně a to už jen proto, že PHP je v céčku. A i kdyby ano, je to vyhozený čas.

Instanci DateTime sdělíme formát a předáme ji naše datum. Ona se ho pokusí naparsovat. Jakékoli chyby nám vrátí v poli pomocí metody getLastErrors(). Pokud se zde nějaké objeví, vyhodíme výjimku s hláškou podle formátu, v opačném případě vrátíme datum v příslušném databázovém formátu. Výjimku můžete poté chytat někde při zpracovávání údajů a zobrazit ji uživateli. Za tímto účelem by bylo ideální vytvořit si nějakou svou.

Funkci si hned můžeme vyzkoušet:

$date = DateUtils::parseDateTime('24.2. 2014', DateUtils::DATE_FORMAT);
echo($date . '<br />');
$dateTime = DateUtils::parseDateTime('24.2. 2014 10:30', DateUtils::DATETIME_FORMAT);
echo($dateTime . '<br />');
$time = DateUtils::parseDateTime('10:30', DateUtils::TIME_FORMAT);
echo($time . '<br />');

Výsledek:

Parsování českého data a času
localhost

Validace data

Pro úplnost si dodejme i metodu validDate(), která o daném datu zjistí, zda je validní:

public static function validDate(string $date, string $format = self::DATETIME_FORMAT): bool
{
    try {
        self::parseDateTime($date, $format);
        return true;
    } catch (InvalidArgumentException $e) {}
    return false;
}

Metodu vyzkoušejme zadáním několika dat:

var_dump(DateUtils::validDate('24.2. 2014', DateUtils::DATETIME_FORMAT));
var_dump(DateUtils::validDate('24.2 14', DateUtils::DATE_FORMAT));
var_dump(DateUtils::validDate('29.2. 2014', DateUtils::DATE_FORMAT));
var_dump(DateUtils::validDate('29. 2. 2012', DateUtils::DATE_FORMAT));
var_dump(DateUtils::validDate('14:56', DateUtils::TIME_FORMAT));
var_dump(DateUtils::validDate('14:62', DateUtils::TIME_FORMAT));

Výsledek:

Validace českého datumu
localhost

Vidíme, že prošla opravu jen validní data.

Databázová funkce NOW()

Jelikož MySQL neumí pří vkládání nového řádku u formátu DateTime dosadit aktuální datum/čas, používám často ještě následující metodu, která vrátí současné datum a čas v databázovém formátu:

public static function dbNow()
{
    $dateTime = new DateTime();
    return $dateTime->format(self::DB_DATETIME_FORMAT);
}

Můžete si o mě myslet, že jsem barbar, protože nepoužívám nativní funkci NOW(), ale tuto pihu na kráse mi několikanásobně vyváží výhody vložení řádku do databáze přímo z PHP pole, které mi mimochodem přijde přímo z formuláře, dotaz se sám generuje a ušetří to spoustu práce. Pokud jste pracovali s místním databázovým wrapperem nad PDO, tak víte o čem mluvím. Pokud ne, dostaneme se k tomu u motivace k formulářové knihovně.

Opět vyzkoušíme:

echo(DateUtils::dbNow());

Výsledek:

Funkce dbNow() v PHP
localhost

Okomentovanou knihovnu máte v příloze ke stažení, ať vám dělá radost :)

V následujícím cvičení, Řešené úlohy k 1.-3. lekci knihovny v PHP, si procvičíme nabyté zkušenosti z předchozích lekcí.


 

Měl jsi s čímkoli problém? Stáhni si vzorovou aplikaci níže a porovnej ji se svým projektem, chybu tak snadno najdeš.

Stáhnout

Stažením následujícího souboru souhlasíš s licenčními podmínkami

Staženo 749x (3.26 kB)
Aplikace je včetně zdrojových kódů v jazyce PHP

 

Předchozí článek
Knihovna DateUtils pro český datum a čas v PHP
Všechny články v sekci
Knihovny pro PHP
Přeskočit článek
(nedoporučujeme)
Řešené úlohy k 1.-3. lekci knihovny v PHP
Článek pro vás napsal David Hartinger
Avatar
Uživatelské hodnocení:
30 hlasů
David je zakladatelem ITnetwork a programování se profesionálně věnuje 15 let. Má rád Nirvanu, nemovitosti a svobodu podnikání.
Unicorn university David se informační technologie naučil na Unicorn University - prestižní soukromé vysoké škole IT a ekonomie.
Aktivity