找到正确的“'algorithm'”以确定给定月份的第一天

Finding the right ''algorithm'' to determine the first day of a given month

我试图制作一个程序来显示特定年份的给定月份的日历,但我真的找不到能够找到该月第一天的算法。

我的程序:

#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("%4d", day);
                    if(++weekDay > 6)
                    {
                        printf("\n");
                        weekDay = 0;
                    }
                    startingDay = weekDay;
                }
            }
        }
        printf("\n");
        return 1;
    }
}

例如,如果我想知道 1800 年的第一个月,它会给出输出:

~/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

但不正确,因为 1800 年 1 月的第一天不是星期六。 Calendar 1800

谁能帮我找到这样的算法。非常感谢!

您在月份处理中出现差一错误。您打印的是 1800 年 2 月。

int months2 = monthDays[months1];

应该是

int months2 = 0;

了解代码的作用后,这很容易调试。

代码以 Wed (int beginning = 3;) 开头。

然后添加从 1800 年开始到指定年份的每一年的天数。

然后将指定月份之前每个月的天数添加到其中。

所以它应该为 1800 年 1 月加零。

至少这是它试图做的。那么为什么它返回 6?好吧,很容易确认从未进入循环。这是对的。而且很容易看出它在 1 月之前的几个月中增加了非零天数。好吧,这显然是错误的。


年的处理也有问题

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

应该是

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

已清理:

#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("%4d", day++);
        dow = ( dow + 1 ) % 7;
        if (!dow)
           printf("\n");
    }

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

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

不清楚上面的公式试图计算什么。貌似是闰年计算,不过year应该是i.

函数 get_first_weekDay 需要一个数组作为第三个参数。但是你称它为

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

修复这些错误似乎没有多大作用。其余的计算相当混乱。我重写了函数get_first_weekDay。请注意,它需要一个数组输入。

#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("%4d", 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