Proč mají všichni nutkání vymýšlet nové krkolomné způsoby ukládání data a času? Lepší než unix timestamp (nebo monotonní čítače např. nanosekund obecně) to velmi pravděpodobně nebude... time_t má jediné úskalí (2038), a to je jednak dobře zdokumentované, a jednak ve většině případů už dnes vyřešené (64bit time_t).
IMHO je problém spíš v tom, že je to naopak nějaký historický relikt z 90. let (možná dokonce z 80. let), který tehdy pro určité účely dával smysl (tehdy se takové věci jako BCD běžně používaly), ale tehdy nikoho nenapadlo, že by to v té podobě vydrželo až do roku 2022 (přesně jako v případě "Y2K"), a mezitím se na to zapomnělo, dokud nenastal průšvih.
to ale není formát BCD, resp. minimálně to není formát BCD, tak jak byl navržen. Formát BCD by to byl kdyby to bylo číslo v šestnáctkové soustavě. V takovém případě ale mimochodem nehrozilo žádné přetečení za předpokladu konverze stringu do unsigned (a nikoli signed) typu (samozřejmě když opomeneme jistý detail, že to číslo má 10 znaků).
3. 1. 2022, 09:08 editováno autorem komentáře
Nepsal jsem, že to je BCD, napsal jsem jen, že tehdy se takové věci jako BCD běžně používaly. Osobně si myslím, že za volbou tohoto formátu stály podobné důvody jako ty, kvůli kterým se BCD a podobné formáty používaly. Mudrcům, kteří tu s převahou pár desítek let vývoje HW i SW vykřikují, jak je to idiotské a jak by za to vyhazovali od zkoušky, bych doporučil, ať si cvičně napíšou implementaci localtime_r()
, vzpomenou si (nebo spíš vyhledají), jaký byl typický výkon tehdejšího hardware a pak ať se nad tím zamyslí znovu.
A ted si vemte, ze za takovy software nekdo plati... Mit na novem VW stejne sroubky a matky jako na Skode 1000 mi nevadi, to je lety provereny koncept, ale cokoli jineho bych chtel u noveho modelu auta nadesignovane od dob Skody 1000 nove, podle aktualnich navrhovych pravidel (pokud vysledek nakonec vyjde stejny, nevadi, ale dulezity je ten proces redesignu).
Vzhledem k tomu, že jde o anti-malware scanner, mám trochu pochybnosti o tom, že je to řešení z 80. nebo 90 let.
Spíš mne překvapuje, že ani firmy jako Microsoft evidentně nemají testovací prostředí, kde by software testovali s aktuálním časem posunutým o rok nebo o deset let dopředu. Trochu mne děsí, jestli tak netestují ani Windows.
Vzhledem k tomu, že jde o anti-malware scanner, mám trochu pochybnosti o tom, že je to řešení z 80. nebo 90 let.
Celé řešení ne, ale ta volba interního formátu může pocházet z něčeho staršího. Přijde mi to pravděpodobnější než že by takový formát pro ukládání časových známek někdo zvolil dnes, pokud by nebyl vázán kompatibilitou s něčím, co už ho používalo. Stejně jako si nemyslím, že by ty formfeedy ( ^L
), které jsou dodnes k vidění v drivers/scsi/st.c
v linuxovém jádře, byly záměr a ne jen pozůstatek copy&paste z nějakého staršího systému.
To jen přesouváte komplexitu jinam – jak by vypadala funkce, která ten Microsoftí timestamp inkrementuje o jeden den? Kolik větví tam bude podle měsíců, přestupných roků, přestupných sekund? :))
Unix timestamp je primitivní na straně zápisu a storage (dělá se často), komplexní na straně prezentace (dělá se vzácně). Tahle hrůza je sice jednodušší když se čte, ale zápis a (jak vidíme ve zprávičce) ukládání je minové pole.
No, zaprvý ti to 2x přeteklo přes uint32 (a int32 ještě víckrát) a zadruhé to neřeší problém komplexity - kdokoli bude chtít implementovat posunutí data o den, bude muset do funkce zahrnout kontrolu, který měsíc to je (jestli má 28/29, 30 nebo 31 dní), který rok to je (jestli je přestupný) a jestli ten rok není dělitelný 100 (pak není přestupný) nebo jestli není dělitelný 400 (pak zase přestupný je).
Navíc takto uvedené datum s časem oproti Unixovému timestampu není nezbytně unikátní ani sekvenční? Tedy, pokud přidáte možnost mít více než 60 sekund v minutě, tak je, protože pak to pokryje přestupné sekundy (a přestupné minuty), které jinak při blbé implementaci způsobí, že bude 2x vteřina 59 nebo vteřina 00 za sebou. To se v unixovém timestampu nestane, protože měří skutečný čas diferenciálně a ne podle nějakého šíleného systému. Vzhledem k tomu, že rychlost rotace Země se všelijak mění, tak není vyloučené ani to, že se v budoucnu budou sekundy ubírat, tedy by takto udaný čas ani při správné implementaci nebyl unikátní - jedna vteřina se 2x za sebou zopakuje.
A teď si vemte blbou funkci, která vám řekne, jestli mezi dvěma časovými daty uběhlo 24 hodin nebo ne. Tak v tomto případě taková funkce musí vědět, jestli v daném časovém úseku neproběhla přestupná sekunda. A pokud ano, tak musí zkontrolovat, jestli uběhlo 24 hodin + sekunda. U timestampu uděláte rozdíl a víte rovnou výsledek.
Při používání timestampu pro interní výpočty a převádění na lidsky čitelné datum jen v okamžiku, kdy je to nezbytné, může ušetřit přeci jen trochu výpočetního výkonu za předpokladu, že se provádí více výpočtů na datech než jejich zobrazení uživateli (např. hledání v databázi, po kterém se vyplivne jeden výsledek, tedy kromě konečného zobrazení se všechny opičárny s Gregoriánským kalendářem a přestupnými sekundami a minutami odstraní).
„To se v unixovém timestampu nestane, protože měří skutečný čas diferenciálně a ne podle nějakého šíleného systému.“
Tohle se protřepávalo na Rootu snad při poslední přestupné sekundě, kdy závěr byl takový, že unixový čas se též koriguje (dohledávat to už nebudu, ale pokud si pamatuju, tak to tam uváděl nejvyšší). Česká Wikipedie uvádí, že se nekoriguje, anglická zas, že existuje verze korigovaná (dle UTC) a nekorigovaná (dle TAI).
Takže?
On na to není žádný standard, takže si to každý může implementovat, jak chce. Běžně se ale předpokládá, že každý den je reprezentován 8400 jednotkami unixového času (říkejme tomu třeba „unixová sekunda“).
Takže pokud je vložena přestupná sekunda, musí se „unixová sekunda“ někde protáhnout – může se třeba protáhnout poslední sekunda na dvojnásobek, nebo se mohou mírně protáhnout sekundy v celém dni. Každopádně tu přestupnou sekundu není možné v unixovém čase reprezentovat. A pokud budete provádět v unixovém čase výpočty přes tu přestupnou sekundu (třeba byste měl spuštěné stopky přes půlnoc), budete to mít o sekundu špatně.
V případě odebrání „přestupné“ sekundy by to zase bylo opačně – buď by se musely „unixové sekundy“ třeba během celého dne nebo hodiny zkrátit, nebo by se muselo o půlnoci poskočit o dvě „unixové sekundy“.
Pravda, on to byl problém spíš BIOSu, a DOS/Windows to potom dědil. Že si s tím neuměl poradit je věc jiná.
Tenkrát když se o tom začalo mluvit, tak jsem ještě na 486ce zkoušel co to udělá, a zjistil jsem že když počítač 1.1.2000 zapnu, tak bude datum blbě a musím ho změnit ručně. Zato když jsem ho nechal běžet přes půlnoc, pokračovalo se bez problému dál a i po restartu to bylo správně. Takže stačilo jenom ho na Silvestra nevypnout... Měl jsem tam W95, ale nefungoval, tak jsem to používal jako DOSový stroj.
Nejvtipnější tenkrát bylo, když M$ po halasné propagandě, že všechny jeho programy jsou na Y2K připravené, vydal katalog softwaru na rok 1900.
Podle mne ten čítač neslouží ani k převádění na čas. Myslím, že jde o to, aby to byly unikátní hodnoty, v čase rostoucí, a příjemný bonus je, že z toho čítače zjistíte den, kterého se to týká. Něco jako verzování – když budete potřebovat verzovat nějaká data a bude vám to vycházet na jednotky až desítky verzí denně, také skončíte u nějakého formátu třeba YYYYMMDD-XXXX. Akorát tady holt někdo vymyslel, že to úsporně uloží do 32bitového čísla…
Takže bude lepší data nešifrovat, protože "vzoreček" na dešifrování je moc složitý? A komprimovat budeme pomocí RLE, protože to vymyslí i středoškolák, zatímco Deflate je moc složitý? A text budeme ukládat v ASCII, protože je to mnohem jednodušší, než přepočítávat Unicode znaky z UTF-8...
Tohle asi nebude nejlepší argument. Primitivnost není vždy výhoda.
Co to je za zhovadilou implementaci? Za to bych vyhodil studenta od zkousky z libovolnyho predmetu, i kdyby nebyl zamerenej na programovani...
Tahle chyba by zasloužila pochod hanby. Kdyby se autor tohoto *nedorozumění* zamyslel nad limity, asi by rychle přišel na to, že datum 2201010000 a každá minuta poté je větší než svatých 2147483647. Po pětisekundovém zamyšlení by přišel s tím, že když už opravdu musí převádět* řetězec na integer, mohll by aspoň záznam data začínal měsícem a ne dvojčíslím roku a měl by řádně zkontrolovat vstup. Ani to ale neodpovídá na otázku "Proč?"
Proč se tu vůbec používá takový úchylný formát data? Koho vůbec napadlo převádět číselný řetězec na integer?
* v chybě se píše "Can't convert "2201010001" to long" . Hádám, že jde o snahu ušetřit pár bitů nebo pár řádků kódu.
Po pětisekundovém zamyšlení by přišel s tím, že když už opravdu musí převádět* řetězec na integer, mohll by aspoň záznam data začínal měsícem a ne dvojčíslím roku
Po desetisekundovém zamyšlení by přišel na to, že s měsícem na začátku to nepude sortovat. Ale ani to ale neodpovídá na otázku "Proč?". :-D
Kdyby se autor zamyslel nad limity, tak se tato chyba nestala. Realisticky vzato se programátoři jen málokdy zamýšlejí nad limity datových typů a prográmátor této funkcionality nebude vyjímka.
Nad limitem datového typu by jste se měl zamyslet (a nejlépe i ošetřit) při každé operaci s proměnnou, včetně například operace +. A řekněme si upřímě, to nedělá nikdo. Mimochodem v některých jazycích (např C a C++) není chování overflow (nebo některých typů overflow) definováno, tím se (korektní) ošetření takové situace stává docela tricky.
Souhlas - jinak na tohle je paradoxně dobré začít potenciální programátory vzdělávat na Arduinu a podobných platformách. Jelikož má Arduino int jen 2B, náráží se na omezení rozsahem poměrně často a je docela zábava sledovat, jak nechápající student dostává "naprosto nesmyslná" čísla a marně přemýšlí, kde udělal chybu, protože opravdu musí svému kódu rozumět a nemůže se spoléhat na debugger, výjimky apod...
Zrovna nedávno jsem zadával úlohu na kreslení kurzoru (křížku) na malém oled displeji podle naklonění joysticku. Analogový vstup je 10bitový, displej má šířku 128 px, takže klasická trojčlenka na přepočet výchylky na pixely analogRead(A0)*127/1023 dává parádně nesmyslné výsledky, pokud se nepřetypuje aspoň jeden argument na long :-).
A nebo na nejakem plne 32 bitovem processoru - treba Texas DSP TMS320C3x:
sizeof(char) = sizeof(short) = sizeof(int) = sizeof(long) = 1, ale to 1 je 32 bitu :-)
Takze clovek si pak do char ulozi 16milionu, a kupodivu to pak i nazpet precte!
To pak cloveka rychle prejdou takove manyry jako pretypovavat char[] na int * .....
4. 1. 2022, 10:24 editováno autorem komentáře
Jenže tohle je docela běžně používaný formát: YYMMDDHHMM.
Výhoda je v tom, že se podle něj dá řadit a je snadné a rychlé z něj vytáhnout jednotlivé části i bez znalosti přestupných roků a podobných věcí. Při použití UNIX time sice řazení funguje také, ale pro filtrování se člověk neobejde bez použití knihoven. A i zdánlivě triviální operace jako "který to byl měsíc" je ve skutečnosti výpočet na docela dlouho. Rozhodně ne pár řádků kódu, spíše pár stovek. Zkuste si třebas napsat vlastnoručně jak z UNIX time získat informaci, zda jde o datum v květnu (pátém měsíci).
Pokud potřebujete řadit a filtrovat obrovské množství dat na podmínky typu "rok 2021" nebo "květen", pak použijete právě něco jako je YYYYMMDDHHMMSS.
I když, popravdě jsem se už dlouho nesetkal s verzí YY, žil jsem v domění, že pár desítek let se používá jen YYYY.
PS: Víte, že MS Office má zabugované ukládání datumu jako čísla? V jejich verzi je rok 1900 přestupný a tudíž existuje datum 29.2.1900. A to by si člověk myslel, že na "počet dnů od 1.1.1900, včetně" nejde nic pokazit :-)
A to unix time ještě neumí vyjádřit libovolný čas a naopak mohou v budoucnosti existovat hodnoty, které budou neplatný unix time – protože unix time nepočítá s přestupnými sekundami. Takže pro vážnou práci s časem je to vlastně dost nevhodná reprezentace.
U toho přestupného roku 1900 v Excelu je to ještě zajímavější – ta chyba je v Excelu záměrně, kvůli kompatibilitě s Lotus 1-2-3.
> i zdánlivě triviální operace jako "který to byl měsíc" je ve skutečnosti výpočet na docela dlouho. Rozhodně ne pár řádků kódu, spíše pár stovek.
Triviální operace to není, ale stovky řádků snad nezabere...
Unix time je naprosto triviální, protože nemá přestupné sekundy.
A přestupné roky lze řešit tak, že se počítá v 400letých cyklech a celý timestamp se posune tak, aby první den v "roce" byl 1. březen (pak vychází poslední den v přestupném "roce" na 29. únor). Je to trik použitý v mnoha knihovnách a je to naprosto triviální naprogramovat (celá dekompozice je pak na pár řádků a je i úžasně rychlá, protože i když je timestamp 64-bit, tak ten 400letý cyklus se vleze do 32-bit).
Plně souhlasím. Navíc není větší frustrace než když vám pár hodin po novém roce začnou volat klienti, že se jim zřejmě nabořil Exchange a že něco neběží jak má. Google v té době také ještě nic neznal. Naštěstí to brečelo do logu ohledně convert to long ,tak, že mne napadlo antimalware filtr vypnout a mailflow se obnovil. Bylo třeba to vypnout na všech 2016 a 2019 Exchange, tedy tento problém někdo zanesl do Exchange ne zas tak dávno. Skvělý dárek k novému roku od MS. Už se těším na prohlášení od Microsoftu že na Exchange online tento problém potají již opravili a že je to důvod k migraci k nim. :)
Je to taková školácká chyba. Spíš mě překvapuje, že přelom roků nemají v testech, protože toto by vyplynulo. Číslování verzí tímto způsobem se dělává, je lidsky čitelné a zároveň po převodu setřiditelné. Ostatně, v DNS se zóny verzují podobným způsobem. Problém je převod na int32.
Já si matně vzpomínám, že na toto "přetečení" bylo upozorňováno v době, kdy se řešil fenomén Y2k. Tehdy se nám to ještě zdálo daleko a od té doby se na to zapomnělo.
Koukam ze indicti mistri neradi jenom v MS, ale Xilinx (ted pod AMD) se taky povedl :P
https://www.reddit.com/r/FPGA/comments/rut1dz/vitis_hls_20201_error/