Autor Zpráva
RASik
Profil *
Ahoj všichni,
určitě se v mnoha vašich formulářích vyskytuje datum nějaké události. Tento datum potřebujete uživateli (rozuměj hloupému, blondýně, policatovi...) vysvětlit, pak OŠETŘIT a samozřejmě vložit do DB. Já osobně používám přibližně toto a rád bych znal Vaše názory a zkušenosti, jak to děláte nebo jak by se to mohlo dělat líp.
Řekněme, že z logiky aplikace vyplývá, že by to nemělo být datum starší než letošní. Zajímá mě i, jak dalece a konkrétně informujete uživatele o tom, co zadal špatně.

Takže formulář:

<form method="post">
    datum události: <input type="text" name="datum_form" size="10" maxlength="10"> nápověda: datum zadávejte ve formátu d.m.rrrr, oddělovače též ,*-:/;
    <input type="submit" name="odeslat" value="potvrdit">
</form>

a skriptík:

<?
if(isset($_POST['odeslat'])) {
    $dat=trim($_POST['datum_form']);
    if(strlen($dat)>=8 AND strlen($dat)<=10) {
        $dat=strtr($dat,",*-:/;","......");
        if(substr_count($dat,".")==2) {
            list($den,$mes,$rok)=explode(".",$dat);
            if(($den<1) OR ($den>date("t",mktime(0,0,0,$mes,1,$rok))) OR ($mes<1) OR ($mes>12) OR (strlen($rok)<>4) OR ($rok<date("Y"))) {
                echo $hlaska="špatně 1";
            }
            else {
                $datum_do_db=date("Y-m-d",mktime(0,0,0,$mes,$den,$rok));    
            }
        }
        else {
            $hlaska="špatně 2";
        }
    }
    else {
        $hlaska="špatně 3";    
    }
}    
?>

Jako první doplňující dotaz by mě ještě zajímalo, jestli, když máte ve formuláři i čas této události, zda je ošetřujete společně s datem a vkládáte do DB jako datetime nebo to děláte každé zvlášť (nebo nějak jinak?).

A druhý: pokud by datum události neměl být budoucí (čili větší než je dnes), jaký postup nebo funkci k porovnání používáte?
Díky za Vaše fundované názory.
1Pupik1989
Profil
Prožeň datum přes strtotime. Pokud vrátí false (-1 v php <= 5.1.0), pak je zadaný datum špatně. Pokud je správně, tak ho uprav přes date a odešli do DB.

Čas i datum ověřuji dohromady.

Řešení rozdílů dat řeším většinou na úrovni DB přes funkci TIMESTAMPDIFF.
Joker
Profil
RASik:
datum zadávejte ve formátu d.m.rrrr, oddělovače též ,*-:/;

A on je někdo reálně používá? Ještě nikdy jsem neviděl datum zapsané např. 3:4*2015 nebo 3;4;2015.
Ale co jsem viděl bylo datum bez oddělovačů: 03042015 (byl tam tlak na rychlost vyplňování a psaní oddělovačů prý zdržovalo).

Ta validace by šla zjednodušit, v podstatě by stačilo jen udělat to $datum_do_db a pak testovat, jestli to není false. Nebo viz 1Pupik1989.
roofer
Profil *
A použít datepicker by nešlo?
Joker
Profil
roofer:
Datepicker na klientovi ovšem neřeší problém validace na serveru.
roofer
Profil *
Joker:
To neřeší, ale formát by se mu ujednotil a měl by to jednodušší i pro policajty, blondýnky... konceckonců i validaci samu.

Z hlediska uživatele mi přijde i vhodnější, když mě "to" navede samo už při vyplňování, než, že mi přijde hláška, že musím něco opravit. (přepsat třeba starý rok, jak uvádí,,)
1Pupik1989
Profil
roofer:
Pokud bude mít uživatel zapnutý javascript. Jinak je tam, kde byl.

Nejjednodušší bylo vedle pole napsat příklad. Další možnost udělat políčka zvlášť.

Já si speciálně kvůli datumu s časem udělal v js funkci. Mám klasické inputy a nad nimi a pod nimi šipky. JS akorát přidává ty šipky, takže funguje i bez JS.
Alphard
Profil
1Pupik1989:
Prožeň datum přes strtotime.
Byť to aktuálně nemusí být problém, co když se přesáhne rozsah? To vždy přemýšlíš o tom, jestli náhodou třeba po uživateli nechceš datum narození? Existují lepší metody, např. \Datetime těmito problémy netrpí, snad vždy je lepší reprezentovat datum jako instanci \Datetime.

roofer:
A použít datepicker by nešlo?
Také ho dávám kde to jde. Lze určit rozsahy a další omezení, takže někde nelze vybrat starší data, někde jenom pracovní dny. Při výběru intervalů lze zakázat vybrat Do v termínu před Od. Považuji to za lepší než nutit někoho číst, v jakém formátu má zadávat data. Navíc třeba mně osobně při výběru vyhovuje, že vidím ten kalendář, mohu se ujistit, že je to ten den co čekám a že nejde třeba o překlep v měsíci.
1Pupik1989
Profil
Alphard:
Používám to v akcích co jsou +- 5 let, takže tak dalece jsem nad tím nepřemýšlel. Navíc jsem začínal někde na PHP 4, takže jsem třídu DateTime od 5.2.0 ani nezaregistroval. Nicméně díky za tip, hned si přepíšu metodu.
RASik
Profil *
No teda, netušil jsem, že rozpoutám takovou "bitvu" :) ale z toho vidím, že to není tak jednoznačný... Díky všem.

1Pupik1989
strtotime jsem kdysi zkoušel a z jakýchsi tehdejších důvodů zavrhl (a zapomněl). Když na to teď s odstupem koukám, asi už vím i proč, i když by leccos zjednodušil. Každopádně dává tohle (ukázka pro ty, kteří neví...):
17.11.1964 OK
17.11.2040 FAIL ???
1.1.2013 OK
29.2.2013 OK - ???
0,1,2013 FAIL
32,1,2013 FAIL
31/1,2013 FAIL
31*1*2013 FAIL 

na úrovni DB přes funkci TIMESTAMPDIFF“ - asi to nechápu, když uživatel zadá špatný datum, tak to přece nemůžu nechat dojít až tak daleko...

JS akorát přidává ty šipky“, jo, taky to někdy buď nabarvím nebo dám jiný signál

Joker
oddělovače též ,*-:/;‘“ , jo, někdy až zírám, co jsou schopní tam nasmolit, protože to je blízko na (nejen numerický) klávesnici.

datepicker“ - co to je? Aha, kalendářích..? Taky jsem ho zkoušel, ale zabírá moc místa (nebo je mrňavej a nečitelnej) a taky nadávali, že když potřebují nějaký vzdálený datum, tak je prý lepší to napsat ručně...
Keeehi
Profil
RASik:
taky nadávali, že když potřebují nějaký vzdálený datum, tak je prý lepší to napsat ručně.
1) Jde vybrat takový, aby šel dobře zadat i vzdálený datum.
2) Samozřejmě nesmí to být povinné ho použít, ale implementovat to pouze jako volitelný doplněk.

A co nějak takto? Přicház se o možnost textového vyjádření ale mělo by to zvládnout formáty ROK.MĚSÍC.DEN, DEN.MĚSÍC.ROK a ROKMĚSÍCDEN s jakýmikoli oddělovači.
<?php
function sanitizeDate($string) {
    $string = trim(preg_replace('~\D+~', '-', $string), '-');
    
    try {
        return new DateTime($string);
    } catch (Exception $e) {
        return null;
    }
}
RASik
Profil *
Tohle je trochu mimo moje programátorské "vzdělání", regul. výrazy mi častokrát dělaly přesně to, na co byly naprogramovaný, ale ne to, co jsem chtěl já, zbytek je pro mě trochu "rozsypanej čaj". Ale proč nepoužít něco, co je napsaný jen na 10 řádkách? Mrknu na to...


Testuju to, hlásí, že
Object of class DateTime could not be converted to string in datum.php on line 13
. Na řádku 13 mám prosté: echo sanitizeDate("2015.1.1");, dělám něco špatně?

Napadá mě, když použiju ROKMĚSÍCDEN - rozumím dobře - bez oddělovačů? Asi bude nutné psát dny a měsíce dvoumístně (čtyřmístný rok je samozřejmý..), jinak si nedovedu představit, že by to rozeznalo např. 1.11. od 11.1 je to tak?
Nechci vypadat zatvrzele, ale moje zkušenost radí, že víc možností vložení = delší nápověda, kterou uživatelé stejně nečtou a pravděpodobně použijí buď 1. možnost nebo jsou zmatení a vloží blbost.
Keeehi
Profil
1) Při úspěchu ta funkce vrátí instanci třídy DateTime. Pokud se datum převést nepovede, tak vrátí null.
2) Zbytek celé magie je schován v řádku 3. Nejdříve to nahradí vše co není číslo pomlčkou. A pak to případné pomlčky ze začátku a z konce ořízne. Takže to co v proměnné $string po třetím řádku může být
0
00000000000
0-0
000-000
0-00-000000-000-000000-0000
//nula reprezentuje jakékoli číslo
Takže je tam řetězec složený jen z číslic a pomlček, přičemž čísel může být za sebou kolik chce a pomlčka je vždy jen jedna.

S pomlčkami bere DateTime tyto formáty 30. dubna 2015
30-4-2015
2015-4
2015-04
20150430
15-04-30
Takže všechny znaky ,*-:/; budou fungovat a dokonce i spoustu dalších. Oddělovač je všechno, co není číslo. Proto 30. dubna 2015 jde zapsat jako
30,4,2015
30*4*2015
30-4:2015
30/4;2015
,*-:/;30,*-:/;4,*-:/;2015,*-:/;
Koupil jsem si jednou 30 koťátek a všechna byla 4barevná. Nejlepší na tom bylo, že jsem za ně zaplatitl jen 2015,-Kč.
Všechno se zvládne převést.

Vaše odpověď

Mohlo by se hodit


Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm:

0