Kirjoittaja: Antti Laaksonen
Kirjoitettu: 01.02.2002 – 29.10.2023
Tagit: matematiikka, koodi näytille, vinkki
Näpsäkkä tapa selvittää tietyn päivämäärän viikonpäivä. Tämä löytyi alunperin Internetistä, mutta olen suomentanut ja parannellut sitä. Koodi toimii vuoden 1800 maaliskuusta aina vuoden 2199 loppuun saakka.
' Alkuperäinen koodi: Ray Thomas
' Funktio laskee viikonpäivän.
' 0 = sunnuntai, 1 = maanantai, ..., 6 = lauantai.
FUNCTION Viikonpaiva(BYVAL Vuosi AS INTEGER, BYVAL Kuukausi AS INTEGER, BYVAL Paiva AS INTEGER)
	DIM Vuosisata AS INTEGER
	DIM Taikaluku AS INTEGER
	IF Kuukausi < 3 THEN
		Kuukausi = Kuukausi + 12
		Vuosi = Vuosi - 1
	END IF
	Vuosisata = Vuosi \ 100
	Vuosi = Vuosi MOD 100
	Kuukausi = FIX((Kuukausi + 1) * 2.61)
	SELECT CASE Vuosisata
		CASE 18: Vuosisata = 2
		CASE 19: Vuosisata = 0
		CASE 20: Vuosisata = 6
		CASE 21: Vuosisata = 4
	END SELECT
	Taikaluku = Vuosisata + Vuosi + Kuukausi + Paiva + (Vuosi \ 4)
	Viikonpaiva = Taikaluku MOD 7
END FUNCTION
DIM Paivamaara AS STRING
DIM Paiva AS INTEGER, Kuukausi AS INTEGER, Vuosi AS INTEGER
DIM Paivat(7) AS STRING
Paivat(0) = "sunnuntai"
Paivat(1) = "maanantai"
Paivat(2) = "tiistai"
Paivat(3) = "keskiviikko"
Paivat(4) = "torstai"
Paivat(5) = "perjantai"
Paivat(6) = "lauantai"
DO
    PRINT "Kirjoita päivä muodossa PP.KK.VVVV (esim. 02.02.2002)."
    PRINT "Lopeta tyhjällä rivillä."
    INPUT Paivamaara
    IF LEN(Paivamaara) <> 10 OR MID$(Paivamaara, 3, 1) <> "." OR MID$(Paivamaara, 6, 1) <> "." THEN EXIT DO
    Paiva = VAL(LEFT$(Paivamaara, 2))
    Kuukausi = VAL(MID$(Paivamaara, 4, 2))
    Vuosi = VAL(RIGHT$(Paivamaara, 4))
    PRINT "Päivä on "; Paivat(Viikonpaiva(Vuosi, Kuukausi, Paiva))
LOOPHauska, ehkä tuosta jotain hyötyä on...
Kun muutetaan alkuperäisen vinkin SELECT-lause vielä kaavaksi, saadaan lyhennettyä funktiota ja saadaan se toimimaan vielä laajemmalla alueella vuosilukuja.
' Funktio laskee viikonpäivän. ' 0 = sunnuntai, 1 = maanantai, ..., 6 = lauantai. FUNCTION Viikonpaiva(BYVAL Vuosi AS INTEGER, BYVAL Kuukausi AS INTEGER, BYVAL Paiva AS INTEGER) IF Kuukausi < 3 THEN Kuukausi = Kuukausi + 12 Vuosi = Vuosi - 1 END IF ' Päivä huomioidaan suoraan. ' Kuukausi huomioidaan kertoimella, joka pyöristyy oikein vuoden aikana. ' Vuosiluvun viimeiset numerot huomioidaan, vuodessa on 1 päivä yli viikon. ' Vuoden jako neljällä tuottaa lisäpäivän tavallisille karkausvuosille. ' Viimeinen osa käsittelee karkausvuoden poikkeukset 100 ja 400 vuoden välein. Viikonpaiva = (Paiva + FIX((Kuukausi + 1) * 2.61) + (Vuosi MOD 100) + ((Vuosi MOD 100) \ 4) + (2 * (3 - ((Vuosi \ 100) MOD 4)))) MOD 7 END FUNCTION
Kommentoin koodiin myös, mihin toiminta perustuu: Vuosilukua koskevilla osilla saadaan laskettua kustakin vuodesta maaliskuun ensimmäinen päivä huomioiden myös karkausvuosien vaikutuksen. Karkauspäivä on tällöin vuoden viimeinen päivä, joten se ei vaadi muuta lisäkäsittelyä. Kuukausissa päästään eteenpäin sopivalla kertoimella. Päivän numero lisätään sellaisenaan.
Funktio voidaan helposti silmukalla testata ja todeta toimivaksi.
DIM Paiva AS INTEGER, Kuukausi AS INTEGER, Vuosi AS INTEGER
DIM OikeaViikonpaiva AS INTEGER, Tulos AS INTEGER
DIM Oikeat AS LONG, Virheet AS LONG
' Gregoriaaninen kalenteri otettiin käyttöön 15.10.1582.
' Takautuvasti ajatellen 1.1.1582 olisi ollut perjantai.
OikeaViikonpaiva = 5
PRINT "Aloitetaan päivästä 1.1.1582."
FOR Vuosi = 1582 TO 9999
    FOR Kuukausi = 1 TO 12
        FOR Paiva = 1 TO 31
            IF Paiva > 30 AND (Kuukausi = 4 OR Kuukausi = 6 OR Kuukausi = 9 OR Kuukausi = 11) THEN EXIT FOR
            IF Paiva > 29 AND Kuukausi = 2 AND NOT (Vuosi MOD 4 <> 0 OR (Vuosi MOD 100 = 0 AND Vuosi MOD 400 <> 0)) THEN EXIT FOR
            IF Paiva > 28 AND Kuukausi = 2 AND (Vuosi MOD 4 <> 0 OR (Vuosi MOD 100 = 0 AND Vuosi MOD 400 <> 0)) THEN EXIT FOR
            Tulos = Viikonpaiva(Vuosi, Kuukausi, Paiva)
            IF Tulos <> OikeaViikonpaiva THEN
                PRINT Paiva; "."; Kuukausi; "."; Vuosi; " on "; OikeaViikonpaiva; ", funktion tulos "; Tulos; "."
                Virheet = Virheet + 1
            ELSE
                IF Paiva = 1 AND Kuukausi = 1 THEN PRINT "Vuosi "; Vuosi; " alkaa viikonpäivällä "; Tulos
                Oikeat = Oikeat + 1
            END IF
            OikeaViikonpaiva = (OikeaViikonpaiva + 1) MOD 7
        NEXT Paiva
    NEXT Kuukausi
NEXT Vuosi
PRINT "Näissä vuosissa oikeita viikonpäiviä oli "; Oikeat; " ja virheitä "; Virheet; "."Alkuperäisen vinkin lähdekin näkyy muuten yhä löytyvän netistä vielä 23 vuoden jälkeenkin:
https://brisray.com/qbasic/qdate.htm