09.05.2017, 14:22
Um die Wochennummer zu berechnen, sind einige Funktionen nötig.
Im Internet findet man zahlreiche Berechnungen, aber viele von denen liefern fehlerhafte Daten zurück und/oder berücksichtigen nicht die deutschen/europäischen Regeln zur Berechnung.
Ich habe mal eine Berechnung auf Grundlage der ISO 8601 erstellt:
So funktioniert das auf dem Arduino problemlos.
Ich habe das Programm umfangreich kommentiert, sodass die Funktionen verständlich sind.
Im Internet findet man zahlreiche Berechnungen, aber viele von denen liefern fehlerhafte Daten zurück und/oder berücksichtigen nicht die deutschen/europäischen Regeln zur Berechnung.
Ich habe mal eine Berechnung auf Grundlage der ISO 8601 erstellt:
Show ContentArduino-Quellcode:
/* Daten mit Grenzwerten zum testen der Funktionen:
* 29.12.2014 = ist ein Montag und faellt bereits in die 1. Woche des naechsten Jahres
* 31.12.2015 = in dem Jahr gab es eine 53. Woche
* 31.12.2016 = Tag des Jahres wird mit 366 korrekt berechnet (Schaltjahr)
* 01.01.2017 = ist ein Sonntag und faellt noch in die 52. Woche des Vorjahres
*/
uint16_t year = 2014;
uint8_t month = 12;
uint8_t day = 29;
const char WeekDays[][3] = {"Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"}; // Abkuerzungen der Wochentage
void setup() {
Serial.begin(115200);
Serial.println(F("Berechnung nach ISO 8601"));
Serial.print(F("Datum: "));
Serial.print(day);
Serial.print(".");
Serial.print(month);
Serial.print(".");
Serial.println(year);
uint8_t wd = GetWeekday(year, month, day); // 1 = Mo, 2 = Di, 3 = Mi, 4 = Do, 5 = Fr, 6 = Sa, 7 = So
Serial.print(F("Wochentag: "));
Serial.println(WeekDays[wd - 1]);
uint16_t doy = GetDayOfYear(year, month, day); // den Tag des Jahres berechnen
Serial.print(F("Tag des Jahres: "));
Serial.println(doy);
uint8_t WeekNr = GetWeekNumber(year, month, day); // die Wochennummer berechnen
Serial.print(F("Wochennummer: "));
Serial.println(WeekNr);
bool LeapYear = IsLeapYear(year); // berechnen, ob das Jahr ein Schaltjahr ist
Serial.print(F("Schaltjahr: "));
Serial.println(LeapYear ? F("Ja") : F("Nein"));
}
void loop() {
}
/***** Den Wochentag nach ISO 8601 (1 = Mo, 2 = Di, 3 = Mi, 4 = Do, 5 = Fr, 6 = Sa, 7 = So) berechnen *****/
uint8_t GetWeekday(uint16_t y, uint8_t m, uint8_t d) {
static int t[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
y -= m < 3;
uint8_t wd = (y + y / 4 - y / 100 + y / 400 + t[m - 1] + d) % 7;
return (wd == 0 ? 7 : wd);
}
/***** Die Wochennummer nach ISO 8601 berechnen *****/
uint8_t GetWeekNumber(uint16_t y, uint8_t m, uint8_t d) {
bool LeapYear;
uint16_t doy = GetDayOfYear(y, m, d); // Anzahl der Tage im Jahr ermitteln
uint8_t wd = GetWeekday(y, m, d); // Wochentag ermitteln
uint8_t wnr = (doy - wd + 7) / 7; // die Wochennummer berechnen
switch (wnr) {
case 0: // wenn die Wochennummer Null ergibt, dann liegt der Tag am Anfang des Jahres (1. Sonderfall)
wd = GetWeekday(y - 1, 12, 31); // den letzten Wochentag aus dem Vorjahr ermitteln
LeapYear = IsLeapYear(y - 1); // ermitteln, ob es sich beim Vorjahr um ein Schaltjahr handelt
break; // und nach dem Switch weitermachen...
case 52: // wenn die Wochennummer 52 ergibt, dann liegt der Tag am Ende des Jahres (2. Sonderfall)
wd = GetWeekday(y, 12, 31); // den letzten Wochentag aus diesem Jahr ermitteln
LeapYear = IsLeapYear(y); // ermitteln, ob es sich bei diesem Jahr um ein Schaltjahr handelt
break; // und nach dem Switch weitermachen...
default: // in den anderen Faellen kann die Funktion
return wnr; // hier verlassen und die Wochennummer zurueckgegeben werden
}
if (wd < 4) { // wenn der 31.12. vor dem Donnerstag liegt, dann...
wnr = 1; // ist das die erste Woche des Jahres
} else { // anderenfalls muss ermittelt werden, ob es eine 53. Woche gibt (3. Sonderfall)
/* wenn der letzte Wochentag auf einen Donnerstag oder, */
/* in einem Schaltjahr, auf einen Donnerstag oder Freitag fällt, */
/* dann ist das die 53. Woche, ansonsten die 52. Woche. */
wnr = ((wd == 4) || (LeapYear && wd == 5)) ? 53 : 52;
}
return wnr;
}
/***** die Anzahl der Tage (Tag des Jahres) berechnen *****/
uint16_t GetDayOfYear(uint16_t y, uint8_t m, uint8_t d) {
static const uint16_t mdays[] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
return d + mdays[m - 1] + (m >= 2 && IsLeapYear(y));
}
/***** Testen, ob das Jahr ein Schaltjahr ist *****/
bool IsLeapYear(uint16_t y) {
return !(y % 4) && ((y % 100) || !(y % 400)); // Schaltjahrberechnung (true = Schaltjahr, false = kein Schaltjahr)
}
Ich habe das Programm umfangreich kommentiert, sodass die Funktionen verständlich sind.