Arduino: How to calculate day of week from date

 I wanted to add some code to a program that could detect if a clock was running during daylight saving and making an appropriate adjustment. To do this I needed to be able to test if a day was a Sunday (as that is the day when clocks are usually moved back and forth depending upon season).

Some real-time clock libraries have this function built in but the one I was targeting <RTCZero> was going to need some help.

I developed a function to calculate a day of the week from a supplied date and tested it with an interactive program (using the Serial Monitor of the IDE) that will run just fine on an Arduino UNO. The serial speed is set at only 9600 so that the code works with the IDE2 Serial Monitor (still broken I note) but if you are using the earlier version of the IDE then you can set a higher rate.

To test the function, just type a date in dd/mm/yyyy format (so a UK format) into the outbound message box of the Serial Monitor and hit the <Return> key. You do not need to set leading zero values for the day or month - 1/2/2022 is just fine.

The day of the week function returns a 1 for a Sunday through a 7 for a Saturday.

The first listing is easy to copy an paste into your IDE and the second is more human readable.

char dayList[][10] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}; char dateBuffer[11]; char sChar; int buffCount = 0; template<class T> inline Print &operator<<(Print &obj, T arg) { obj.print(arg); return obj;} void setup() { Serial.begin(9600); // slow so this works with IDE 2 Serial monitor while (!Serial) {} clearBuffer(); Serial << "Please set Serial Monitor line ending to NL & CR\n"; Serial << "Then enter dates in dd/mm/yyyy format and press <return>\n"; } void loop() { if ( Serial.available()){     sChar = Serial.read();     switch (sChar){      case 10:      case 13:         if(buffCount >= 8){          String dt = dateBuffer;          int daySlash = dt.indexOf(('/'));          int monthSlash = dt.indexOf('/', daySlash + 1);          int res = dayOfWeek(dt.substring(0, daySlash).toInt(), dt.substring(daySlash + 1, monthSlash).toInt(), dt.substring(monthSlash + 1).toInt());          Serial << '\n' << dateBuffer << " is a " << dayList[res -1] << '\n';          Serial << "Try another one\n";         }         clearBuffer();         break;      default:         if(buffCount <= 10){          dateBuffer[buffCount++] = sChar;         }     } } } int dayOfWeek(int d, int m, int y){ // note arguments are not validated bool leapYear = false; if((y % 4 == 0 && y % 100 != 0) || y % 400 == 0){     leapYear = true; } while (y > 2299){ y -=400;} // extend function to before 1900 and beyond 2299 while (y < 1900) {y += 400;} int century = y / 100; int yearInC = y % 100; int cValue = 0; // default for 21st C switch(century){     case 19:      cValue = 1;      break;     case 21:      cValue = 5;      break;     case 22:      cValue = 3;      break; } int mValue = 0; // good for month 10 switch(m) {     case 1:      if(leapYear) { mValue = 6;}      break;     case 2:      mValue = leapYear ? 2 : 3;      break;     case 3:     case 11:      mValue = 3;      break;     case 4:     case 7:      mValue = 6;      break;     case 5:      mValue = 1;      break;     case 6:      mValue = 4;      break;     case 8:      mValue = 2;      break;     case 9:     case 12:      mValue = 5;      break; } int aValue = d + mValue + yearInC + cValue + yearInC / 4; int dValue = aValue % 7; return dValue > 0 ? dValue : 7; // Sunday 1, Saturday 7 } void clearBuffer(){ memset(dateBuffer, 0, 11); buffCount = 0; }


char dayList[][10] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
char dateBuffer[11];
char sChar;
int buffCount = 0;

template<class T> inline Print &operator<<(Print &obj, T arg) {
  obj.print(arg); return obj;}

void setup() {
  Serial.begin(9600); // slow so this works with IDE 2 Serial monitor
  while (!Serial) {}
  clearBuffer();
  Serial << "Please set Serial Monitor line ending to NL & CR\n";
  Serial << "Then enter dates in dd/mm/yyyy format and press <return>\n";
}

void loop() {
  if ( Serial.available()){
    sChar = Serial.read();
    switch (sChar){
      case 10:
      case 13:
        if(buffCount >= 8){
          String dt = dateBuffer;
          int daySlash = dt.indexOf(('/'));
          int monthSlash = dt.indexOf('/', daySlash + 1);
          int res = dayOfWeek(dt.substring(0, daySlash).toInt(), dt.substring(daySlash + 1, monthSlash).toInt(), dt.substring(monthSlash + 1).toInt());
          Serial << '\n' << dateBuffer << " is a " << dayList[res -1] << '\n';
          Serial << "Try another one\n";
        }
        clearBuffer();
        break;
      default:
        if(buffCount <= 10){
          dateBuffer[buffCount++] = sChar;
        }
    }
  }
}
int dayOfWeek(int d, int m, int y){
  // note arguments are not validated
  bool leapYear = false;
  if((y % 4 == 0 && y % 100 != 0) || y % 400 == 0){
    leapYear = true;
  }
  while (y > 2299){ y -=400;} // extend function to before 1900 and beyond 2299
  while (y < 1900) {y += 400;}
  int century = y / 100;
  int yearInC = y % 100;
  int cValue = 0; // default for 21st C
  switch(century){
    case 19:
      cValue = 1;
      break;
    case 21:
      cValue = 5;
      break;
    case 22:
      cValue = 3;
      break;
  }
  int mValue = 0; // good for month 10
  switch(m) {
    case 1:
      if(leapYear) { mValue = 6;}
      break;
    case 2:
      mValue = leapYear ? 2 : 3;
      break;
    case 3:
    case 11:
      mValue = 3;
      break;
    case 4:
    case 7:
      mValue = 6;
      break;
    case 5:
      mValue = 1;
      break;
    case 6:
      mValue = 4;
      break;
    case 8:
      mValue = 2;
      break;
    case 9:
    case 12:
      mValue = 5;
      break;
  }
  int aValue = d + mValue + yearInC + cValue + yearInC / 4;
  int dValue = aValue % 7;
  return dValue > 0 ? dValue : 7; // Sunday 1, Saturday 7
}
void clearBuffer(){
  memset(dateBuffer, 0, 11);
  buffCount = 0;
}

Let me know if you hit any problems.


Comments

Popular posts from this blog

Unicode output from an Arduino.

Arduino: How to scroll long text on OLED screen

Arduino Regular Expressions