Hét napja dátumból, szökőév

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!

Mennyire volt hasznos amit olvastál? Értékelés után szövegesen is leírhatod megjegyzéseidet és véleményedet!

Kattints egy csillagra az értékeléshez!

Szövegesen is leírhatod véleményedet! Ha kérdésed van, ne felejtsd el megadni az email címedet!