Как рассчитать день недели для RTC?

Я использую MCP7940 RTC от микрочипа, который требует ввода дня недели как часть обновления RTC с датой. Итак, как мне рассчитать день недели на основе даты, предоставленной пользователем?

Ответы (4)

Если вы хотите самостоятельно вычислить день недели, вот реализация на C части модуля Perl, который я написал около 20 лет назад. Мне нравится этот алгоритм, потому что он не требует никакого цикла или таблицы длин месяцев. Обратите внимание, что ints предполагается 32-битным.

/* 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;
}
Таблица с количеством дней с 1 марта до первого дня данного месяца, вероятно, окажется меньше и быстрее, чем код для вычисления данной формулы, особенно если вас интересуют только даты в диапазоне 2000-2099.
@supercat: Почему бы вам не показать нам, как будет выглядеть этот код?

Согласно даташиту по адресу 0x03 в таблице 4-1 есть поле «День». В конце строки есть краткое описание:

Адрес Бит7:3 Бит2:0 Функция Диапазон 0x03 ... День День 1-7

Это означает, что день может быть установлен на любое число от 1 до 7. Вы можете выбрать свой собственный день недели. В системах POSIX понедельник определяется как 1, я думаю, что это хороший стандарт. Тогда вторник = 2; среда = 3; ...

День = 0 не задокументирован, поэтому не используйте его.

В Linux этот номер легко найти с помощью команды date +%u, которая сегодня отвечает, что сегодня 6суббота. Если вы хотите рассчитать это локально на своем PIC, вам нужно будет найти C-библиотеку, которая реализует формулу, я верю strftime, <time.h>что она делает именно это, но я недостаточно программист на C, чтобы объяснить, как использовать эту конкретную библиотеку. Это широко используемая библиотека, поэтому документацию легко найти.

Понедельник также является днем ​​1 (воскресенье, день 7) в международном стандарте ISO-8601.

День недели произвольный . Вы определяете это. Вы можете использовать юлианское воскресенье = день 1. Вы можете использовать понедельник как день 1, потому что воскресенье - 7-й день. Вы можете использовать пятницу в качестве дня 1, потому что это первый день выходных. Вы можете использовать вторник как день 1, потому что вы ненавидите понедельники.

Это не ответ. Кажется, это какая-то тирада, но я не могу понять, в чем смысл. Первоначальный вопрос заключался в том, как перейти от определенной даты к правильному дню недели.
@DaveTweed Я объясняю, что день недели произвольный. Он не имеет фиксированного значения для RTC. Пока ОП не определит, каким, по его мнению, будет День 1, невозможно получить «правильный день недели», как вы выразились.
Если вы считаете, что вопрос был неполным, то его нужно было опубликовать как комментарий, а не как ответ.
Тот факт, что он произвольный, не означает, что его нельзя рассчитать, как только вы установите свой стандарт.

Я предлагаю вам использовать библиотеку RTClib

#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);
}
Я протестировал его, и он работал отлично
Итак, вы говорите использовать какую-то случайную библиотеку, но не упоминаете, откуда эта библиотека доступна и при каких обстоятельствах ее можно использовать, например, поддерживаемые платформы или лицензия на программное обеспечение.