Funktion zur Berechnung des Wochentages


  • Mod

    Bin gerade über diese Funktion gestolpert:

    static uint8_t calculateWeekday(uint16_t year, uint8_t month, int32_t day)
    {
        day += 6; // 1.1.2000 was a saturday
        day += (year-2000)*365.25;
        if (month > 11)
            day+=334;
        else if (month > 10)
            day+=304;
        else if (month > 9)
            day+=273;
        else if (month > 8)
            day+=243;
        else if (month > 7)
            day+=212;
        else if (month > 6)
            day+=181;
        else if (month > 5)
            day+=151;
        else if (month > 4)
            day+=120;
        else if (month > 3)
            day+=90;
        else if (month > 2)
            day+=59;
        else if (month > 1)
            day+=31;
    
        if (year%4 == 0 && (month < 2 || (month == 2 && day <= 28)))
        {
            day--;
        }
    
        return (day%7+1);
    }
    

    So richtig elegant sieht das noch nicht aus. Vielleicht hat jemand eine bessere Idee, wie man das kompakt lösen kann.




  • Mod

    Das sieht ja noch schrecklicher aus. 😃



  • Ist aber korrekt 😉 (im Gegensatz zu obiger Funktion)


  • Mod

    Kannst du das nach C übersetzen mit obigen Parametern?

    Hier im Forum gefunden:

    dayofweek(int y, int m, int d)      /* 0 = Sonntag */
                                        /* 1 <= m <= 12,  y > 1752 oder so */
    {
      static int t[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
    
        y -= m < 3;
    
      return (y + y/4 - y/100 + y/400 + t[m-1] + d) % 7;
    }
    

    im Gegensatz zu obiger Funktion

    Bisher wurde der Wochentag korrekt berechnet, aber ich traue der sache auch nicht.



  • Erhard Henkes schrieb:

    Bisher wurde der Wochentag korrekt berechnet, aber ich traue der sache auch nicht.

    Im Jahr 2100 stimmts nimmer, soweit ich das sehen kann, das ist nämlich kein Schaltjahr 😉



  • ich hab mal so angefangen:
    EDIT: (angefangen heißt nicht fertig 😃 )
    EDIT2: ist auch irgendwie falsch

    static uint8_t calculateWeekday(uint16_t year, uint8_t month, int32_t day)
    {
        //1.1.2000 was Saturday
        size_t day_ = 0;
    
        int32_t diff_day = 1-day;
        int32_t diff_year = 2000-year;
    
        uint8_t schaltjahr[diff_year+1];
        for(int i = 0;i < diff_year+1;i++)
        {
            if((2000+i)%4 == 0 && ((2000+i)%100 != 0 || (2000+i)%400 == 0))
                schaltjahr[i] = 1;
            else
                schaltjahr[i] = 0;
        }
        if(diff_year > 0)
        {
            for(int i = 0;i < diff_year;i++)
            {
                day_ += 365+schaltjahr[i];
            }
        }
    }
    

  • Mod

    da kommt noch kein Wochentag zurück ^^


  • Mod

    Es ist interessant, wenn man höhere Jahreszahlen mit Emulatoren oder Windows testen will:

    - qemu bricht sofort beim Start zusammen (ganz erbärmlich)
    - Datum/Zeit von Win XP endet im Jahr 2099 (Unverschämtheit!)
    - der GNU-Compiler gerät aus dem Takt, wenn man 2099 einstellt (merkwürdig)



  • static uint8_t calculateWeekday(uint16_t year, uint8_t month, int32_t day)
    {
        //1.1.2000 was Saturday
        size_t day_ = 5;
        int32_t diff_year = year-2000;
        uint8_t schaltjahr[diff_year+1];
    
        //calculate Schaltjahre
        for(int i = 0;i < diff_year+1;i++)
        {
            if((2000+i)%4 == 0 && ((2000+i)%100 != 0 || (2000+i)%400 == 0))
                schaltjahr[i] = 1;
            else
                schaltjahr[i] = 0;
        }
    
        //add days of diff. of years
        if(diff_year > 0)
        {
            for(int i = 0;i < diff_year;i++)
            {
                day_ += 365+schaltjahr[i];
            }
        }
    
        //Month
        if(month > 1)
        {
            for(int i = 0;i < month-1;i++)
            {
                if(month-1+i == 2)
                {
                    if(schaltjahr[year])
                        day_ += 29;
                    else
                        day_ += 28;
                }
                else
                {
                    if((month-1+i)%2 == 1)
                        day_ += 31;
                    else
                        day_ += 30;
                }
            }
        }
    
        //add diff.day
        day_ += day-1;
    
        return day_%7;
    }
    

    Ich hab das noch nicht überprüft aber bei Montag sollte 0 rauskommen


  • Mod

    Im Jahr 2100 stimmts nimmer, soweit ich das sehen kann, das ist nämlich kein Schaltjahr

    Das lässt sich leicht ausbügeln:

    if ((year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0)) && (month < 2 || (month == 2 && day <= 28)))
        {
            day--;
        }
    


  • Ja, aber du hast doch sowieso schon eine fertige Implementierung der Wochentagsformel gefunden!? Ich würd die benutzen^^



  • jetzt hab ich mir mühe gemacht 🙄 😉


  • Mod

    Wenn man unsere Formel optisch etwas pusht, die korrekte isLeapyear(...) einsetzt und die korrekte Zahl der Tage pro Jahr verwendet, dann hat das auch etwas Eingängliches.

    uint8_t calculateWeekday(uint16_t year, uint8_t month, int32_t day)
    {
        day += 6; // 1.1.2000 was a saturday
        day += (year-2000) * 365.24219;
    
        if      (month > 11)    day+=334;
        else if (month > 10)    day+=304;
        else if (month >  9)    day+=273;
        else if (month >  8)    day+=243;
        else if (month >  7)    day+=212;
        else if (month >  6)    day+=181;
        else if (month >  5)    day+=151;
        else if (month >  4)    day+=120;
        else if (month >  3)    day+=90;
        else if (month >  2)    day+=59;
        else if (month >  1)    day+=31;
    
        if ((year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0)) && (month < 2 || (month == 2 && day <= 28)))
        {
            day--;
        }
    
        return ( day % 7 + 1 );
    }
    

    @dot: Diese perfekte Formel von Gauß versteht man nicht leicht. Es gibt übrigens noch mehr Systeme zur Berechnung.

    @neuer_user: Vielleicht nehmen wir auch deine Formel. Noch ist alles offen.



  • Erhard Henkes schrieb:

    Diese perfekte Formel versteht man nicht. Es gibt übrigens noch mehr Systeme zur Berechnung.

    Was genau versteht man daran nicht, im Wikipedia-Artikel ist doch eine komplette Herleitung!?


  • Mod

    Welche Formel wir verwenden werden, entscheidet letztendlich das Team. Der Thread ist noch zu frisch. Danke auf jeden Fall für den Tipp. 🙂



  • Meine Version ist länger.
    Mich stört diese Kommaangabe

    (year-2000) * [u]365.24219[/u];
    

  • Mod

    Ja, das stimmt. Man könnte vielleicht auch 146097.0 / 400.0 verwenden.

    Wenn wir eine kürzere Formel für month ==> day finden, ist unsere Formel viel schöner. Sie muss ja nur ab 2000 und nicht vorher gelten.

    - isLeapyear(...) könnte man auslagern
    - die Zahlen der Tage für einen abgeschlossenen Monat könnte man in ein Array packen



  • Erhard Henkes schrieb:

    Sie muss ja nur ab 2000 und nicht vorher gelten.

    So haben schon viele gedacht... 😉


  • Mod

    static uint16_t days[12] = {  0,  31,  59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
    
    static bool isLeapyear(uint16_t year)
    {
        return (year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0));
    }
    
    static uint8_t calculateWeekday(uint16_t year, uint8_t month, int32_t day)
    {
        day += 6; // 1.1.2000 was a saturday
        day += (year-2000) * 365.24219 + days[month-1];
    
        if (isLeapyear(year) && (month < 2 || (month == 2 && day <= 28)))
        {
            day--;
        }
    
        return ( day % 7 + 1 );
    }
    

    So sieht das doch schon richtig fein aus. 😃

    Verflixt! beim 31.12.2099 kommt Mittwoch raus, ist aber Donnerstag. Die genaue Kommazahl ist offenbar nicht hilfreich. Nein, daran liegt es nicht.


Anmelden zum Antworten