Jump to content

script [inc] ReturnDate


NeoRevCrew

Recommended Posts

ReturnDate

Převod časové známky na datum

 

​Zdravím, rád bych vám představil moji verzi převodu timestampu na datum - ReturnDate.

​Předem bych chtěl skutečně poděkovat za pozornost a trpělivost při čtení tohoto dlouhého příspěvku, snažil jsem se zkrátit jej co nejvíce to jen šlo tak, aby to bylo pochopitelné a mělo to hlavu a patu.

​V případě problémů či potřeby rady se nebojte mě kontaktovat zde či prostřednictvím SZ.

 

Soubor ke stažení zde.

 

 

Proč jsem udělal vlastní verzi?

Vyvíjím vlastní mód, kde krom pluginů nepoužívám cizí funkce, vždy se snažím udělat vše po svém tak, aby to bylo rychlejší a pokud možno tak i zatěžovalo míň RAM či CPU než verze z internetu.

Je sice pravda, že já testuju funkce v cyklu opakující se 1.000.000x (abych zajistil rozdíly) a v praxi se vyvolá tak jedou, možná 2x 3x, ale nemění to nic na tom, že kód musí být nepřehledný a zbytečně komplikovaný, když to jde jednoduše.

V tomto případě jsem se po zkušenostech a používání funkcí TimestampToDate a 'date', které mi často ukazovaly trochu jiný datum než měly, že udělám vlastní převod na datum.

 

Jaký je rozdíl mezi původními a touto verzí?

​Tato verze nepoužívá zbytečně dvourozměrné proměnné (do kterých se ukládá 12 měsíců, ke každému 2 možné počty dní v měsíci a časová známka) jako je tomu u původních verzí.

​Dalším a hlavním rozdílem je to, že se časová známka nebere od 1.1.1970 00:00:00, ale od předem nastaveného začátku roku.

​Například první registrovaný hráč X bude dne 12.1.2017 (čas není důležitý) a vím, že server nebude už ukládat žádná starší data, ale vždy už jen novější (později registrovaní, timeban,..).

​Proto v includu nastavíme FYear jako 2017; FStamp jako časovou známku pro půlnoc 1.1.2017 (možné získat ZDE, je potřeba k výslednému timestampu přičíst 7200 -> 2 hodiny, SEČ).

 

Při vyvolání funkce se jakoby už přeskočí k té zadané části, kterou je v tomto případě začátek roku 2017 a pokračuje už výpočet ze zbylé časové známky.

Prvně se začne cyklit odčítání roku (pokud je minimálně 1 rok k dispozici), dále pokračuje na zjištění měsíců (v tomto kroku není udělaný cyklus, ale jelikož víme, že už zbývá 12 měsíců tak je po jednom prověříme, pokud se zjistí, že už není další k dispozici, přeskočí se na klasické cykly, které dopočítají dny, hodiny, minuty a zbytek jsou sekundy.

 

Výhody a nevýhody?

​Výhodami této verze je rychlejší provedení a menší využití paměti RAM.

​Nevýhodou je, že funkce nezjistí starší data než od definovaného v includu (čímž se vlastně zajistí to rychlejší provedení). 

 

​Test rychlosti

​Porovnal jsem rychlost všech 3 funkcí v cyklu 1.000.000 - ReturnDate, TimestampToDate a date.

ReturnDate:        1749 |  709 |  1809 ms (průměr:  1423 ms)
TimestampToDate:   3568 | 2167 |  3454 ms (průměr:  3063 ms)
date:             37637 | 9752 | 37344 ms (průměr: 28245 ms)

​Shrnutí funkce

​Abych tedy shrnul použití této funkce.

​Přidejte soubor returndate.inc do složky pawno\include.

​V souboru dle vlastních potřeb upravte FYear a FStamp.

​FStamp si můžete obstarat ZDE, zadáte jako datum 1.1. (rok podle FYear) - čas 00:00:00.

​Z timestampu, který vám vygeneruje musíte odečíst 7200 (to jsou 2 hodiny, kvůli SEČ).

​Výslednou hodnotu nastavíte k definici FStamp.

 

Příklad, jak získat FStamp a FYear je zde.

Edited by NeoRevCrew
  • Líbí se mi to! (+1) 4
Link to comment
Share on other sites

  • Globální moderátor

Zajímavý koncept. Přiložíš ještě kód k benchmarku?

 

Každopádně pár připomínek:

 

1) např rok 2100 rozhodně není přestupný, ale je dělitelný 4. (Sice se toho nedožije naše generace, ale bylo by fajn si ujasnit, co přesně ten přestupný rok je)

A year is not a leap year if it's NOT divisible by 4, OR if it's divisible by 100 AND NOT divisible by 400. 

 

2) 

while(py > 3) //Každé 4 roky přidá 1 den
{
	rday++;
	py -= 4;
}

Tohle je basically matematická operace dělení, stejný output je rday = py / 4;

 

3) goto je opravdu prasárna, celý ten koloběh ifů se dá přepsat do cyklu

4) ty while těch dnů/hodin/minut/(sekund) se dá také přepsat do dělení (+ modulo)

5) Proč se odečítají 2h? 

6) Jaký smysl má odečítat v první iteraci 366 dní?

new py;
if(ts > 31535999) // 365dní
{
    /*...*/
    py++;
    if(py == 1)
    {
	 if(ts > 31622399) // 366dní
	 {
	     py = 0;
	     ryear++;
	     ts -= 31622400;
	 }
    }
}

Jinak hezká práce

  • Líbí se mi to! (+1) 1
Link to comment
Share on other sites

Kontaktovat ta cez SZ? wat
načo taky prispevok vobec?
Treba napisat dobry kod a nemusel by si to vysvetlovat. Inak sa na to nikto ani nepozrie nie uz to rozmyslat nad tym ako si to spravil. :d;)

Link to comment
Share on other sites

S dovolením, prvně se vyjádřím k Tangovi.

​A proč ty píšeš takový příspěvěk? Ano, ty jsi třeba génius, kterýmu to hned dojde, ale může tu být někdo, kdo tomu třeba hned neporozumí a tak mu mile rád (třeba za nějakou dobu, kdy se podle pravidel, mám ten pocit 30 dní+, nemá do diskuze zasahovat) poradím. Já sám jsem timestamp pochopil až po půlroce (jsem blesk no, ale bohužel jsem tomu prostě nerozuměl hned icon_cry.gif), co jsem se začal učit s pawnem, a teprve loni jsem se po hodně dlouhé době rozhodl s tím zkusit pracovat. Takže sice ty bys to napsal tak geniálně, že by to každý pochopil, já bohužel ne, proto jsem napsal, aby mě kontaktovali do SZ. icon_e_wink.gif Myslím, že tvoje reakce vůbec nemá smysl v tomto případě, protože se nevyjadřuješ k obsahu, ale pouze se snažíš za každou cenu si rýpnout.

 

HighPrinte, tobě mockrát děkuju za takovou reakci, přesně v něco takového jsem doufal, že se najde někdo, kdo případně mě upozorní na nějaké nedomyšlené či špatně promyšlené kousky. 

Pokusím se reagovat podle tvé osnovy:

 

1) O tomto jsem nevěděl, protože takový rok už jsem nezkoušel. Testoval jsem roky 2006 - 2028, takže jsem neměl tušení. Děkuju - napravím.

 

2) Kód jsem dělal včera ve vedru a měl jsem přepařený mozeček (je mi jasné, že to neomlouvá), byl jsem rád, že jsem vymyslel ten cyklus, i když jsem věděl, že to půjde i líp, ale zapomněl jsem na to. Děkuju - napravím.

 

3) Vím, že if + goto má stejný význam jako cyklus, nechtěl jsem ho ale použít a dělat kontroly, které jsem měl pocit, že by ubraly na rychlosti (ale netestoval jsem, takže otestuju a popřípadě zkusím vymyslet lépe).

 

4) S tím modulem jsem pracoval pouze jednou a to když jsem to nedávno zkoušel. Proto jsem se neodvážil do toho vůbec jít, každopádně věřím, že by to mohlo být ještě o něco rychlejší.

 

5) 2 hodiny se odečítají z důvodu středoevropského času. Docílí se u funkce tak vždy aktuálního času.

 

6) Při prvním testu mělo hodně vliv na výsledné datum, když se změnila podmínka if(py == 1) až po if(py == 4). Původně šlo o přestupný rok, jenže tam pak na mě byla nějaká zrada a udělal jsem to takhle. Ještě na to mrknu.

 

Kód, se kterým jsem to testoval zkusím najít, 2 testy byly totiž prováděny na localhostu (1. a 3.), 2. na serveru.


UPDATE 1.1
Drobný update, odrážející se především ve zrychlení funkce (z průměrné rychlosti 1423 ms zlepšeno na 978 ms).
 
Úpravy se týkaly pouze změny výpočtu hodin, minut a sekund a úprava kontroly měsíců.
Opět test rychlosti opakující se 3x s cyklem 1.000.000:
ReturnDate: 994 | 972 | 967 ms (průměr: 978 ms)

Abych se ještě vrátil k diskuzi výše:

 

- Změna cyklu při přičítání 1 dne každé 4 na výše zmíněný výpočet nefunguje tak zcela přesně (v dalších letech je ztráta 1 dne, testován rok 2037).

 
- Situace, kde se odečítalo 366 dní byl vlastně původem přestupný rok s tím rozdílem, že se prováděla kontrola k nejbližšímu přestupnému roku - původně mám pocit tam byla ztráta prvně po 4 poté po 2 a poté po 1 roce.
Když jsem podmínku změnil na if(py == 1) a přidal cyklus pro přičtení dne každé 4 roky už nebyla žádná ztráta.
 
- Dále jsem zkusil dle HighPrintova nápadu změnit kontrolu měsíců přes cyklus, kde se ovšem funkce mírně zpomalila (průměr: 1137 ms).
Edited by NeoRevCrew
Link to comment
Share on other sites

OK, neda mi nepozriet to teraz... :d Hlavne sa nenechaj odradit od Pawn tym co som napisal.. Proste, tje jedno. Neberte to tak važne.
Kod som pozrel, nechapem z toho nič, ale to bude tym ako timestamp funguje plus tym tvojim optimalizačnym riešenim.

 

Tak ak chceš, možem ti aspon poradit co by som tam zmenil ja...
Pozrel som ten tvoj kod, a tiez ten z odkazu co si dal, tipujem ze tym nekonecnym cyklom si sa inspiroval odtial... Ten kod co tam chlapik dal je tiež nejaky podozrivy.. Nerozumiem mu teda, ale

Timestamp -= 172800; // Delete two days from the current timestamp. This is necessary, because the timestamp retrieved using gettime() includes two too many days.

wat

@Highpritn :d to s tymi dvoma hodinami :d shet :d skoro mi pri tom zhorel mozog, ale uz viem :d
Čo je unix timestamp: kolko sekund ubehlo od 1970-01-01T00:00:00 GMT

U nás však 01.01.2017 00:00:00 nastalo kvôli časovému posunu o dve hodiny skorej než v Greenwichi, a teda "náš" timestamp stihol napočítať o dve hodiny menej oproti nejakému na kompe v Greenwichi. :)

(GMT) 01.01.2017 00:00:00 = 1483228800
(MY)    01.01.2017 00:00:00 = GMT - 2 hodiny = 1483228800 - 7200 = 1483221600

Je to potrebné odpočítať teda preto, lebo tipujem autor dal vypočítať cez online kalkulačku dátum 1.1.2017 a len pre GMT. Keby v tej kalkulačke našiel naše časové pásmo, rovno mu ukáže náš dátum a netreba nič odčitovať.
zo zvyškom čo pišeš suhlasim
 

No a čo by som ti/autorovi poradil, #define pisat vzdy s velkymi pismenami. Robi sa to tak vzdy a vzdy sa to tak aj robilo. Lahsie sa to cita. Tiez by som nepomenovaval tie #define rovnako ako premenne.
A tiež nepouživat goto, next, break, atd. Samotne použitie takychto konštruktcii spomaluje celkovu rychlost vykonania kodu kvoli branch prediction (podobny pripad, hlavne mad obre vysvetlenie). Ale to nei je podstatne. Hlavne sa to zle číta, lebo musíš hladať kde to začína a končí. Tiež switch je rýchlejší než ify.

Na druhej strane viem, že najrýchlejší kód je vždy najmenej čitatelný.

Inak teda priznavam, nemam šajnu čo sa v tom kode deje a netušim čo su tie magicke čisla. Do buducna, piš komentare. ;)
Evidentne sa totiž chceš pochváliť svojim kódom, tak musíš aj zariadit, že ten kod je to čo nas zaujme. A dobry kod je ten, ktory ma komentare.
A tiež teda chvalim napad.

Link to comment
Share on other sites

Od pawna se odradit nenechám, tak nějak svým tempem již pár let tomu snažím věnovat.

 

Jednak ti děkuju za takovou reakci.

Co se té inspirace týče, tak původně ne, až ta podmínka kontrolující 366 dní, pak jsem zjistil, že to mám jak v originálu.

Ono totiž ze začátku celá tato funkce vypadala úplně jinak, ale postupně jsem vše upravoval a vznikl z toho současný výsledek.

 

Ano, dělal jsem to přes online kalkulačku na GMT, protože je na netu plno takových, kde se různě nastavuje a nechtěl jsem si dovolit chybu.

 

Definice nepoužívám, v tomto případě šlo o zjednodušení úpravy ostatním, co by nemuseli vědět kde, co a jak přepsat. Každopádně definice nemají stejné názvy jako použité proměnné.

 

Právě já jsem zkusil nahradit if+goto cyklem, ve kterým byl i switch na daný měsíc, ale vždy se při testu dostala rychlost nad 1100 ms, kdežto současná verze okolo 950 ms. V módu používám především switche, if vždy na ojedinělé případy, ale zde to na rychlost opravdu polepšilo stylu if + goto. V includu komentáře byly, ale mám pocit, že ve verzi 1.1 jsem je neměl. Ale nejspíš to nebylo poslední vylepšení funkce, vždy se něco najde, takže pak dodám.

Link to comment
Share on other sites

Je fajn vidiet, ze sa kladie doraz na optimalizaciu, rozhodne v tom pokracuj.

 

Co sa tyka komentarov, zvycajne zhrniem cely priebeh algoritmu v 2-8 vetach a dalej to neriesim. Preferujem vidiet API priamo, taktiez neuznavam komentovanie takmer kazdeho kroku (stare M2MP toto robilo, komentar skoro za kazdym riadkom, aj pri jasnych krokoch). Co sa tyka samotnej dokumentacie, mam zmiesane skusenosti, moze to byt dobra vec, ak maintainer nezabudne dokumentaciu aktualizovat (v opacnom pripade vznikne kolizia s realitou a robit s API, ktora nema jasne pouzitie, nikto veru nechce). Nepozeral som tvoj kod, cize ide len o hint.

 

Suhlasim s konstantami na "magicke" hodnoty, ale len pri takych kde je nazov vseobecne znamy, napr. statisticke hodnoty by som nechal v povodnom stave. To ale aj zalezi na frekvencii pouzitia konstanty, ak sa casto opakuje, tak logicky si zavediem makro/konstatnu premennu.

Link to comment
Share on other sites

  • Globální moderátor

Jo dobrá poznámka... ještě uveď příklad použití, aby lidi co nechtěli zkoumat kód věděli jak se to používá. 

 

@Tango aha, díky :d ty dvě hodiny jsem nechtěl zjišťovat, dobrá informace

 

 

 

Změna cyklu při přičítání 1 dne každé 4 na výše zmíněný výpočet nefunguje tak zcela přesně (v dalších letech je ztráta 1 dne, testován rok 2037).

 

Na tohle bych se rád mrknul, jestli bys mi poslal ten timestamp do SZ :) 

Link to comment
Share on other sites

UPDATE 1.2 - DŮLEŽITÉ

​Zdravím, dnes jsem se opět dostal k počítači a chtěl ještě dovést tento include k ještě větší "dokonalosti", než tomu bylo doteď.

​Dělal jsem test počátečních roků (od kterých funkce počítala) 2006 - 2017 a zjistil jsem (bohužel až nyní), že každý přestupný rok má o 1 den více (pokud byl počáteční rok nastavený před rokem 2013).

​V této verzi je již tato chyba opravena a obsahuje další úpravy:

 

- Upravená kontrola přestupného roku (na základě poznámky od Printa),

​- upravený výpočet dní,

- upravený výpočet roků (změněný cyklus).

 

Tato verze je samozřejmě opět rychlejší, než dosud vydané verze 1.0 a 1.1.

Nyní průměrná rychlost při cyklu 1.000.000 je 555 ms.

Aby bylo možné zajistit rozdíl mezi verzemi 1.1 a 1.2 jsem již musel použít cyklus opakující se 5.000.000x, kde byla verze 1.2 rychlejší o něco málo přes 1600 ms (1.1: 3815 | 1.2: 2168).

 

Současná verze by již měla být bez jakýchkoliv bugů.

Edited by NeoRevCrew
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...