輸入年份與月份,輸出該月份完整日歷(含星期對齊)。支援循環查詢,直到用戶退出。
計算任意日期對應星期幾(0=周一 ... 6=周日,或 1=周日 ... 7=周六):
// 輸入:year, month (1-12), day (1-31)
// 注意:1、2 月視作上一年的 13、14 月
if (month == 1 || month == 2) {
month += 12;
year--;
}
// 公式
int w = (day + 2*month + 3*(month+1)/5 + year + year/4 - year/100 + year/400) % 7;
// 結果:0=周一, 1=周二, ..., 6=周日
// 若需 1=周日: w = (w + 6) % 7 + 1;
bool is_leap(int y) {
return (y % 4 == 0 && y % 100 != 0) || (y % 400 == 0);
}
#include <stdio.h>
#include <stdlib.h>
int days_in_month(int year, int month) {
static const int dim[12] = {31,28,31,30,31,30,31,31,30,31,30,31};
if (month == 2 && ((year%4==0 && year%100!=0) || year%400==0))
return 29;
return dim[month - 1];
}
int weekday_kim_larsen(int year, int month, int day) {
if (month <= 2) { month += 12; year--; }
return (day + 2*month + 3*(month+1)/5 + year + year/4 - year/100 + year/400) % 7;
// 返回 0=Mon ... 6=Sun
}
void print_calendar(int year, int month) {
int dim = days_in_month(year, month);
int w = weekday_kim_larsen(year, month, 1); // 1號星期幾
// 轉換為 1=Sun ... 7=Sat 以便打印對齊
int start_col = (w + 6) % 7 + 1; // 1=Sun, 7=Sat
printf("\n %d 年 %2d 月 日曆\n", year, month);
printf(" 日 一 二 三 四 五 六\n");
printf("=========================\n");
// 打印前導空格
for (int i = 1; i < start_col; i++)
printf(" ");
// 打印日期
for (int d = 1; d <= dim; d++) {
printf("%2d ", d);
if ((d + start_col - 1) % 7 == 0)
printf("\n");
}
printf("\n");
}
int main(void) {
int year, month;
while (1) {
printf("請輸入年份 (0 退出): ");
if (scanf("%d", &year) != 1 || year == 0) break;
printf("請輸入月份 (1-12): ");
if (scanf("%d", &month) != 1 || month < 1 || month > 12) {
printf("月份無效\n");
while (getchar() != '\n'); // 清緩衝區
continue;
}
print_calendar(year, month);
}
return 0;
}
基姆拉爾森公式返回 0=周一。日歷習慣以周日為列首:
// 公式結果 w (0=Mon..6=Sun) -> 列號 1=Sun..7=Sat
int col = (w + 6) % 7 + 1;
`scanf` 失敗時殘留字符需清理,否則陷入死循環:
while (getchar() != '\n');
| 年份 | 月份 | 1號星期 | 天數 | 驗證 |
|---|---|---|---|---|
| 2024 | 2 | 周四 | 29 | 閏年 |
| 2023 | 2 | 周三 | 28 | 平年 |
| 2000 | 1 | 周六 | 31 | 世紀閏年 |
| 1900 | 1 | 周一 | 31 | 非閏年 |
#include <iostream>
#include <iomanip>
using namespace std;
void print_calendar_cpp(int year, int month) {
// ... 同邏輯 ...
cout << "\n " << year << " 年 " << setw(2) << month << " 月 日曆\n";
cout << " 日 一 二 三 四 五 六\n";
cout << "=========================\n";
for (int i = 1; i < start_col; i++) cout << " ";
for (int d = 1; d <= dim; d++) {
cout << setw(2) << d << ' ';
if ((d + start_col - 1) % 7 == 0) cout << '\n';
}
cout << '\n';
}
另一經典公式(結果 0=周六...6=周五):
int zeller(int y, int m, int d) {
if (m < 3) { m += 12; y--; }
int c = y / 100, k = y % 100;
return (d + 13*(m+1)/5 + k + k/4 + c/4 + 5*c) % 7;
}
兩公式本質等價,基姆拉爾森無需分離世紀/年份,代碼更簡潔。