Převod data z českého formátu
V databázi se datum ukládá obvykle ve tvaru yyyy-mm-dd
, v češtině se ale používá formát d.m.yyyy
. O tom, jak toto datum správně zobrazit, už jsem psal, tento článek ukazuje, jak datum převést zpátky na tvar použitelný v databázi.
Databáze MySQL si u kalendářního data poradí i s formátem yyyy-m-d
, který se z českého formátu dá získat jednoduchým převodem. Pokud se však datum převede na řetězec (třeba po aplikaci funkce GREATEST()
), tak se při porovnávání bez plného formátu neobejdeme. Jak ho získat?
<?php
// převod na formát yyyy-m-d
$datum_iso = preg_replace('~^([0-9]+)\\.([0-9]+)\\.([0-9]+)~', '\\3-\\2-\\1', $datum);
// převod na formát yyyy-mm-dd
if (preg_match('~^([0-9]+)\\.([0-9]+)\\.([0-9]+)$~', $datum, $match)) {
$datum_iso = sprintf("%d-%02d-%02d", $match[3], $match[2], $match[1]);
}
// trik
$datum_iso = vsprintf('%3$d-%2$02d-%1$02d', explode('.', $datum));
?>
Poslední způsob využívá méně známou funkci vsprintf, která se od sprintf liší v tom, že místo seznamu parametrů přijímá pole. To získáme funkcí explode. Pro otočení pořadí parametrů by se dala použít funkce array_reverse, příklad ale používá formátovací řetězec 1$
.
Ve většině případů bych nicméně spíše doporučoval obdobu druhého příkladu, která formát zároveň i zkontroluje.
Diskuse
Kcko:
<OT> Muzu vedet, proc v danem REGEXPU pouzivate dvojita zpetna lomitka pred teckou, kdyz staci jedno? ( \. => znak tecky, . => zastupny znak jakehokoliv znaku krome tusim whitespaces )
Diky za vysvetleni
16.4.2007 03:21:40
BlackSUN:
Právě proto, aby se výraz kontroloval na český formát data s tečkami. Pokud by tam byla tečka jakožto "jeden libovolný znak", výraz by akceptoval i datum ve formátu d-m-yyyy, ale také třeba ddmmyyyy, což by pak nepřelouskala navazující funkce, protože pole by mělo jeden prvek a ne tři.
Prostě se na začátku definoval formát s tečkou, tak ji použijeme ve výrazu. Lze použít cokoliv nečíselného.
16.4.2007 06:48:40
Kcko:
To samozrejme chapu.
Kdyz potrebuju vyjadrit napr znak dolaru v REGEXPU tak ho vyjadrim takto -> \$
Kdyz potrebuju znak tecky tak -> \.
Nechapu proc tam jsou 2x zpetna lomitka
16.4.2007 12:58:36
Protože lomítka mají escape funkci v řetězci (v řetězci uzavřeném do apostrofů ' lze jen escapovat apostrof '\'') a je správné je zdvojovat i když někdy to není nutné. Např.: 'L\\A' je L\A
16.4.2007 13:16:42
Kcko:
Aha nejvsiml jsem si apostrofu, ja je totiz v REGEXPECH nepouzivam, tak jsem byl lehce udiven. Zkusim priste vice premyslet. Diky !
16.4.2007 13:23:23
Jen jedna maličkost na kterou se na webu často zapomíná: český formát datumu není dd.mm.rrrr, ale dd. mm. rrrr (jde o typografickou věc a nemá s PHP nic společného, ale třeba to někomu připomene základy typografie ;-) ).
16.4.2007 10:16:30
joe:
nj, to by pak mohlo byt treba ...
'~(0[1-9]|[12][0-9]|3[01])[- /.]\s?(0[1-9]|1[012])[-
/.]\s?((?:19|20)\d\d)~'
ale treba seznameni s knihovnou zend_date by asi bylo zajimavejsi, nez objevovat znovu kolo.
16.4.2007 12:13:32
Pokud se dobře pamatuji, jedná se o českou normu zápisu data, takže v české typografii se jen uplatňuje (jen pro přesnost).
16.4.2007 13:19:07
a nestačilo by použít tohle?
$datum_iso = date("Y-m-d", strtotime("31.4.2005"));
16.4.2007 15:20:20
Ten trik bude rychlejší :)
16.4.2007 16:20:45
m:
Nicmene v PHP nikdy nejde o rychlost.
16.4.2007 17:42:00
Já bych se strotime() trochu bál s formátem d.m.yyyy používat, protože to není žádný mezinárodně uznávaný formát a nemám jistotu, že na nějakém systému se nevyloží třeba jako m.d.yyyy. Nicméně novější verze PHP mají vlastní knihovnu pro zpracování data, takže tam jakás takás jistota už je.
17.4.2007 03:04:42
Nic proti typografii, ale kdo přiznejme si, že BFU českou typografii nedodržují. Rovněž vím, že by se za tečkami v datu měly dělat mezery, ale když píšu nějaké datum (zvláště v prostředí počítače), tak píšu ve formátu d.m.yyyy (případně dd.mm.yyyy - podle toho co je za den a měsíc). Takže výše uvedený příklad sice možná není typograficky správně, ale z uživatelského hlediska správný je, protože většina uživatelů to datum zapíše bez mezer.
16.4.2007 15:26:43
Většina asi ano, ale ne všichni. Já píšu s mezerama.
16.4.2007 20:54:53
Tomáš:
Nezlobte se, ale to jako když bude většina lidí na vašem webu psát "ponďelý" a "vijymka", tak to prohlásíte za správné jenom proto, že vaši návštěvníci nedokončili ani čtvrtou třídu pomocné školy? To mi připadá jako poněkud podivná logika...
17.4.2007 00:37:31
Andrew:
Nicméně když už chceme být přesní, tak není mezera jako mezera a v tomhle případě se používá poloviční. Klasická mezera z mezerníku je tedy stejně špatná jako psaní bez mezery a navíc blbě vypadá.
17.4.2007 23:17:31
Nevermind:
"V databázi se datum ukládá obvykle ve tvaru yyyy-mm-dd"
Skoro určitě se datum takto v databázi neukládá :) Snad jedině, že by to byla nějaká zvláštní textová/xml databáze.
16.4.2007 18:28:15
Nedavno jsem resil podobny problem a to jak obecne prevadet datum z/do ruznych formatu a vysledkem je tato funkce. Lze jednoduse rozsirit a na prevod DATETIME. V 99% pripadu ji ale stejne pouzivam na prevod z YYYY-mm-dd do dd.mm.YYYY :)
<?php
function convert_date($datum, $inf, $outf)
{
$inf = str_replace('d', '(\d{2})', $inf);
$inf = str_replace('m', '(\d{2})', $inf);
$inf = str_replace('Y', '(\d{4})', $inf);
if(preg_match("|$inf|", $datum, $match))
{
$result = $outf;
$result = str_replace('Y', $match[1], $result);
$result = str_replace('m', $match[2], $result);
$result = str_replace('d', $match[3], $result);
return $result;
}
return false;
}
?>
16.4.2007 18:31:02
Jeste bych chtel podotknout ze $datum je retezec, datum naformatovane dle $inf (input format) "1900-01-01" pro $inf = "YYYY-mm-dd" a $outf (output format) muze byt napriklad vyse uvedene "dd.mm.YYYY"
16.4.2007 18:32:56
kovar:
zdravim, zkošim tvojí funkci a furt mi neslape...:) a to to používám jak říkáš:)) nesedá mi tam proměná $match....he to napsané správně?
1.12.2007 15:28:56
S timhle je stale velky problem. Nechapu jednu vec. Proc sakra v PHP neexistuje nejaka samostatna funkce na prevod datumu.
Navic, pokud nekdo ulozi do MySQL neco jako '0000-00-00' je to spatne. Dost casto se zapomina na to, ze pokud datum neni, ma byt "NULL" nikoli zmrseny retezec, ktery neni typu date.
Napsal jsem si na to dost silenou tridu, ktera mi datum parsuje. Problem totiz nastava jeste ve chvili, kdy potrebuji vytvorit pivotni tabulku, kde sloupce budou (mesice, tydny, dny, atd.). Pak je treba pouzit v GROUP BY DATE_FORMAT, ktery ma odlisnou masku od te v PHP. Tohle samotne je dost silene.
Nikdy se totiz datum presne validovat neda, uz jen z toho duvodu, ze uzivatele pokazde napisi datum uplne jinak :). Jedine co se mi trosku osvedcilo je, ze jsem jim datum nechal vybirat pres kalendar, kde mam jakz takz jistotu, ze z toho nevyleze kravina. Nikdy by ovsem nemelo vyjit '0000-00-00', coz je stejna chyba jako miti 32 dni ci 13 mesicu.
16.4.2007 20:32:06
"Navic, pokud nekdo ulozi do MySQL neco jako '0000-00-00' je to spatne."
Někdy to může být i užitečné. Když víš třeba rok a měsíc, ale dnem si nejsi jistý, tak jak to uděláš? Vložíš třeba 2006-12-00 a později doplníš za nuly konkrétní datum.
Jinak pokud nechceš ukládat nuly v datu, mělo by stačit zapnout mod NO_ZERO_IN_DATE a MySQL a nuly se ukládat nebudou.
17.4.2007 02:48:40
Jinak funkci strtotime povazuji za stastnejsi reseni, nez regulari vyrazy. Uz jen z toho duvodu, ze clovek musi resit pocet dni v mesici, atd.
PHP + MySQL pro Date je stejne silene, jak PHP tak MySQL se k nejakemu Date chova naprosto svevolne a dovoluje ukladat snad jakoukoli kravinu.
16.4.2007 20:36:33
Funkce pro práci s datem v PHP používají Unix timestamp, který práci s neplatnými daty neumožňuje z principu. V MySQL se neplatná data dají zakázat proměnnou ALLOW_INVALID_DATES. Tvůj nářek není tedy v tomto případě opodstatněný.
17.4.2007 03:04:29
Velmi hezky řeší práci s datem třída Zend_Date
<?php
Zend_Date::setOptions(array('format_type' => 'php'));
$date = new Zend_Date('1. 1. 2007');
//alternativně i
$date = new Zend_Date('1.1.2007');
echo $date->toString('Y-m-d'); //2007-01-01
?>
Pochopí mnoho různých formátů.
17.4.2007 03:13:50
JFK:
Jestlize datum pouze vkladam do databaze, pouzivam na prevod vzdy SQL.
SET date = DATE_FORMAT('"17. 04. 2007"', '%d. %m. %y')
17.4.2007 16:51:22
Funkce DATE_FORMAT ale přeci slouží k formátování data ve správném formátu a ne k jeho rozebrání do toho formátu.
18.4.2007 10:38:09
JFK:
Po preceteni vaseho clanku, jsem me pocit ze se snazite pouze prevest datum, tedy formatovat pred ulozenim. Viz nadpis ... Převod data z českého formátu ... a pokracujete dale textem ... tento článek ukazuje, jak datum převést zpátky na tvar použitelný v databázi... . Proto jsem zminil funkci, ktera se snazi o totez.
23.4.2007 14:47:43
Problém je v tom, že funkce se nesnaží o totéž, ale o něco zcela jiného - mě osobně tento konkrétní případ vrátí NULL.
23.4.2007 15:48:25
JFK:
Mate pravdu ... nevsiml jsem si.
Je pravda, ze nektere jeji parametry nefunguji stejne pri SELECTu jako pri UPDATE.
funkcni priklad
UPDATE tb_xxx SET date = DATE_FORMAT('23.04.07', '%d.%m.%y')
pro INSERT neni funkcni vubec.
Pro INSERT pouzivam STR_TO_DATE
INSERT INTO tb_xxx (date) VALUES (STR_TO_DATE('23. 04. 2007','%d. %m. %Y')).
Pravdepodobne je lepsi pouzivat pouze STR_TO_DATE ...
23.4.2007 18:58:34
aha:
a tak to je docela k nicemu ne?
proc neukazes priklad kamo?
15.11.2009 22:02:28
url:
pise chybu:
Warning: vsprintf() [function.vsprintf]: Too few arguments in_
15.11.2009 19:07:14
Jakub:
A nestačilo by třebas nahrát do databáze oba formáty datumu - jeden pro výstup, druhý pro porovnávání datumů v databázi.
$datum=date("d.m.Y H:i:s");
$table = Mysql_Query("insert into tabulka (datum_mysql, datum_ceske)
values (now(),'$datum')");
21.7.2010 18:51:44
To bych nedoporučoval, protože jednak jde o duplicitu dat a jednak může dojít k nekonzistenci.
21.7.2010 18:53:31
Uprava pro pouziti s formatem DATETIME
preg_replace('~^([0-9]+)-0?([0-9]+)-0?([0-9]+) ([0-9]+)\\:([0-9]+)\\:([0-9]+)~', '\\3.\\2.\\1 \\4:\\5', $datum);
Vypise datum ve formatu "28.1.2012 13:32"
7.1.2012 15:55:39
Kith:
Uff
14.2.2012 21:10:14
Pavel:
Zdravím. Mám formulář, kde se uvádí datum narození ("DatumNarozeni1") ve formátu dd/mm/yyyy. V jiné části formuláře se musí uvádět ale formát mm/dd/yyyy. Jak zajistit, aby se datum přepsal z ("DatumNarozeni1") ale v požadovaném formátu.
Díky
3.3.2018 11:06:10