Gyakorlati alapok

Kis nosztalgia avagy előretekintés: az év hányadik napja?

 

Az egyik fejezetben a szökőév kiszámításakor felmerülő többszörös feltételmegadással bosszantottam a Tisztelt Olvasót. Ebben a fejezetben azt számítjuk ki, hogy a beírt dátum az év hányadik napjára esik. A 2 probléma természetesen összetartozik, hiszen a korrekt végeredményhez tudnunk kell, hogy a bemeneti adatként megadott év szökőév-e. További fontos szempont, hogy a bemeneti adatot most nem ellenőrizzük le, helyette csakis a problémamegoldásra koncentrálunk.

 

www.informatika-programozas.hu - Ezt most meg kell tanulni!

 

Kis elméleti előzmény: a szökőév egy olyan speciális év, amely általában 4 évente +1 napot tartalmaz (február 24.). Erre azért van szükség, mert a csillagászati év és az 1582 óta működő Gergely-, másik nevén Gregorián-naptár között folyamatosan korrigálandó, időbeli eltérések vannak. A szökőév nem tévesztendő össze a szökőmásodpercekkel, amelyeket -ugyanilyen okból-, a csillagászati naphosszhoz szintén korrigálnak.

 

A szökőév implementációjánál a következő többszörös feltételmegadást kell figyelembe vennünk:

 

nagyobb 1582-nél, 4-gyel osztható; 100-zal nem osztható, 400-zal osztható
 

Mindennek kiszámítása a fejezetcsomag igényei szerint külön függvénybe került:


public static int szokoev(int ev){
    int szokoev = 0;
        if ((ev > 1582) && (ev % 4 == 0) && (ev % 100 != 0) || (ev % 400 == 0)){
            szokoev++;
        }
    return szokoev;
}

 

Ezen függvény érdekessége, hogy int típusú. A funkció valójában megoldható boolean típussal is:

 

public static boolean szokoev(int ev){
   
boolean szokoev = false;
        if ((ev > 1582) && (ev % 4 == 0) && (ev % 100 != 0) || (ev % 400 == 0)){
            szokoev == true;
        }
    return szokoev;
}

 

Továbbá ismernünk kell azt a listát, amelyik azt tartalmazza, hogy a hónapok hány napból állnak, illetve hónapváltáskor éppen az év hányadik napjában vagyunk (barna színnel jelölve):

Szökőév esetén március 1-től felfelé az aktuális dátumhoz +1 napot kell hozzáillesztenünk.

 

A számolás fő vezérlési szerkezete egy switch kapcsoló (Dönteni kell! (switch) című fejezet), amely a "napsorszámot" nekünk villámgyorsan megállapítja:

 

switch(honap){
    case 1: eredmeny = nap; break;
    case 2: eredmeny = 31 + nap; break;
    case 3: eredmeny = 59 + nap; break;
    case 4: eredmeny = 90 + nap; break;
    case 5: eredmeny = 120 + nap; break;
    case 6: eredmeny = 151 + nap; break;
    case 7: eredmeny = 181 + nap; break;
    case 8: eredmeny = 212 + nap; break;
    case 9: eredmeny = 243 + nap; break;
    case 10: eredmeny = 273 + nap; break;
    case 11: eredmeny = 304 + nap; break;
    case 12: eredmeny = 334 + nap; break;
}

 

A bemeneti adat fogadásakor a legfontosabb, még nem ismert beépített metódus a substring(). Ez választja le a bemeneti String füzérről (például 2015.03.18.)...

www.informatika-programozas.hu - Ezt most meg kell tanulni!

 

Ám amint már említésre került, nincs egyéb karakterellenőrzés.

 

Az utolsó if-else döntéscsomagban pedig az eredményeket írjuk ki. Ennek is van egy kis bonyodalma, hiszen...

 

www.informatika-programozas.hu - Ezt most meg kell tanulni!

 

...valójában nem pontos: a szökőnap ugyanis nem február 29. hanem február 24. Ám ez lényegtelen, mert a napszámításkor nem ez, hanem csakis az számít, hogy február 28 vagy 29 napos. Tehát a napsorszámok csak február 28. után (59. nap után) változnak meg és csakis szökőév esetén.

 

www.informatika-programozas.hu - Futtatható Java-kód!

 

 

 

 

 

 

 

 

import java.util.Scanner;
 

public class Main {
    public static int szokoevSzamitas(int ev){
        int szokoev = 0;
            if ((ev > 1582) && (ev % 4 == 0) && (ev % 100 != 0) || (ev % 400 == 0)){
                szokoev++;
            }
        return szokoev;
    }


public static void main(String[] args) {
    int ev = 0;
    int honap = 0;
    int nap = 0;
    int szokoev = 0;
    int eredmeny = 0;

    Scanner scanner = new Scanner (System.in);
    System.out.println ("Kérem, hogy adja meg a dátumot a következő formátumban: pl. 2015.03.18.");
    String adatString = scanner.nextLine();
    String year = adatString.substring(0,4);
    String month = adatString.substring(5,7);
    String day = adatString.substring(8,10);

    ev = Integer.parseInt(year);
    honap = Integer.parseInt(month);
    nap = Integer.parseInt(day);

    szokoev =
szokoevSzamitas(ev);

    switch(honap){
        case 1: eredmeny = nap; break;
        case 2: eredmeny = 31 + nap; break;
        case 3: eredmeny = 59 + nap; break;
        case 4: eredmeny = 90 + nap; break;
        case 5: eredmeny = 120 + nap; break;
        case 6: eredmeny = 151 + nap; break;
        case 7: eredmeny = 181 + nap; break;
        case 8: eredmeny = 212 + nap; break;
        case 9: eredmeny = 243 + nap; break;
        case 10: eredmeny = 273 + nap; break;
        case 11: eredmeny = 304 + nap; break;
        case 12: eredmeny = 334 + nap; break;
    }

    if(szokoev != 0 && eredmeny > 59){
        System.out.println(adatString + ". szökőév és a megadott dátum az év "

                                                + (eredmeny + szokoev) + ". napja volt/lesz.");
    }
   

else if(szokoev != 0){
        System.out.println(adatString + ". szökőév és a megadott dátum az év "

                                                + eredmeny + ". napja volt/lesz.");

    }

else
        System.out.println(adatString + ". NEM szökőév és a megadott dátum az év "

                                                + eredmeny + ". napja volt/lesz.");
    }
}
 

A program valójában 3 metódusból áll, amelyhez +1 lehetőségként szintén külön eljárásban hozzácsaphatjuk az eredménykiírást:

  1. szimpla adatbekérés, vele adattípus-átalakítás,

  2. szökőévszámítás,

  3. napsorszám-számítás,

  4. eredménykiírás.

A fenti program ebből csak 1 metódust implementált külön függvényben (szokoevSzamitas(int ev), kézenfekvő tehát a feladat, miszerint mindegyiket valósítsuk meg külön függvényben!

 

www.informatika-programozas.hu - Futtatható Java-kód!

 

 

 

 

 

 

 

 

import java.util.Scanner;

public class Main {
    static int szokoevSzamitas(int ev){
        int szokoev = 0;
            if ((ev > 1582) && (ev % 4 == 0) && (ev % 100 != 0) || (ev % 400 == 0)){
                szokoev++;
            }
    return szokoev;
}

    static int[] getBemenetiAdat(String adatBekeres){
        int[] eredmenyTomb = new int[3];
        Scanner scanner = new Scanner (System.in);
        System.out.println(adatBekeres);
        String adatString = scanner.nextLine();

        String year = adatString.substring(0,4);
        String month = adatString.substring(5,7);
        String day = adatString.substring(8,10);

        eredmenyTomb[0] = Integer.parseInt(year);
        eredmenyTomb[1] = Integer.parseInt(month);
        eredmenyTomb[2] = Integer.parseInt(day);

        return eredmenyTomb;
    }

    static int napSorszamSzamitas(int honap, int nap){
        int napSorszam = 0;
        switch(honap){
            case 1: napSorszam = nap; break;
            case 2: napSorszam = 31 + nap; break;
            case 3: napSorszam = 59 + nap; break;
            case 4: napSorszam = 90 + nap; break;
            case 5: napSorszam = 120 + nap; break;
            case 6: napSorszam = 151 + nap; break;
            case 7: napSorszam = 181 + nap; break;
            case 8: napSorszam = 212 + nap; break;
            case 9: napSorszam = 243 + nap; break;
            case 10: napSorszam = 273 + nap; break;
            case 11: napSorszam = 304 + nap; break;
            case 12: napSorszam = 334 + nap; break;
        }
        return napSorszam;
    }

    static void eredmenyKiiras(int ev, int szokoev, int napSorszam){
        if(szokoev != 0 && napSorszam > 59){
            System.out.println(ev + ". szökőév és a megadott dátum az év "

                                          + (napSorszam + szokoev) + ". napja volt/lesz.");
        }
        else if(szokoev != 0){
           System.out.println(ev + ". szökőév és a megadott dátum az év "

                                         + napSorszam + ". napja volt/lesz.");
        }
        else
          System.out.println(ev + ". NEM szökőév és a megadott dátum az év "

                                 + napSorszam + ". napja volt/lesz.");
}

    public static void main(String[] args) {
        int[] eredmenyTomb = getBemenetiAdat("Kérem, hogy adja meg a dátumot

                                                                a következő formátumban: pl. 2015.03.18.");
        int szokoev = szokoevSzamitas(eredmenyTomb[0]);
        int napSorszam = napSorszamSzamitas(eredmenyTomb[1], eredmenyTomb[2]);
        eredmenyKiiras(eredmenyTomb[0], szokoev, napSorszam);
    }
}

 

Végeredmény (például):

Kérem, hogy adja meg a dátumot a következő formátumban: pl. 2015.03.18.
2015.01.10.
2015. NEM szökőév és a megadott dátum az év 10. napja volt/lesz.

 

Ilyen módon a Java-kódban több érdekes változás is történik. A legszembetűnőbb jelenség, hogy a főprogram milyen rövid lett, hiszen a funkcionális kódok "kívülre" kerültek, a main főprogram csak hivatkozik rájuk:

 

    public static void main(String[] args) {
        int[] eredmenyTomb = getBemenetiAdat("Kérem, hogy adja meg a dátumot

                                                                a következő formátumban: pl. 2015.03.18.");
        int szokoev = szokoevSzamitas(eredmenyTomb[0]);
        int napSorszam = napSorszamSzamitas(eredmenyTomb[1], eredmenyTomb[2]);
        eredmenyKiiras(eredmenyTomb[0], szokoev, napSorszam);
    }

 

www.informatika-programozas.hu - Ezt most meg kell tanulni!

 

A külső eljárások és függvények használatával viszont új nehézségekbe ütköztünk: fokozottan kell figyelnünk a függvények közti adatátadáskor fellépő típusegyezéseket.