Računari 94

Strogo po kalendaru

Da li vam je nekada zatrebalo da odredite u koji je dan pao neki događaj, koliko je vremena proteklo između dva datuma, kada će tačno isteći prvih 100 dana neke vlade ili, uopšte, da obavite neku kalendarsku čaroliju?

Dejan Ristanović

Ako pišete poslovni softver, sigurno jeste, a sigurno je i da ste se snašli i napisali neki manje ili više složen program koji je "obavio posao". Ovim tekstom ćemo pokušati da "za svagda" rešimo probleme koji se javljaju pri radu sa datumima, da predstavimo potprograme koje ćete docnije moći da ugrađujete u vaša remek dela uz sigurnost da će korektno tretirati sve datume koje im "podmetnete" i, što će možda mnoge zanimati, da objasnimo kako sve to radi i zašto je baš tako!

Kada bismo imali dobar kalendar, pitanja kojima se bavi ovaj tekst se ne bi ni postavljala - svaki bi mesec imao jednak broj dana, prvi u mesecu bi iz godine u godinu padao na isti datum pa bi malo pamćenja rešilo sve probleme. Međutim, kalendar je takav kakav je, pa su se pitanja tipa "u koji je dan pao 19. novembar 1825. godine" itekako postavljala i rešavala raznim metodama. Ti metodi su se uglavnom zasnivali na složenim tabelama koje su objavljivane u knjizi zvanoj "Večiti kalendar" ("večnost" se obično tamo svodila na interval od sto ili dvesta godina) koja je dopunjavana sanovnikom, horoskopom, roždanikom i drugim glupostima tog tipa. Problem konverzije datuma mi je "konačno" rešio moj prvi računar (bolje reći programabilni kalkulator) TI-58 - prisećam se da je u njegovu standardnu biblioteku (Master Library Module) ugrađen program pomoću koga se određuje u koji dan neki datum pada i koliko je dana proteklo između dva datuma. Naprosto otkucate 1119.1825, izaberete PGM 20, pritisnete taster na kome piše slovo D, sačekate trenutak i... eto dana! Inverzna funkcija nije podržana ali je i ovo bilo sasvim dovoljno da fascinira svakoga kome pokažete kalkulator.

Znatno bolji program koji obavlja isti posao dobio sam u svojim HP-41C danima, pošto sam kupio ROM američkog PPC kluba - u njega su ugrađeni programi CJ i JC koji konvertuju datum u referentni broj ali i referentni broj u dan, mesec i godinu. Programi su, kao uostalom i čitav PPC ROM, pravo malo čudo optimizacije i godinama su mi zamenjivali kalendar - i dan danas ću, ako mi treba da proverim u koji dan neki datum pada, uključiti HP-41CV. U međuvremenu sam pregledao brojne biblioteke matematičkih i poslovnih funkcija raznih računara i kompajlera i pronašao najrazličitije algoritme za rešavanje problema - ima ih boljih i gorih, pouzdanijih i manje pouzdanih, sporijih i bržih... u svoje programe već godinama ugrađujem iste procedure koje sam, uglavnom po ugledu na PPC ROM, napisao još davne 1985. godine, najpre na bejziku a docnije na paskalu, C-u, Clipper-u... Da bi se ove procedure kreativno primenile potrebna je, naravno, određena teorijska podloga koju ćemo ovde pokušati da izložimo.

Referentni broj datuma

Rad sa datumima se zapravo zasniva na dve osnovne operacije. Prva je pretvaranje datuma (zadatog u obliku datum/mesec/godina) u referentni broj tj. izračunavanje broja dana koji su protekli između nekog nultog trenutka u istoriji i zadatog datuma. Druga operacija je inverzna - za zadati referentni broj treba odrediti datum, mesec i godinu koji mu odgovaraju. Recimo da je nulti trenutak istorije 1. septembar 1993. godine i "posmatrajmo" neke realne datume. Referentni broj samog 1. septembra 1993. biće 0, referentni broj 2. septembra 1993. će biti 1 a, recimo, 15. septembra 1993 biće 14. Sada nas zanima koji će datum biti 10 dana posle 15. septembra 1993. Izračunaćemo referentni broj 15. septembra (14), zatim mu dodati 10 (24) i onda za taj referentni broj izračunati datum, mesec i godinu - dobićemo 25. septembar 1993. Što se dana u nedelji tiče, potrebno je da znamo u koji je dan pao nulti datum - recimo da je on pao u sredu. Tada je dovoljno da odredimo ostatak pri deljenju referentnog broja za 7 (14 mod 7 = 0) i dodamo taj broj na sredu - dobijamo da je 15. septembar pao takođe u sredu.

Ostaje još da kažemo koji je to nulti trenutak istorije opšte usvojen i kako se izračunava referentni broj ostalih datuma. Nulti trenutak koji su astronomi usvojili, začudo, nije 1. januar 1. godine nego podne 1. januara 4713. godine pre nove ere - ovakav sistem je predložio je 1582. godine Joseph Justus Scaliger i od tada je u upotrebi. Referentni broj datuma računat u odnosu na ovaj trenutak se u literaturi obično naziva JDN što je skraćenica od Julian Day Number; mi ćemo koristiti termin "referentni broj" ili skraćenicu RB kako bismo izbegli mešanje ovog datuma i julijanskog kalendara o kome ćemo nešto kasnije govoriti.

Odluka da se za nulti trenutak usvoji podne a ne ponoć je u najmanju ruku neusklađena sa našim uobičajenim poimanjem vremena. Pa ipak, razlozi za nju su čisto praktične prirode - većina astronomskih posmatranja se odvija tokom noći a promena datuma usred eksperimenta unosi konfuziju u dalja računanja. Pa ipak, ova konvencija ne predstavlja poseban problem u praktičnim (a pogotovu programerskim) primenama pošto u svim proračunima radimo sa čitavim danima a ne njihovim delovima. Ukoliko, međutim, poželite da odredite RB nekog sekunda, moraćete da uzmete u obzir i ovu astronomsku začkoljicu.

Iako smo fiksirali nulti trenutak, još ne možemo da pređemo na algoritam za računanje referentnog broja. Problem je u tome što taj broj neposredno zavisi od korišćenog kalendara, a kalendar se kroz istoriju više puta menjao zbog različitih tumačenja pojma "godina". Obično se, naime, smatra da Zemlja obiđe Sunce za 365 dana koliko traje kalendarska godina. Ukoliko malo bolje razmislite, setićete se i prestupnih godina - zašto svaka četvrta godina ima dan više? Odgovor znate: zato što Zemlja obiđe Sunce za 365.25 dana što znači da se posle svake četiri godine pojavi "greška" od jednog dana koju treba korigovati. Kada bismo zaboravili na prestupne godine, praznik Nove godina bi se postepeno pomerao prema jesenjoj ravnodnevici pa bi za 500 godina prvi januar bio jedan od najtoplijih dana leta!

Astronomi su još u doba starog Egipta uočili ovu anomaliju pa su uvedene prestupne godine - kalendar kod koga je svaka četvrta godina prestupna nazivamo julijanskim po Juliju Cezaru koji ga je uveo 46. godine pre nove ere (više o tome nešto kasnije). Ovaj kalendar, međutim, i dalje nije dovoljno tačan - periodi rotacije Zemlje oko sopstvene ose i revolucija oko Sunca nisu međusobno povezani pa bi bilo prilično čudno da je drugi tačno 365.25 puta veći od prvog. Zemlja se, zaista, ne okreće oko Sunca za 365.25 dana već za nešto manje; razlika je, doduše, mala ali se iz godine u godinu kumuliše pa se praznik Nove godine pomera prema prolećnoj ravnodnevici što znači da bi pre ili posle prvi januar pao u proleće a docnije i u leto. Srednjevekovni astronomi i astrolozi su primetili ovu anomaliju i, često ne shvatajući njene uzroke (tada se smatralo da Sunce obilazi oko Zemlje!), uvideli kuda ona vodi pa su se pojavili predlozi za reviziju kalendara. Iako je nesaglasnost julijanskog kalendara sa prirodom bila nesumnjiva čak i u to vreme, nije se bilo lako odlučiti za promenu kalendara zbog poznate "socijalne inercije" naroda. Papa Grgur XIII je "presekao čvor" i proglasio da posle četvrtog nastupa petnaesti oktobar 1582. godine, čime je anulirana greška koja se akumulisala za prethodnih 1500 godina. Da bi buduća pokoljenja oslobodio sličnih konfliktnih situacija, Grgur XIII je (sledeći savete svog astronoma Luiđi Lila (Luigi Lillo)) odlučio da godine kojima se završavaju vekovi budu prestupne samo ako je njihov broj deljiv sa 400; tako će 2000. biti prestupna dok su 1900, 1800. i 1700. bile proste godine! Ovaj kalendar se naziva gregorijanskim, mada treba znati da Grgur XIII nema previše zasluga za njegov nastanak - veći deo posla obavljen je za vreme pontifikata Pija V, koji je inicirao reformu kalendara ali je umro pre nego što je posao završen.

Iako je Papin autoritet bio nesporan, promena kalendara nije "tek tako" prošla: pojavila su se milionska udruženja koja su tražila da im se "vrati njihovih deset dana" a bilo je i relativno ozbiljnih sukoba i nemira. Gregorijanski kalendar je, ipak, postepeno prihvatan u raznim državama - u britanskim kolonijama (npr. današnjim Sjedinjenim Američkim Državama) prihvaćen je 2. septembra 1752 (posle 2. nastupio je 14. septembar) tako da ćete često naći različite podatke o pojedinim istorijskim ličnostima (Džordž Vašington je rođen 11. februara 1732. ali je ovaj datum izražen u julijanskom kalendaru pa se njegov rođendan obeležava 22. februara; negde ćete naći i podatak da je rođen 11. februara 1731, pošto je u Britanskim kolonijama tog vremena Nova godina počinjala 25. marta, što je još jedna interesantna anomalija o kojoj treba voditi računa). Neke druge države su prihvatile gregorijanski kalendar znatno kasnije, pre svega pod uticajem Pravoslavne crkve koja nije prihvatala čak ni matematički zasnovane Papine naredbe. U Rusiji je gregorijanski kalendar prihvaćen tek u ovom veku, a ni mi nismo bili bolji - gregorijanski kalendar je u Jugoslaviji (koja se tada zvala Kraljevina Srba, Hrvata i Slovenaca) prihvaćen tek 19. januara 1919. - taj dan je ukazom proglašen za 31. januar. Poslednja moderna država koja je prihvatila gregorijanski kalendar je Turska (1927. godine), mada neki smatraju da je to Rusija koja se u vreme između dva svetska rata vraćala na julijanski kalendar, da bi najzad ponovo usvojila gregorijanski. Tačan datum prelaska na novo računanje vremena u pojedinim državama može da se nađe u knjizi Explanatory Supplement to the Astronomical Ephemeris and the American Ephemeris and Nautical Almanac iz 1961. godine, strana 414.

Julijanski kalendar se kod nas održao i do današnjih dana pod imenom "Stari kalendar" - Nova godina po ovom kalendaru pada 14. januara. Treba da razumemo da razlika nije u tih četrnaest dana: 2101. godine će se povećati na petnaest, 2201. na šesnaest i tako dalje - za nekih 47,000 godina će se napraviti pun krug pa će se prvi januari julijanskog i gregorijanskog kalendara poklopiti s tim što će se oznaka godine razlikovati za jedan!

Bilo koji datum u istoriji sveta ima svoj jedinstveni referentni broj - RB datuma izlaska ovih "Računara" je, na primer, 2,449,232. Datum koji pridružujemo tom referentnom broju, međutim, zavisi od kalendara - ako se služimo julijanskim, taj dan će se "zvati" 19. avgust a po gregorijanskom 1. septembar 1993. godine.

Završavajući ovu diskusiju, reći ćemo da ni kalendar koji danas koristimo nije naročit. Period revolucije Zemlja oko Sunca se, pre svega, danas može izmeriti daleko preciznije što znači da konstatovana razlika između kalendarske i realne godine postoji i da se stalno akumulira - 4905. godine pojaviće se razlika od jednog dana tako da je moguće da 4904. godina ne bude prestupna kako bi se ta razlika uklonila. Postoji i predlog po kome bi godine kojima se završavaju milenijumi bile prestupne samo ako su deljive sa 4000, koji bismo mogli da "osetimo" već 2000. godine koja, po tom predlogu, ne bi bila prestupna! Osim što je pogrešan, kalendar je krajnje nepraktičan: dužine meseci su različite, prvi u mesecu ne padaju uvek u isti dan, kalendar se iz godine u godinu pomera za jedan ili dva dana... Promene kalendara su danas u nadležnosti Ujedinjenih nacija koje, verovatno imajući u vidu teškoće sa kojima svet prima novitete, već dvadesetak godina ne mogu da usvoje novi sistem računanja vremena.

Uz malo matematike...

Pređimo na algoritam računanja referentnog broja. Za početak ćemo pretpostaviti da svaki februar ima po 30 dana i nazvati svaku godinu proisteklu iz te pretpostavke "proširenom godinom" od 367 dana. Pretpostavimo, dalje, da ta proširena godina počinje 1. marta i završava se 30. februara. Ako "pravi" datum obeležimo sa DD, "pravi" mesec sa MM a "pravu" godinu sa YY i izračunamo y=YY+(MM-3)/12, pokazaće se da ceo deo broja y predstavlja oznaku odgovarajuće "proširene godine" a razlomljen deo broj meseca u njoj. Posmatrajmo sada broj z=367*INT(y) + 367*FRC(y). Prvi sabirak označava 367 dana proširene godine a drugi uzima vrednosti takve da se dodavanjem bilo kog broja p iz intervala [7/12, 8/12) na njih dobija (posle odbacivanja decimala) stvarni broj dana protekao od početka godine do početka zadatog meseca. Prema tome, broj INT(367*y+p) daje broj dana koji prethodi zadatom datumu u zadatoj godini, naravno uz pretpostavku da su sve godine "proširene" na 367 dana.

Da bismo prešli na prave godine, treba proširenima oduzeti 1 dan ako su prestupne i 2 dana ako su proste. Oduzimanje broja 2*INT(y) se brine o tome, ali posle toga treba dodati INT(y/4) da bi se uzele u obzir prestupne godine. Korekcija koju uvodi gregorijanski kalendar zahteva da se od dobijenog broja odbije INT(y/100) a zatim doda INT(y/400). Tako dobijamo broj dana protekao između DD/MM/YY i 1. marta 0-te godine (nulta godina je ovde čista fikcija, pošto je pre 1 godine nove ere bila 1 godina pre nove ere; ipak, ova fikcija olakšava računanje pa je i mnogi astronomi primenjuju) dok za dobijanje "pravog" referentnog broja treba dodati referentni broj pomenutog 1. marta. Njega uzimamo iz tablice i dobijamo formulu RB = INT(367*y+p) - 2*INT(y) + INT(y/4) - INT(y/100) + INT(y/400) + DD + 1721119.

Formula se može malo "srediti" izborom pravilnog p kako bi se umanjile numeričke greške i ubrzalo računanje. Ne upuštajući se neposredno u to "sređivanje" koje, uz malo pažnje, može da izvrši svaki matematički nastrojen čitalac, dajemo konačnu formulu:

RB = INT(INT(INT(367*y') - INT(y') - 0.75*INT(y') + DD) - 0.75*INT(y'/100)) + 1721115

gde je y'=YY+(MM-2.85)/12. Kada se radi sa julijanskim kalendarom, INT(y'/100) treba zameniti brojem 2 što se zasniva na činjenici da kalendari poklapaju tokom prvih godina nove ere. Funkcija DAT2RB sa slike 1 omogućava izračunavanje referentnog broja za zadati datum.

Inverzna operacija je za nijansu složenija. Najpre ćemo od zadatog RB oduzeti 1721119 i tako dobiti N, broj dana proteklih od 1. marta 0-te godine do zadatog dana. Srednja dužina gregorijanskog veka je 36524.25 dana dok je broj gregorijanskih vekova protekao između tekućeg datuma i 1. marta 0-te godine C=INT((N-e)/36524.25) gde je e bilo koji broj iz intervala (0, 0.25]; mi ćemo uzeti e=0.2. Broj N'=N + C - INT(C/4) daje broj proteklih dana računat po gregorijanskom kalendaru dok N'=N+2 odgovara julijanskom. Dalje računanje je isto za oba kalendara, uz uzimanje ispravnog N'.

Neka su Y' i M' "pomerena" godina i mesec računate kao da godina počinje 1. marta (M'=0). Tada je Y'=INT((N'-e')/365.25) gde je e' iz istog intervala kao i e (uzećemo e'=e=0.2). Broj dana protekao od početka "pomerene" godine je N'' = N' - INT(365.25*Y') dok je M' = INT((N''-d)/30.6) gde je d bilo koji broj iz intervala (0.4, 0.6); mi ćemo uzeti d=0.5. Pošto smo izračunali ove brojeve, ostaje samo da se vratimo na "normalnu" godinu: biće DD = INT(N'' - 30.6*M' + 0.5) i za M'>9: YY=Y'+1 i MM=M'-9 a za M' manje ili jednako 9: YY=Y' i M=M'+3. Procedura RB2DAT sa slike 2 omogućava izračunavanje datuma, meseca i godine za zadati referentni broj.

U starim danima

Programe sa slika 1 i 2 možete "bezbedno" primenjivati na sve datume iz bliže prošlosti i budućnosti, naravno sve do dana kada dođe do reforme kalendara. Kada se radi o datumima iz dalje prošlosti, a naročito o prvim godinama posle Hrista, treba biti veoma oprezan. Listajući neke stare knjige primetićete neke nesaglasnosti među datumima, danima u nedelji i formula koje smo izneli. Stvar je u tome što, čitajući neku staru knjigu, obično ne čitate originalni rukopis nego ko-zna-koji-po-redu prepis i prevod - uostalom, malo je verovatno da biste se uopšte snašli sa starim pismima i jezikom. Svaki prevod unosi po neku nepreciznost, dešava se da se pri tome neki datum konvertuje na "novi sistem" ili se ne konvertuje, pa se posle desi da pri sledećem prevodu već konvertovan datum bude greškom još jednom konvertovan... za 2000 godina te greške su se "akumulisale" tako da pri tumačenju datuma iz antičke istorije treba biti veoma oprezan. Zanimljiv osvrt na tu temu objavio je 1972. godine A.E.Samuel pod naslovom "Calendars and Years in Classical Antiquity", a vredi pročitati i tekst "Calendars - the Real Story" koji je William E. Hitchins objavio marta 1982. u PPC Journal-u v9n2p36. Ovde ćemo se samo ukratko osvrnuti na nekoliko najzanimljivijih činjenica.

Bilo kakvo oslanjanje na julijanski kalendar pre 46. godine p.n.e. nema mnogo smisla - Rimljani su i tada koristili sličan kalendar (zapravo varijaciju egipatskog kalendara), ali je dodavanje "prestupnih" dana (zapravo prestupnog meseca, Intercalary) vršeno stihijski i neprecizno, što zbog neznanja, što zbog nepažnje, što iz političkih razloga (dodate godini još jedan mesec i odmah su porezi veći). Tih "političkih" promena kalendara se sakupilo toliko da je 46. godina p.n.e, po svemu sudeći, imala januar (29 dana), februar (24 dana), interkalar (27), mart (31), april (29), maj (31), jun (29), quatilis (31), sextilis (29), septembar (29), oktobar (31), novembar (29), undecembar (33), duodecembar (34) i decembar (29 dana).

Boraveći u Egiptu i "družeći" se sa Kleopatrom, Cezar je 48. godine p.n.e. upoznao astronoma Sosigenesa koji mu je predložio usvajanje fiksnog kalendara zasnovanog na egipatskom računanju vremena koje uključuje prestupne godine. Cezaru se ideja okončanja "kalendarskog haosa" dopala, pa je Sosigenes. u saradnji sa Marcusom Flaviusom, prilagodio ovaj kalendar rimskim običajima ukidajući "prestupni mesec" i raspoređujući njegove dane ostalim mesecima. Kalendar je predočen Rimskom Senatu 46. godine p.n.e. i, po usvajanju, postao je zakon. Naravno, ova godina se po tom zakonu ne naziva 46-tom godinom pre nove ere (svakom je pokoljenju njegova era "nova") već je "nulti" datum vezan za nastanak Rima i, u priličnoj meri proizvoljno, fiksiran na 753 godinu p.n.e. tako da se kaže da je julijanski kalendar stupio na snagu 1. januara 709. godine A.U.C.

Godinu dana kasnije, Senat je predložio da se mesec Quantilis preimenuje u Iulius (Jul), u slavu Julija Cezara (zbog složene birokratske procedure, ovaj predlog nije postao zakon sve do posle atentata na Cezara, 15. marta). Međutim, Cezarov kalendar u početku nije primenjivan na način koji je Sosigenes zamislio tako da je svaka treća godina bila prestupna - Senat je tada bio previše zauzet raznim političkim previranjima da bi se ozbiljnije bavio "nametanjem" kalendara lokalnim vlastima. Pošto je Oktavijan Avgust čvrsto zaseo na presto, primećena je nesaglasnost kalendara sa realnošću pa je odlučeno da između 8. godine p.n.e. i 8. godine n.e. ne bude prestupnih godina kako bi se stvari dovele u red. Dakle, 4. godina n.e. nije bila prestupna, pa naše programe sa slika 1 i 2 ne treba primenjivati na datume pre marta 4. godine - mogli smo, naravno, da unesemo i ovu korekciju ali smo smatrali da bi ona samo nepotrebno komplikovala proračune. U isto vreme, Senat je predložio da septembar bude preimenovan u avgust u slavu imperatora koji je rođen 23. septembra 63. godine p.n.e (dobro je poznat Klaudijev komentar na ovu temu "šta ćemo raditi kada se rodi trinaesti Cezar?"), ali je sam Avgust, iz razloga oko kojih se istoričari ne slažu, izabrao mesec Sextilis. Pominjenje Oktavijana Avgusta je ujedno dobra prilika da ukažemo na jednu od zabluda kojom su opterećena naša znanja o kalendaru - verovatno ste u školi učili da je Avgust, da "njegov" mesec ne bi bio kraći od "Cezarovog" jula, oduzeo jedan dan februaru i dodao ga avgustu. Teorija zvuči logično (zašto bi inače februar imao manje dana od bilo kog drugog meseca?) ali je istorijska istraživanja ne potvrđuju - dužine svih meseci su određene još u doba Julija Cezara, a februar ima malo dana zato što je smatran "baksuznim mesecom" (posvećen je nekim nižim bogovima) pa je bilo pogodno da bude što kraći. Teorija o produženju avgusta pojavila se u XIV veku i niko je nije uzimao za ozbiljno dok se, krajem prošlog veka, nije pojavila u jednom od tomova Encyclopedia Britannica odakle je prenesena u mnoge udžbenike. Redakcija ove slavne enciklopedije je početkom osamdesetih izjavila da je ova greška otklonjena u najnovijem izdanju, ali nismo imali prilike da proverimo da li je to izdanje i objavljeno.

Danas važeće imenovanje godina predložio je 532. godine kaluđer Dionysis Exiguus (poznat i pod imenom Denys le Petit) - godina Hristovog rođenja je nazvana 1. godinom A.D. a godina pre nje 1. godina B.C. Iako Exiguus u svojim proračunima nije bio baš precizan, njegovo računanje vremena je široko usvojeno, čak i u nehrišćanskim zemljama. U nekim zemljama je kasnije pokušana revizija "prve godine" (u doba Francuske revolucije usvojen je novi kalendar, a pokušaje je činio i Staljin za "Sovjetskim kalendarom") ali ni jedna od tih alternativa nije se duže zadržala na istorijskoj pozornici.

SI rođendani

Da se ovaj tekst ne bi završio potprogramima, dajemo i praktičan primer njihove primene koji će vam omogućiti da zabavite i iznenadite prijatelje. Svi oni, osim eventualno stanovnika "Alise u zemlji čuda", slave rođendan svega jednom godišnje. Ali, zašto baš jednom godišnje? Godina i nije neka jedinica za merenje vremena: videli smo da se Zemlja, ako ništa drugo, ne okrene oko Sunca za 365 pa čak ni za 365.25 dana! Sekund je, sa druge strane precizno definisana jedinica za merenje vremena koja je kao takva ušla i u SI sistem. Zašto se ređendan ne bi slavio kada se, na primer, navrši jedna gigasekunda?

Program sa slike 3 zahteva da otkucate dan, mesec i godinu rođenja, zatim preuzima tekuće vreme očitavajući PC-jev časovnik i pronalazi datum vašeg sledećeg "SI rođendana" kao i starost koju ćete toga dana navršiti. Samo se po sebi razume da računar, koga niste snabdeli podatkom o tačnom vremenu vašeg rođenja, ne može da kaže kog ćete sekunda u toku nekog dana navršiti određen broj megasekundi ali je i datum obično sasvim dovoljan. Vremena se izražavaju u megasekundama a "rođendan" nastupa kada napunite punu stotinu megasekundi - ovu smo brojku izabrali jer je gigasekund prevelika jedinica a vi svakako ne želite da rođendan slavite samo jednom u 32 godine!

Kako bi vam rođendani bili češći, program smo osposobili da izračunava i vašu starost u kilodanima - izaberite jedinicu koja vam više odgovara i iznenadite nekog prijatelja koji zasigurno nije znao da mu je baš danas rođendan!

slika 1:

{$N+E+}
PROGRAM datumi;
{

      KONVERZIJE DATUM <> REFERENTNI BROJ
    Copyright (C) 1980-1993 Dejan Ristanović
                 "Računari  94"

}

CONST gregor: BOOLEAN = true; { Staviti gregor:=false za rad
                                 sa Julijanskim kalendarom  }

{
  DAT2RB - konverzija datuma u referentni broj dana, računat od
           1. januara 4713. godine p.n.e
  ULAZ   - dd: oznaka datuma (1-31)
           mm: oznaka meseca (1-12)
           yy: oznaka godine (1-100000)
  IZLAZ  - referentni broj dana
}
FUNCTION dat2rb (dd, mm, yy: INTEGER): LONGINT;
VAR yp, temp: EXTENDED;
BEGIN
   yp:=yy+(mm-2.85)/12.0;
   temp:=INT(367*yp)-INT(yp)-0.75*INT(yp)+dd;
   IF gregor THEN
      temp:=INT(temp)-0.75*INT(yp/100)
   else
      temp:=INT(temp)-1.5;
   temp:=INT(temp)+1721115;
   dat2rb:=TRUNC(temp);
END;

{
  DAY    - određivane dana u koji pada zadati datum
  ULAZ   - dd: oznaka datuma (1-31)
           mm: oznaka meseca (1-12)
           yy: oznaka godine (1-100000)
  IZLAZ  - oznaka dana (0=nedelja, 1=ponedeljak, ..., 6=subota
}
FUNCTION day (dd, mm, yy: INTEGER): INTEGER;
BEGIN
   day:=(dat2rb(dd, mm, yy)+1) MOD 7
END;

slika 2:


{
  RB2DAT - konverzija referentnog broja dana u datum
  ULAZ   - rb: referentni broj dana, računat od
           1. januara 4713. godine p.n.e
  IZLAZ  - dd: oznaka datuma (1-31)
           mm: oznaka meseca (1-12)
           yy: oznaka godine (1-100000)
}
PROCEDURE rb2dat (rb: LONGINT; VAR dd,mm,yy: INTEGER);
VAR n,c,np,yp,npp,mp: LONGINT;
BEGIN
   n:=rb-1721119;
   c:=TRUNC((n-0.2)/36524.25);
   IF gregor THEN
      np:=n+c-TRUNC(c/4)
   ELSE
      np:=n+2;
   yp:=TRUNC((np-0.2)/365.25);
   npp:=np-TRUNC(365.25*yp);
   mp:=TRUNC((npp-0.5)/30.6);
   dd:=TRUNC(npp-30.6*mp+0.5);
   IF mp <= 9 THEN BEGIN mm:=mp+3; yy:=yp   END
              ELSE BEGIN yy:=yp+1; mm:=mp-9 END;
END;

slika 3:

PROGRAM si;
{

                  SI ROĐENDANI
    Copyright (C) 1987-1993 Dejan Ristanović
                 "Računari  94"

}

USES dos, crt;

FUNCTION st (ulaz: LONGINT): STRING;
VAR rez: STRING;
BEGIN
   str(ulaz, rez);
   st:=rez;
END;

FUNCTION datisp (d, m, g: INTEGER): STRING;
VAR rez: STRING;
BEGIN
   IF d<10 THEN rez:='0'+st(d) ELSE rez:=st(d);
   IF m<10 THEN rez:=rez+'/0'+st(m) ELSE rez:=rez+'/'+st(m);
   datisp:=rez+'/'+st(g);
END;

VAR d,m,g: INTEGER;
    msec, msled, jdr, jdk, jds, kdan, star: longint;
    dc, mc, yc, xx: WORD;
    odg: STRING;

BEGIN
   writeln;
   write ('Datum rođenja (DD): ');
   readln (d);
   write ('Mesec         (MM): ');
   readln (m);
   write ('Godina      (YYYY): ');
   readln (g);
   REPEAT
       write ('M(egasekunde) ili K(ilodani): ');
       readln (odg);
       odg:=UPCASE (odg[1]);
   UNTIL (odg='M') OR (odg='K');
   getdate(yc, mc, dc, xx);
   jdr:=dat2rb(d,m,g);
   jdk:=dat2rb(dc,mc,yc);
   REPEAT
      star:=jdk-jdr;
      IF odg='M' THEN
      BEGIN
         msec:=TRUNC(0.0864*star);
         msled:=TRUNC(msec/100.0+1.0)*100;
         jds:=TRUNC(msled/0.0864)+jdr;
      END
      ELSE
      BEGIN
         kdan:=star div 1000;
         msled:=kdan+1;
         jds:=msled*1000+jdr;
      END;
      rb2dat (jds, d, m, g);
      write ('Sledeći SI rođendan (', msled);
      IF odg='M' THEN write (' Ms): ') ELSE write (' Kdana): ');
      writeln (datisp (d,m,g));
      writeln ('Enter za sledeći rođendan, Esc=kraj');
      jdk:=jds+10;
   UNTIL readkey=#27;
end.