Szükségem volt egy óra programhoz arra, hogy a dátum alapján kitalálja magának a program a hét napját, és ne kelljen azt is beállítani, mint a legtöbb buta digitális órán. Azt, hogy miképpen kell ezt megcsinálni, gyorsan találtam ötletet a neten. Még program forrást is találtam, de hibás volt. Igy némi gondolkodás után sikerült megíni magamnak.
Az alap ötlet kézenfekvő! Ha meghatározzuk, hogy hány nap telt el a 0. év január 1.-e óta, akkor a napok számát kell csak héttel osztani és a maradék megmondja, hogy hányadik napja van a hétnek. Pl. ha a mai napon (mikor ezeket a sorokat írom 2022.04.16. van), 17730 nap telt el a 0. év első napja óta. Azonban ezt nem is olyan egyszerű kiszámolni, mivel egy év nem mindig 365 nap, ráadásul a hónapok sem azonos napokból állnak. A legnagyobb gond a szökőévek figyelembevételével van. Nevezetesen minden 4-el osztható év szökőév. Kivéve, ha az adott év éppen 100-al osztható, mert akkor nem szökőév mégsem! Kivéve, ha 400-al osztható mert akkor meg mégis szökőév. Azért ilyen furcsa a szökőév meghatározása, mert a föld a nap körül 365 nap 5 óra 48 perc 46 másodperc tesz egy kört. Ez majdnem pontosan 365 és negyed nap, de egy kicsit kevesebb, ezért kell 100 évente egy szünet a szökőévekben. Viszont ez sem elegendően pontos korrekció , ezért kell 400 évente mégis egy szökőév. Elődjeink csak így tudták megoldani, hogy évszázadok alatt ne csússzon el az évszakok kezdete. Gergely pápa idejében már 8 nap eltérés keletkezett, amit az akkori mezőgazdaság észrevett, és ez kényszerítette ki a naptárreformot 1582-ben.
Szóval a feladat egyszerű, bárki meg tudná írni, így nekem is sikerült. Csak az idő megy el vele! Remélem valaki még rajtam kívül fel tudja használni.
A programot az UnoArduSim szimulátorban írtam meg. Ennek a szimulátornak van néhány butasága, pl. a Serial.println() függvénybe a zárójelekbe nem lehet saját függvényt beírni, ezért először változókba kell tölteni az értékeket és azt küldeni a sorosportra. A datum_hetnapja() függvényem elején csináltam néhány ellenőrzést, ami a megadott dátumot ellenőrzi. Pl. nem lehet a hónap 0. Sajnos a hónapok napjainak a számát ellenőrző programsorban az if()-ben olyan sok feltétel lett, amit a szimulátor már nem tud kezelni, ezért azt is ki kellett kommentezni. Valós Arduino-ba töltve azonban működik.
A kommentek alapján remélem követhető a működés. Nagy ötletek nincsenek a megvalósításban.Pl. az aktuális év eltelt napjainak a számát egy tömbben tárolt adatokból nyerem ki, ahol minden egyes hónap kumulált napszámait tárolom. Azaz a hónap megadásával visszakapom, hogy hány nap telik el abban a hónapban január 1 óta. Természetesen itt is figyelni kell, mert ha az aktuális év szökőév és a dátum nagyobb, mint február, akkor még egyet a napokhoz kell adni, mert szökőéveben február nem 28, hanem 29 napos. Szóval bamba feltételrendszer az egész megoldás.
Nem igazán tudtam értelmezni magamtól a kezdő napot, és hogy az milyen napja volt akkor a hétnek. A net teljesen összezavart. A szabályok ismeretében úgy tekintettem, hogy krisztus születésének éve 0. év január 1-el és vasárnappal kezdődik. Ennek megfelelően Krisztus 0.12.24.-én született hétfőn. Ezt persze csak az én programom adta vissza, mint eredményt. Valójában Krisztus időszámításunk előtt 4 vagy 6-ban születhetett, és nem is decemberben. Az akkori Juliánus naptár szerinti napforduló esett december 24-re, így ezt a napot tekintik születésnapjának. A napforduló viszont tudjuk, hogy a Gergely naptár szerint december 21.-én van. Még szerencse, hogy nem ezen infók alapján állítottam be a program 0. napját, hanem a jelenből számoltam vissza!
byte a; bool b; void setup() { Serial.begin(9600); b = datum_hetnapja(2022, 4, 16); //2022.04.16 szombat (6) Serial.println(b); b = datum_hetnapja(2022, 11, 3); //2122.11.13 csütörtök (4) Serial.println(b); a = szokoev(2022); //nem szökőév Serial.println(a); a = szokoev(2024); //szökőév Serial.println(a); } void loop() { } byte datum_hetnapja(int ev, byte ho, byte nap) /******************************************************************************* * Ez a függvény paraméterként várja egy dátumból az évet, hónapot és napot. * * Eredményként visszaadja a megadott dátum melyik napja a hétnek. A hét napja * * 1től 7-ig megadott érték, az 1 a hétfő, 7 a vasárnap. * *******************************************************************************/ { // if (ho<1) { return 0;} //hónap napjainak száma nem lehet 0 // if (ho!=1 & ho!=3 & ho!=5 & ho!=7 & ho!=8 & ho!=10 & ho!=12 & nap>31) { return 0;}; //több napot adtunk meg a hónapnak, mint amennyi napja van // if (ho!=4 & ho!=6 & ho!=9 & ho!=11 & nap>30) { return 0;} //több napot adtunk meg a hónapnak, mint amennyi napja van // if (ho==2) { //ha február van, ellenőrizni kell a szökőév szerinti napokat is // if (szokoev(ev)) { //megmondja, hogy az adott év szökőév-e, mert ha igen, akkor a február 29 napos // if (nap>29) { return 0;}} //szökőév, és több napot adtunk meg // else { // if (nap>28) { return 0;}} //nem szökőév, és több napot adtunk meg // } int ho_napjai[]={0,31,59,90,120,151,181,212,243,273,304,334,365}; //Az évből eltelet hónapok napjainak száma halmozva havonként nem szökőévben long elmult_nap=ev*365; //Eddig ennyi napja volt az elmúlt éveknek a szökőévek figyelembevétele nélkül int elmult_szokonap=0; //Ebbe a változóba számoljuk ki majd a szökőévekből adódó plusz napok számát int szn4=(ev-1)/4; //Minden negyedik év szökőév (kivéve minden 100. év, de azt később levonjuk) //az aktuális évet nem szabad beleszámolni, mert az majd az aktuális év napjaiban benne lesz int szn100=(ev-1)/100; //minden 100. év nem szökőév, ezt majd levonjuk, kivéve minden 400. év, azt meg mindjárt hozzáadjuk int szn400=(ev-1)/400; //Minden 400. év mégiscsak szökőév elmult_szokonap=szn4-szn100+szn400; //így megkaptuk a szökőévekből adódó plusz napokat long akt_ev_nap=ho_napjai[ho-1]+nap; //Az eddig eltelt hónapok napjainak száma kiderül a tömbből, plusz hozzáadjuk az aktuális hónap napjait, ahol épp járunk //Ha az adott év szökőév, és már elmúlt február, akkor még egyet hozzá kell majd adni, mert a tömb egy nem szökőévre készült. long akt_ev_szokonap=0; if (ho>2) { if (szokoev(ev)) { akt_ev_szokonap++; // ha az aktuális éveben már elmúlt február, és az év szökőév, akkor még egy napot hozzá kell adni } } long napok=elmult_nap+elmult_szokonap+akt_ev_nap+akt_ev_szokonap; //és ezzel megkaptuk Jézus szülteésének napja óta eltelt napok számát if (napok%7==0) { return 7; //ha pont vasárnap van, akkor maradék nélkülosztható 7-el, ezért ilyenkor 7-et adunk vissza } else { return napok%7; //a maradék az adott hétben eltelt napok száma (hétfő az 1) } } bool szokoev(int ev) { /************************************************************************************ * Ez a függvény paraméterként várja az évet (pl. 2022) és visszaadja bool értékben * * hogy a paraméterben megadott év szökőév, vagy sem. * ************************************************************************************/ if (ev==0) { return false; //a 0.évet nem vesszük szökőévne } bool szoko_ev=false; if (ev%4==0) { //ha néggyel osztva nem ad maradékot, akkor szökőév szoko_ev=true; if (ev%100==0) { //ha 100-al osztva nem ad maradékot, akkor nem szökőév szoko_ev=false; if (ev%400==0) { szoko_ev=true; //ha 400-al osztva nam ad maradékot, akkor mégis szökőév } } } return szoko_ev; }
Készítettem egy olyan programot is, ami automatikusan átállítja az órát a téli és nyári óraállítás időpontjában egy órával előre illetve vissza. Bagatell dolognak tűnik, de nem az, ha az óránk épp elemről működik, és csak az óraállítás után kapcsoljuk be valamikor!