Datum jako služba – používáte?

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
jannek19
Člen | 47
+
0
-

Ahoj,

chtěl bych se v aplikaci zbavit všudypřítomného new DateTime a tak mě napadlo, že by se datum dal tahat z DIC jako služba. Našel jsem k tomu téma Datum jako služba – dobrý nápad?, kde sice všichni píšou, že by to bylo dobré, ale nikdo už tam nezmiňuje žádné praktické zkušenosti :)

Chtěl jsem se tedy zeptat – používáte někdo ve svých aplikacích datum registrované v DIC? Používáte Kdyby\Clock, nebo svojí vlastní implementaci? Na co si dát pozor?

Díky!

filsedla
Člen | 101
+
+1
-

Dobrá věc k přemýšlení.

V jakých situacích new DateTime() vlastně používáš?

Může být dobrý nápad použití new DateTime() zrušit, např. v databázových dotazech použít místo toho NOW() na úrovni databáze. Při vkládání CURRENT_TIMESTAMP. Zažil jsem situaci, kdy databáze měla rozsynchronizovaný čas s aplikací a kombinování časů z databáze a z aplikace dělalo problémy.

Další věc, se kterou jsem se setkal, byla řekněme nějaká funkce, která potřebovala současný čas. Tak jsem nejprve v ní uvedl $now = new DateTime(). Pak jsem ale zjistil, že ji potřebuju volat s jinou časovou referencí, takže čas nyní předávám zvenku. Taky řešením bylo zbavit se new DateTime úplně – objekt času dodá „někdo jiný“.

CZechBoY
Člen | 3608
+
+1
-

Je to dobrý pro testování, synchronizaci času napříč aplikací a nezávislosti na vnější proměnný.
Je to taky dobrý pro debugování (což je vlastně i součást testování) když ti aplikaci v určitý čas (třeba 23:59:59) něco provede a ty to nemůžeš v (třeba 9:00) nasimulovat.

jannek19
Člen | 47
+
0
-

@filsedla new DateTime obvykle používám např. když potřebuji do DB uložit datum vytvoření/změny/smazání určitého záznamu (tj. při sestavování DB dotazu ve formuláři/pomocné třídě). A pak maximálně pro referenci „aktuální data“ – např. když potřebuju rozdělit záznamy na minulé/dnešní/budoucí, nebo když zobrazuji záznamy k určitému datu – pokud datum chybí, znamená to zobrazit dnešní záznamy (tedy něco jako if ($date === NULL) { $date = new \DateTime; }).

Od NOW() a CURRENT_TIMESTAMP, timestamp v DB jsem před lety upustil – lepší je do DB vždy předat aplikační datum manuálně a na straně DB používat typ datetime, nebo date – a nespoléhat se na nastavení DB – navíc je to flexibilnější – můžu prohlásit, že v DB jsou datumy uloženy v UTC a při načtení/zobrazení je konvertovat do požadované časové zóny, což při použití NOW() a timestamp může být docela komplikované (nevíme s jakou zónou nám DB pracuje).

"…objekt času dodá “někdo jiný” – to je právě můj cíl, v praxi by to šlo přes parametry metod, ale někde na vyšší úrovni stejně budu ten DateTime vyrobit – a proto uvažuju, že bych si vyrobil nějakou tovární třídu na aktuální čas, nebo použil Kdyby\Clock.

@CZechBoY souhlas – to „když ti aplikaci v určitý čas (třeba 23:59:59) něco provede a ty to nemůžeš v (třeba 9:00) nasimulovat.“ je dobrá poznámka :)


Jak si tedy s aktuálním časem v aplikaci pracujete vy? Používáte nějakou vlastní továrnu v DIC, nebo Kdyby\Clock?

F.Vesely
Člen | 368
+
+1
-

Kdyby\Clock funguje v pohode. :)

CZechBoY
Člen | 3608
+
0
-

@jannek19 Jak třeba řešíš groupování hodnot podle času, když chceš aby u klienta to bylo správně nagroupované – tzn. jeden čas může být v letním a druhý v zimním času. Pokud nepoužíváš žádné nastavení databáze, resp. jedeš tak jakoby si nevěděl jaký je tam nastavení.

Editoval CZechBoY (23. 1. 2017 12:00)

jannek19
Člen | 47
+
0
-

@CZechBoY jak to groupování hodnot podle času myslíš? Jako groupnutí záznamů v DB podle data a času? Nikdy jsem nic takového nepotřeboval (příklad použití?), ale prostě bych to groupnul podle daného sloupce – nepotřebuješ na straně DB rozlišovat letní a zimní čas pokud do DB ukládáš všechny datumy se stejným nastavením (normalizuješ si letní/zimní čas už v aplikaci).

CZechBoY
Člen | 3608
+
0
-

@jannek19 No dejme tomu třeba grafy. Chci pro každej den (nebo pro každou hodinu v konkrétní den, nebo histogram pro každou hodinu napříč dny) vědět kolikrát se někdo přihlásil (nebo cokoliv užitečnějšího).

jannek19
Člen | 47
+
0
-

@CZechBoY díky za příklad.

@MichalHlávka o Carbonu jsem už četl, v čem je to lepší než čistý DateTime objekt?

Michal Hlávka
Člen | 190
+
0
-

@jannek19 to se doctes hned na prvni strance toho odkazu. Moc casu ti to nezabere, ale uvidis ze se s tim lip pracuje. Navic umi simulovat cas, jak psal @CZechBoY ze je nekdy potreba. A hodi se lip aji pri testech.

jannek19
Člen | 47
+
0
-

@MichalHlávka na ten odkaz jsem samozřejmě koukal, sice jsem to proběhl jen letmo, ale nezahlédl jsem tam žádnou „killer-feature“, kvůli které bych měl zahodit obyčejný DateTime a začít používat Carbon. Proto jsem se ptal, v čem konkrétně je to podle tebe lepší. Čas umí simulovat i obyčejný DateTime, v tom bych problém neviděl :)

Michal Hlávka
Člen | 190
+
0
-

@jannek19 tak v tom se necham rad priucit, pokud volas new DateTime nekde v kodech, jak nastavis cas, ktery chces, aniz by si serverove zasahoval?

Barvoj
Člen | 60
+
0
-

pokud volas new DateTime nekde v kodech, jak nastavis cas, ktery chces, aniz by si serverove zasahoval?

To právě podle mě neuděláš. Proto je lepší nepoužívat běžně v aplikaci new DateTime ale udělat si službu (řekněmě DateTimeProvider), která ti DateTime vrátí a tuto službu si pak můžeš injectovat tam kde potřebuješ vytvářet DateTime.

Pokud pak při testování chceš pracovat s konkrétním datumem a časem, stačí ti injectovat takovou instanci DateTimeProvideru, která ti bude vracet přesně ten DateTime který potřebuješ.

jannek19
Člen | 47
+
0
-

Prostě si ten objekt vytvořím s potřebnými parametry a předám ho dál, proč v tom hledat komplikace?

$date = new DateTime(...); // nastavení potřebného datumu, zóny,...
$obj->method($date,...);

Vylepšit to můžu už jenom tím, že na vyšších úrovních aplikace nebudu vytvářet DateTime ručně, ale požádám o to nějakou službu.

@MichalHlávka jak bys to řešil s Carbonem?

filsedla
Člen | 101
+
0
-

@MichalHlávka Na první pohled se mi na Carbon zalíbily např. metody diffInDays(). V čistém PHP si nikdy nemůžu zapamatovat, jak se k podobnému výsledku vlastně dostat.

Michal Hlávka
Člen | 190
+
0
-

@Barvoj @jannek19 prave o tom mluvim, to Carbon prave zvladne. Zaobaluje tridu DateTime, dava ji vice funkci a v pripade, ktery resime, staci v incializaci aplikace zavolat

Carbon\Carbon::setTestNow(Carbon\Carbon::createFromTime(11,00));

Potom vsude, kde v kode volate Carbon::now() bude mit cas 11 am.

Editoval Michal Hlávka (25. 1. 2017 10:37)

mkoubik
Člen | 728
+
+7
-

@MichalHlávka Což je takový ten ruby-on-rails styl testování (monkey patching místo mockování). Ze začátku to asi stačí, ale narazíš když budeš potřebovat testovat použití různých časů v různých službách najednou (třeba u dlouhoběžících procesů, aktuální čas vs. čas requestu, nebo třeba měření jak dlouho trvá nějaká operace) – to statické Carbon::now() je logicky jen jedno.