[c] C Program to find day of week given date

Is there a way to find out day of the week given date in just one line of C code?

For example

Given 19-05-2011(dd-mm-yyyy) gives me Thursday

This question is related to c

The answer is


A one-liner is unlikely, but the strptime function can be used to parse your date format and the struct tm argument can be queried for its tm_wday member on systems that modify those fields automatically (e.g. some glibc implementations).

int get_weekday(char * str) {
  struct tm tm;
  memset((void *) &tm, 0, sizeof(tm));
  if (strptime(str, "%d-%m-%Y", &tm) != NULL) {
    time_t t = mktime(&tm);
    if (t >= 0) {
      return localtime(&t)->tm_wday; // Sunday=0, Monday=1, etc.
    }
  }
  return -1;
}

Or you could encode these rules to do some arithmetic in a really long single line:

  • 1 Jan 1900 was a Monday.
  • Thirty days has September, April, June and November; all the rest have thirty-one, saving February alone, which has twenty-eight, rain or shine, and on leap years, twenty-nine.
  • A leap year occurs on any year evenly divisible by 4, but not on a century unless it is divisible by 400.

EDIT: note that this solution only works for dates after the UNIX epoch (1970-01-01T00:00:00Z).


Not in one line of code, there's nothing for dealing with dates in the C standard library. It would be fairly simple to write a function based on the Doomsday algorithm, or similar, though.


#include<stdio.h>
int main(void) {
int n,y;
int ly=0;
int mon;
printf("enter the date\n");
scanf("%d",&n);
printf("enter the month in integer\n");
scanf("%d",&mon);
mon=mon-1;
printf("enter year\n");
scanf("%d",&y);
int dayT;
dayT=n%7;
if((y%4==0&&y%100!=0)|(y%4==0&&y%100==0&&y%400==0))
{
    ly=y;
    printf("the given year is a leap year\n");
}
char a[12]={6,2,2,5,0,3,5,1,4,6,2,4};
if(ly!=0)
{
    a[0]=5;
    a[1]=1;
}
int m,p;
m=a[mon];
int i,j=0,t=1;
for(i=1600;i<=3000;i++)
{
 i=i+99;
    if(i<y)
    {

        if(t==1)
        {
        p=5;t++;
        }
        else if(t==2)
        {
            p=3;
            t++;
        }
        else if(t==3)
        {
            p=1;
            t++;
        }
        else
        {
            p=0;
            t=1;
        }

}}
int q,r,s;
q=y%100;
r=q%7;
s=q/4;
int yTerm;
yTerm=p+r+s;
int w=dayT+m+yTerm;
w=w%7;
if(w==0)
printf("SUNDAY");
else if(w==1)
printf("MONDAY");
else if(w==2)
printf("TUESDAY");
else if(w==3)
printf("WEDNESDAY");
else if(w==4)
printf("THURSDAY");
else if(w==5)
printf("FRIDAY");
else
printf("SATURDAY");
return 0;

}


This is my implementation. It's very short and includes error checking. If you want dates before 01-01-1900, you could easily change the anchor to the starting date of the Gregorian calendar.

#include <stdio.h>

int main(int argv, char** arv) {
    int month[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    char* day[] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};   
    int d, m, y, i; 

    printf("Fill in a date after 01-01-1900 as dd-mm-yyyy: ");
    scanf("%d-%d-%d",  &d, &m, &y);

    // correction for leap year
    if (y % 4 == 0 && (y % 100 != 0 || y % 400 == 0))
        month[1] = 29;

    if (y < 1900 || m < 1 || m > 12 || d < 1 || d > month[m - 1]) {
        printf("This is an invalid date.\n");
        return 1;
    }

    for (i = 1900; i < y; i++)
        if (i % 4 == 0 && (i % 100 != 0 || i % 400 == 0))
            d += 366;
        else
            d += 365;

    for (i = 0; i < m - 1; i++) 
        d += month[i];

    printf("This is a %s.\n", day[d % 7]);
    return 0;
}

The answer I came up with:

const int16_t TM_MON_DAYS_ACCU[12] = {
    0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
};

int tm_is_leap_year(unsigned year) {
    return ((year & 3) == 0) && ((year % 400 == 0) || (year % 100 != 0));
}

// The "Doomsday" the the day of the week of March 0th,
// i.e the last day of February.
// In common years January 3rd has the same day of the week,
// and on leap years it's January 4th.
int tm_doomsday(int year) {
    int result;
    result  = TM_WDAY_TUE;
    result += year;       // I optimized the calculation a bit:
    result += year >>= 2; // result += year / 4
    result -= year /= 25; // result += year / 100
    result += year >>= 2; // result += year / 400
    return result;
}

void tm_get_wyday(int year, int mon, int mday, int *wday, int *yday) {
    int is_leap_year = tm_is_leap_year(year);
    // How many days passed since Jan 1st?
    *yday = TM_MON_DAYS_ACCU[mon] + mday + (mon <= TM_MON_FEB ? 0 : is_leap_year) - 1;
    // Which day of the week was Jan 1st of the given year?
    int jan1 = tm_doomsday(year) - 2 - is_leap_year;
    // Now just add these two values.
    *wday = (jan1 + *yday) % 7;
}

with these defines (matching struct tm of time.h):

#define TM_WDAY_SUN 0
#define TM_WDAY_MON 1
#define TM_WDAY_TUE 2
#define TM_WDAY_WED 3
#define TM_WDAY_THU 4
#define TM_WDAY_FRI 5
#define TM_WDAY_SAT 6

#define TM_MON_JAN  0
#define TM_MON_FEB  1
#define TM_MON_MAR  2
#define TM_MON_APR  3
#define TM_MON_MAY  4
#define TM_MON_JUN  5
#define TM_MON_JUL  6
#define TM_MON_AUG  7
#define TM_MON_SEP  8
#define TM_MON_OCT  9
#define TM_MON_NOV 10
#define TM_MON_DEC 11

#include<stdio.h>
#include<math.h>
#include<conio.h>
int fm(int date, int month, int year) {
int fmonth, leap;
if ((year % 100 == 0) && (year % 400 != 0))
leap = 0;
   else if (year % 4 == 0)
  leap = 1;
else
  leap = 0;

  fmonth = 3 + (2 - leap) * ((month + 2) / (2 * month))+ (5 * month + month / 9) / 2;

 fmonth = fmonth % 7;

  return fmonth;
}
int day_of_week(int date, int month, int year) {

   int dayOfWeek;
   int YY = year % 100;
   int century = year / 100;

   printf("\nDate: %d/%d/%d \n", date, month, year);

   dayOfWeek = 1.25 * YY + fm(date, month, year) + date - 2 * (century % 4);

   //remainder on division by 7
   dayOfWeek = dayOfWeek % 7;

   switch (dayOfWeek) {
      case 0:
         printf("weekday = Saturday");
         break;
      case 1:
         printf("weekday = Sunday");
         break;
      case 2:
         printf("weekday = Monday");
         break;
      case 3:
         printf("weekday = Tuesday");
         break;
      case 4:
         printf("weekday = Wednesday");
         break;
      case 5:
         printf("weekday = Thursday");
         break;
      case 6:
         printf("weekday = Friday");
         break;
      default:
         printf("Incorrect data");
   }
   return 0;
}
int main() {
   int date, month, year;

   printf("\nEnter the year ");
   scanf("%d", &year);

   printf("\nEnter the month ");
   scanf("%d", &month);

   printf("\nEnter the date ");
   scanf("%d", &date);

   day_of_week(date, month, year);

   return 0;
}

OUTPUT: Enter the year 2012

Enter the month 02

Enter the date 29

Date: 29/2/2012

weekday = Wednesday


/*
Program to calculate the day on a given date by User
*/

#include<stdio.h>
#include<conio.h>
#include<process.h>
void main()
{
int dd=0,mm=0,i=0,yy=0,odd1=0,todd=0;//variable declaration for inputing the date
int remyr=0,remyr1=0,lyrs=0,oyrs=0,cyr=0,upyr=0,leap=0;//variable declaration for calculation of odd days
int montharr[12]={31,28,31,30,31,30,31,31,30,31,30,31};//array of month days
clrscr();
printf("Enter the date as DD-MM-YY for which you want to know the day\t:");
scanf("%d%d%d",&dd,&mm,&yy);  //input the date
/*
check out correct date or not?
*/
if(yy%100==0)
    {
    if(yy%400==0)
        {
        //its the leap year
        leap=1;
        if(dd>29&&mm==2)
            {

            printf("You have entered wrong date");
            getch();
            exit(0);
            }
        }
    else if(dd>28&&mm==2)
        {
        //not the leap year
        printf("You have entered wrong date");
        getch();
        exit(0);

        }
    }
else if(yy%4==0)
    {
    //again leap year
    leap=1;
    if(dd>29&mm==2)
        {
        printf("You have entered wrong date");
        getch();
        exit(0);

        }
    }
else if(dd>28&&mm==2)
    {
    //not the leap year
    printf("You have entered wrong date");
    getch();
    exit(0);

    }
//if the leap year feb month contains 29 days
if(leap==1)
{
montharr[1]=29;

}
//check date,month,year should not be beyond the limits

if((mm>12)||(dd>31)|| (yy>5000))
    {
    printf("Your date is wrong");
    getch();
    exit(0);

    }
//odd months should not contain more than 31 days
if((dd>31 && (mm == 1||mm==3||mm==5||mm==7||mm==8||mm==10||mm==12)))
    {
    printf("Your date is wrong");
    getch();
    exit(0);

    }
//even months should not contains more than 30 days

if((dd>30 && (mm == 4||mm==6||mm==9||mm==11)))
    {
    printf("Your date is wrong");
    getch();
    exit(0);

    }

//logic to calculate odd days.....
printf("\nYou have entered date: %d-%d-%d ",dd,mm,yy);
remyr1=yy-1;
remyr=remyr1%400;

cyr=remyr/100;
if(remyr==0)
    {
    oyrs=0;
    }
else if(cyr==0 && remyr>0)
    {
    oyrs=0;
    }


else if(cyr==1)
    {
    oyrs=5;
    }
else if(cyr==2)
    {
    oyrs=3;
    }
else if(cyr==3)
    {
    oyrs=1;
    }

    upyr=remyr%100;
    lyrs=upyr/4;
    odd1=lyrs+upyr;
    odd1=odd1%7;
    odd1=odd1+oyrs;
    for(i=0;i<mm-1;i++)
        {
        odd1=odd1+montharr[i];
        }
    todd=odd1+dd;
    if(todd>7)
        todd=todd%7;    //total odd days gives the re quired day....
    printf("\n\nThe day on %d-%d-%d :",dd,mm,yy);

    if(todd==0)
        printf("Sunday");
    if(todd==1)
        printf("Monday");
    if(todd==2)
        printf("Tuesday");
    if(todd==3)
        printf("Wednesday");
    if(todd==4)
        printf("Thrusday");
    if(todd==5)
        printf("Friday");
    if(todd==6)
        printf("Saturday");
getch();
}

As reported also by Wikipedia, in 1990 Michael Keith and Tom Craver published an expression to minimise the number of keystrokes needed to enter a self-contained function for converting a Gregorian date into a numerical day of the week.

The expression does preserve neither y nor d, and returns a zero-based index representing the day, starting with Sunday, i.e. if the day is Monday the expression returns 1.

A code example which uses the expression follows:

int d    = 15   ; //Day     1-31
int m    = 5    ; //Month   1-12`
int y    = 2013 ; //Year    2013` 

int weekday  = (d += m < 3 ? y-- : y - 2, 23*m/9 + d + 4 + y/4- y/100 + y/400)%7;  

The expression uses the comma operator, as discussed in this answer.

Enjoy! ;-)



This one works: I took January 2006 as a reference. (It is a Sunday)

int isLeapYear(int year) {

     if(((year%4==0)&&(year%100!=0))||((year%400==0))) 
        return 1;
     else 
        return 0;

 }

int isDateValid(int dd,int mm,int yyyy) {

    int isValid=-1; 
    if(mm<0||mm>12) {
        isValid=-1;
    }
    else {

    if((mm==1)||(mm==3)||(mm==5)||(mm==7)||(mm==8)||(mm==10)||(mm==12)) {
           if((dd>0)&&(dd<=31))
             isValid=1;
    }  else if((mm==4)||(mm==6)||(mm==9)||(mm==11)) {
         if((dd>0)&&(dd<=30))
             isValid=1;
    }  else {
             if(isLeapYear(yyyy)){
                 if((dd>0)&&dd<30)
                     isValid=1;
             } else {
                   if((dd>0)&&dd<29)
                     isValid=1;
             }
        }  



    }
               return isValid;



 }


int calculateDayOfWeek(int dd,int mm,int yyyy)  {

                if(isDateValid(dd,mm,yyyy)==-1) {
                    return -1;
                }

                 int days=0;
                  int i; 

                   for(i=yyyy-1;i>=2006;i--) {
                         days+=(365+isLeapYear(i));

                     }
                     printf("days after years is %d\n",days);

                   for(i=mm-1;i>0;i--) {

                       if((i==1)||(i==3)||(i==5)||(i==7)||(i==8)||(i==10)) {

                           days+=31;
                       }
                       else if((i==4)||(i==6)||(i==9)||(i==11)) {
                           days+=30;
                       } else {

                           days+= (28+isLeapYear(i));

                       }


                   }
                       printf("days after months is %d\n",days);

                   days+=dd;

                   printf("days after days is %d\n",days);

                   return ((days-1)%7);                


              }

Here's a C99 version based on wikipedia's article about Julian Day

#include <stdio.h>

const char *wd(int year, int month, int day) {
  /* using C99 compound literals in a single line: notice the splicing */
  return ((const char *[])                                         \
          {"Monday", "Tuesday", "Wednesday",                       \
           "Thursday", "Friday", "Saturday", "Sunday"})[           \
      (                                                            \
          day                                                      \
        + ((153 * (month + 12 * ((14 - month) / 12) - 3) + 2) / 5) \
        + (365 * (year + 4800 - ((14 - month) / 12)))              \
        + ((year + 4800 - ((14 - month) / 12)) / 4)                \
        - ((year + 4800 - ((14 - month) / 12)) / 100)              \
        + ((year + 4800 - ((14 - month) / 12)) / 400)              \
        - 32045                                                    \
      ) % 7];
}

int main(void) {
  printf("%d-%02d-%02d: %s\n", 2011, 5, 19, wd(2011, 5, 19));
  printf("%d-%02d-%02d: %s\n", 2038, 1, 19, wd(2038, 1, 19));
  return 0;
}

By removing the splicing and spaces from the return line in the wd() function, it can be compacted to a 286 character single line :)


For Day of Week, years 2000 - 2099.

uint8_t rtc_DayOfWeek(uint8_t year, uint8_t month, uint8_t day)
{
    //static const uint8_t month_offset_table[] = {0, 3, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5}; // Typical table.

    // Added 1 to Jan, Feb. Subtracted 1 from each instead of adding 6 in calc below.

    static const uint8_t month_offset_table[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};

    // Year is 0 - 99, representing years 2000 - 2099

    // Month starts at 0.

    // Day starts at 1.

    // Subtract 1 in calc for Jan, Feb, only in leap years.
    // Subtracting 1 from year has the effect of subtracting 2 in leap years, subtracting 1 otherwise.
    // Adding 1 for Jan, Feb in Month Table so calc ends up subtracting 1 for Jan, Feb, only in leap years.
    // All of this complication to avoid the check if it is a leap year.
    if (month < 2) {
        year--;
    }

    // Century constant is 6. Subtract 1 from Month Table, so difference is 7.

    // Sunday (0), Monday (1) ...

    return (day + month_offset_table[month] + year + (year >> 2)) % 7;

} /* end rtc_DayOfWeek() */

#include<stdio.h>
static char day_tab[2][13] = {
        {0,31,28,31,30,31,30,31,31,30,31,30,31},
        {0,31,29,31,30,31,30,31,31,30,31,30,31}
        };
int main()
{
     int year,month;
     scanf("%d%d%d",&year,&month,&day);
     printf("%d\n",day_of_year(year,month,day));
     return 0;
}
int day_of_year(int year ,int month,int day)
{
        int i,leap;
        leap = year%4 == 0 && year%100 != 0 || year%400 == 0;
        if(month < 1 || month >12)
        return -1;
        if (day <1 || day > day_tab[leap][month])
        return -1;
        for(i= 1;i<month ; i++)
        {
                day += day_tab[leap][year];
        }
        return day;
}

Here is a simple code that I created in c that should fix your problem :

#include <conio.h>

int main()
{
  int y,n,oy,ly,td,a,month,mon_,d,days,down,up; // oy==ordinary year, td=total days, d=date

    printf("Enter the year,month,date: ");
    scanf("%d%d%d",&y,&month,&d);
    n= y-1; //here we subtracted one year because we have to find on a particular day of that year, so we will not count whole year.
    oy= n%4;

    if(oy==0) // for leap year
      {
         mon_= month-1;
         down= mon_/2;  //down means months containing 30 days.
           up= mon_-down; // up means months containing 31 days.
           if(mon_>=2)
             {
               days=(up*31)+((down-1)*30)+29+d; // here in down case one month will be of feb so we subtracted 1 and after that seperately
               td= (oy*365)+(ly*366)+days;      // added 29 days as it is the if block of leap year case.
             }
           if(mon_==1)
             {
               days=(up*31)+d;
               td= (oy*365)+(ly*366)+days;
             } 
           if(mon_==0)
             {
               days= d;
               td= (oy*365)+(ly*366)+days;
             }    
      }
    else
      {
         mon_= month-1;
         down= mon_/2;
           up= mon_-down;
           if(mon_>=2)
             {
               days=(up*31)+((down-1)*30)+28+d;
               td= (oy*365)+(ly*366)+days;
             }
           if(mon_==1)
             {
               days=(up*31)+d;
               td= (oy*365)+(ly*366)+days;
             } 
           if(mon_==0)
             {
               days= d;
               td= (oy*365)+(ly*366)+days;
             }    
      }  

    ly= n/4;
     a= td%7;

     if(a==0)
       printf("\nSunday");
     if(a==1)
       printf("\nMonday");
     if(a==2)
       printf("\nTuesday");
     if(a==3)
       printf("\nWednesday");
     if(a==4)
       printf("\nThursday");
     if(a==5)
       printf("\nFriday");
     if(a==6)
       printf("\nSaturday");
  return 0;   
}