Wie berechnet man den Wochentag für RTC?

Ich verwende MCP7940 RTC von Mikrochip, der den Wochentag als Teil der Aktualisierung von RTC mit Datum eingeben muss. Wie soll ich also den Wochentag basierend auf dem vom Benutzer angegebenen Datum berechnen?

Antworten (4)

Wenn Sie den Wochentag selbst berechnen möchten, finden Sie hier eine C-Implementierung eines Teils eines Perl-Moduls, das ich vor etwa 20 Jahren geschrieben habe. Ich mag diesen Algorithmus, weil er keine Schleifen oder eine Tabelle mit Monatslängen erfordert. Beachten Sie, dass intangenommen wird, dass s 32 Bit sind.

/* Returns the number of days to the start of the specified year, taking leap
 * years into account, but not the shift from the Julian calendar to the
 * Gregorian calendar. Instead, it is as though the Gregorian calendar is
 * extrapolated back in time to a hypothetical "year zero".
 */
int leap (int year)
{
  return year*365 + (year/4) - (year/100) + (year/400);
}

/* Returns a number representing the number of days since March 1 in the
 * hypothetical year 0, not counting the change from the Julian calendar
 * to the Gregorian calendar that occured in the 16th century. This
 * algorithm is loosely based on a function known as "Zeller's Congruence".
 * This number MOD 7 gives the day of week, where 0 = Monday and 6 = Sunday.
 */
int zeller (int year, int month, int day)
{
  year += ((month+9)/12) - 1;
  month = (month+9) % 12;
  return leap (year) + month*30 + ((6*month+5)/10) + day + 1;
}

/* Returns the day of week (1=Monday, 7=Sunday) for a given date.
 */
int dow (int year, int month, int day)
{
  return (zeller (year, month, day) % 7) + 1;
}
Eine Tabelle mit der Anzahl der Tage vom 1. März bis zum ersten Tag eines bestimmten Monats wäre wahrscheinlich kleiner und schneller als der Code zum Auswerten der angegebenen Formel, insbesondere wenn man nur an Daten im Bereich 2000-2099 interessiert ist.
@supercat: Warum zeigst du uns nicht, wie dieser Code aussehen würde?

Laut Datenblatt gibt es unter Adresse 0x03 in Tabelle 4-1 ein Feld „Tag“. Am Ende der Zeile steht eine kurze Beschreibung:

Die Anschrift Bit7:3 Bit2:0 Funktion Reichweite 0x03 ... Tag Tag 1-7

Das bedeutet, dass der Tag auf eine beliebige Zahl zwischen 1 und 7 eingestellt werden kann. Sie können Ihren eigenen Wochentag auswählen. Auf POSIX-Systemen ist der Montag als 1 definiert, ich denke, das ist ein guter Standard. Dann Dienstag = 2; Mittwoch = 3; ...

Tag = 0 ist nicht dokumentiert, also nicht verwenden.

Unter Linux kann diese Nummer leicht mit dem Befehl gefunden werden date +%u, der heute antwortet, 6da es Samstag ist. Wenn Sie dies lokal auf Ihrem PIC berechnen möchten, müssen Sie die C-Bibliothek finden, die die Formel implementiert, von der ich glaube, dass strftimesie <time.h>genau das tut, aber ich bin nicht genug C-Programmierer, um zu erklären, wie diese bestimmte Bibliothek verwendet wird. Es ist eine häufig verwendete Bibliothek, daher ist die Dokumentation leicht zu finden.

Montag ist auch Tag 1 (Sonntag Tag 7) im internationalen Standard ISO-8601.

Der Wochentag ist beliebig . Sie definieren es. Sie könnten den julianischen Sonntag = Tag 1 verwenden. Sie könnten Montag als Tag 1 verwenden, da Sonntag der 7. Tag ist. Sie könnten Freitag als Tag 1 verwenden, weil es der erste Tag des Wochenendes ist. Sie könnten den Dienstag als Tag 1 verwenden, weil Sie Montage hassen.

Dies ist keine Antwort. Es scheint eine Art Geschwätz zu sein, aber ich kann nicht herausfinden, was der Sinn ist. Die ursprüngliche Frage war, wie man von einem bestimmten Datum zum richtigen Wochentag kommt.
@DaveTweed Ich erkläre, dass der Wochentag willkürlich ist. Es hat keine feste Bedeutung für die RTC. Bis OP definiert, was seiner Meinung nach Tag 1 sein würde, ist es unmöglich, den "richtigen Wochentag" zu erhalten, wie Sie es ausdrücken.
Wenn Sie der Meinung sind, dass die Frage unvollständig war, hätte dies als Kommentar und nicht als Antwort gepostet werden sollen.
Die Tatsache, dass es willkürlich ist, bedeutet nicht, dass es nicht berechnet werden kann, sobald Sie Ihren Standard festgelegt haben.

Ich schlage vor, Sie verwenden die RTClib-Bibliothek

#include <Wire.h>
#include "RTClib.h"
 
RTC_DS3231 rtc;
 
char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
 
void setup () {
  Serial.begin(9600);
  delay(3000); // wait for console opening
 
  if (! rtc.begin()) {
    Serial.println("Couldn't find RTC");
    while (1);
  }
 
  if (rtc.lostPower()) {
    Serial.println("RTC lost power, lets set the time!");
     
    // Comment out below lines once you set the date & time.
    // Following line sets the RTC to the date & time this sketch was compiled
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
     
    // Following line sets the RTC with an explicit date & time
    // for example to set January 27 2017 at 12:56 you would call:
    // rtc.adjust(DateTime(2017, 1, 27, 12, 56, 0));
  }
}
 
void loop () {
    DateTime now = rtc.now();
     
    Serial.println("Current Date & Time: ");
    Serial.print(now.year(), DEC);
    Serial.print('/');
    Serial.print(now.month(), DEC);
    Serial.print('/');
    Serial.print(now.day(), DEC);
    Serial.print(" (");
    Serial.print(daysOfTheWeek[now.dayOfTheWeek()]);
    Serial.print(") ");
    Serial.print(now.hour(), DEC);
    Serial.print(':');
    Serial.print(now.minute(), DEC);
    Serial.print(':');
    Serial.print(now.second(), DEC);
    Serial.println();
     
    Serial.println("Unix Time: ");
    Serial.print("elapsed ");
    Serial.print(now.unixtime());
    Serial.print(" seconds/");
    Serial.print(now.unixtime() / 86400L);
    Serial.println(" days since 1/1/1970");
     
    // calculate a date which is 7 days & 30 seconds into the future
    DateTime future (now + TimeSpan(7,0,0,30));
     
    Serial.println("Future Date & Time (Now + 7days & 30s): ");
    Serial.print(future.year(), DEC);
    Serial.print('/');
    Serial.print(future.month(), DEC);
    Serial.print('/');
    Serial.print(future.day(), DEC);
    Serial.print(' ');
    Serial.print(future.hour(), DEC);
    Serial.print(':');
    Serial.print(future.minute(), DEC);
    Serial.print(':');
    Serial.print(future.second(), DEC);
    Serial.println();
    Serial.println();

    delay(1000);
}
Ich habe es getestet und es hat perfekt funktioniert
OK, Sie sagen also, Sie sollen eine zufällige Bibliothek verwenden, aber nicht erwähnen, wo diese Bibliothek verfügbar ist und unter welchen Umständen sie verwendet werden kann, z. B. unterstützte Plattformen oder Softwarelizenzen.