Datum jako služba – používáte?
- jannek19
- Člen | 47
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
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ý“.
- jannek19
- Člen | 47
@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?
- CZechBoY
- Člen | 3608
@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
@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).
- Michal Hlávka
- Člen | 190
@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
@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
@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
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
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?
- Michal Hlávka
- Člen | 190
@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
@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.