Home > Software engineering >  Finding the right ''algorithm'' to determine the first day of a given month
Finding the right ''algorithm'' to determine the first day of a given month

Time:11-26

I was trying to make a program that shows the calendar of a given month of a particular year, but I can't really find an algorithm that does find the first day of the month.

My Program:

#include <stdio.h>
#include <stdlib.h>

int get_first_weekDay(int year, int months1, int monthDays[months1])
{
    int day;
    int months2 = monthDays[months1];
    int beginning = 3;
    while(months1 > 0)
    {
        months2 = months2   monthDays[months1];
        months1 = months1 - 1;
    }
    for (int i = 1800; i < year; i  )
    {
        if ((i % 4 == 0 && year % 100 != 0) || year % 400 == 0)
        {
            beginning = beginning   366;
        }
        else
        {
            beginning = beginning   365;
        }
    }
    day = (beginning   months2) % 7;
    return day;
}

int main(int argc, char* argv[])
{
    if(argc != 3)
    {
        printf("Usage: ./calendar year month \n");
        return 1;
    }
    int year = atoi(argv[1]);
    int months1 = atoi(argv[2]) - 1;
    int day = 0, dayInMonth, weekDay = 0, startingDay ,month;
    char *months[] = {"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
    int monthDays[] = {31,28,31,30,31,30,31,31,30,31,30,31};
    if (argc == 3)
    {
        if((year % 4 == 0 && year % 100 != 0) || year % 400 == 0)
        {
            monthDays[1] = 29;
        }
        startingDay = get_first_weekDay(year, months1, &monthDays[months1]);
        for(month = 0; month < 12; month  )
        {
            if(months1 == month)
            {
                dayInMonth = monthDays[month]   1;
                printf("           %s %d          \n ---------------------------", months[month], year);
                printf("\n Sun Mon Tue Wed Thu Fri Sat\n");
                for(weekDay = 0; weekDay < startingDay; weekDay  )
                {
                    printf("    ");
                }
                for(day = 1; day < dayInMonth; day  )
                {
                    printf("M", day);
                    if(  weekDay > 6)
                    {
                        printf("\n");
                        weekDay = 0;
                    }
                    startingDay = weekDay;
                }
            }
        }
        printf("\n");
        return 1;
    }
}

For example if I wanted to know the 1st month of the year 1800, it gives me as output:

~/calendar/ $ ./calendar 1800 1
           Jan 1800          
 ---------------------------
 Sun Mon Tue Wed Thu Fri Sat
                           1
   2   3   4   5   6   7   8
   9  10  11  12  13  14  15
  16  17  18  19  20  21  22
  23  24  25  26  27  28  29
  30  31

But not correct, as the first day of the month Jan 1800 isn't Saturday. Calendar 1800

Could somebody help me with finding such an algorithm. I would really appreciate it!

CodePudding user response:

You have an off by one error in the month handling. You were printing Feb 1800.

int months2 = monthDays[months1];

should be

int months2 = 0;

This was easy to debug after understanding what the code does.

The code starts with Wed (int beginning = 3;).

It then adds to it the days of every year leading to the specified year, starting in 1800.

It then adds to it the days of every month leading up to the specified month.

So it should be adding zero for Jan 1800.

That's what it tries to do, at least. So why is it returning 6? Well, it's easy to confirm the loop is never entered. This is correct. And it's also easy to see it's adding a non-zero number of days for the months leading up the January. Well, that's obviously wrong.


There's also a problem in the handling of years.

(i % 4 == 0 && year % 100 != 0) || year % 400 == 0

should be

(i % 4 == 0 && i % 100 != 0) || i % 400 == 0

Cleaned up:

#include <stdio.h>
#include <stdlib.h>

static const char *months[] = {"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
static const int monthDays[] = {31,28,31,30,31,30,31,31,30,31,30,31};

// Returns 0 or 1
static int is_leap_year(int year) {
    return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0;
}

static int get_days_in_month(int year, int month0) {
    if (month0 == 1) {
        int leap_days = is_leap_year(year);
        return 28   leap_days;
    } else {
        return monthDays[month0];
    }
}

static int get_dow(int year, int month0, int day) {
    int dow = 3;  // 1800-01-01 is a Wednesday.

    // For each year up to provided year (exclusive), starting with 1800.
    while (year-- > 1800) {
        int leap_days = is_leap_year(year);
        dow  = 365   leap_days;
    }

    // For each month up to provided month (exclusive)
    while (month0--)
        dow  = monthDays[month0];

    // For each day up to the provided day (exlcusive)
    dow  = day - 1;

    return dow % 7;
}

int main(int argc, char* argv[]) {
    if(argc != 3) {
        fprintf(stderr, "Usage: ./calendar year month \n");
        return 1;
    }

    int year   = atoi(argv[1]);
    int month0 = atoi(argv[2]) - 1;  // 0-based month
    int day    = 1;                  // 1-based day

    int dow      = get_dow(year, month0, day);
    int num_days = get_days_in_month(year, month0);

    printf("          %s %d\n", months[month0], year);
    printf(" ---------------------------\n");
    printf(" Sun Mon Tue Wed Thu Fri Sat\n");

    for (int i=0; i<dow;   i)
       printf("    ");

    while (day <= num_days) {
        printf("M", day  );
        dow = ( dow   1 ) % 7;
        if (!dow)
           printf("\n");
    }

    if (dow)
        printf("\n");

    return 0;
}

CodePudding user response:

for (int i = 1800; i < year; i  )
{
    ...
    if ((i % 4 == 0 && year % 100 != 0) || year % 400 == 0)
}

It's not clear what the above formula is trying to calculate. It looks like leap year calculation, but year should be i.

The function get_first_weekDay expects an array for the 3rd parameter. But you are calling it as

startingDay = get_first_weekDay(year, months1, &monthDays[months1]);

Fixing these errors doesn't seem to do much. The rest of the calculation is rather confusing. I rewrote the function get_first_weekDay. Note that it expects an array input.

#include <stdio.h>
#include <stdlib.h>

int is_leap_year(int y)
{ return (y % 4 == 0 && y % 100 != 0) || (y % 400 == 0); }

int get_first_weekday(int year, int month, int days_in_month[12])
{
    int beginning = 3; //1800, Jan, 1 is wedndsay (3)
    for (int y = 1800; y < year; y  )
        beginning  = is_leap_year(y) ? 366 : 365;
    for (int m = 0; m < month; m  )
        beginning  = days_in_month[m];
    return beginning % 7;
}

void print_calendar(int year, int month)
{
    month--;
    const char* months[] = { "Jan","Feb","Mar","Apr","May","Jun",
        "Jul","Aug","Sep","Oct","Nov","Dec" };
    int days_in_month[] = { 31,28,31,30,31,30,31,31,30,31,30,31 };
    if (is_leap_year(year))
        days_in_month[1] = 29;
    int first_week_day = get_first_weekday(year, month, days_in_month);
    printf("           %s %d            \n", months[month], year);
    printf(" ---------------------------\n");
    printf(" Sun Mon Tue Wed Thu Fri Sat\n");
    for (int wkday = 0; wkday < first_week_day; wkday  )
        printf("    ");
    for (int day = 1; day < days_in_month[month]   1; day  )
    {
        printf("M", day);
        if(((day   first_week_day) % 7) == 0)
            printf("\n");
    }
    printf("\n\n");
}

int main(void)
{
    for (int m = 1; m < 4; m  ) print_calendar(1800, m);
    for (int m = 8; m <= 12; m  ) print_calendar(2021, m);
    return 0;
}

Run

  • Related