#include <stdio.h>
const char *title_weekday[7] = {" 星期日", " 星期一", " 星期二", " 星期三", " 星期四", " 星期五", " 星期六"};
const char *sky_terms[10] = {"甲", "乙", "丙", "丁", "戊", "己", "庚", "辛", "壬", "癸"};// 天干
const char *gnd_terms[12] = {"子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥"};// 地支
const char *animal_terms[12] = {"鼠", "牛", "虎", "兔", "龍", "蛇", "馬", "羊", "猴", "雞", "狗", "豬"};// 生肖
const unsigned int y1900_2099[] = {
0x04bd8,0x04ae0,0x0a570,0x054d5,0x0d260,0x0d950,0x16554,0x056a0,0x09ad0,0x055d2,
0x04ae0,0x0a5b6,0x0a4d0,0x0d250,0x1d255,0x0b540,0x0d6a0,0x0ada2,0x095b0,0x14977,
0x04970,0x0a4b0,0x0b4b5,0x06a50,0x06d40,0x1ab54,0x02b60,0x09570,0x052f2,0x04970,
0x06566,0x0d4a0,0x0ea50,0x06e95,0x05ad0,0x02b60,0x186e3,0x092e0,0x1c8d7,0x0c950,
0x0d4a0,0x1d8a6,0x0b550,0x056a0,0x1a5b4,0x025d0,0x092d0,0x0d2b2,0x0a950,0x0b557,
0x06ca0,0x0b550,0x15355,0x04da0,0x0a5b0,0x14573,0x052b0,0x0a9a8,0x0e950,0x06aa0,
0x0aea6,0x0ab50,0x04b60,0x0aae4,0x0a570,0x05260,0x0f263,0x0d950,0x05b57,0x056a0,
0x096d0,0x04dd5,0x04ad0,0x0a4d0,0x0d4d4,0x0d250,0x0d558,0x0b540,0x0b6a0,0x195a6,
0x095b0,0x049b0,0x0a974,0x0a4b0,0x0b27a,0x06a50,0x06d40,0x0af46,0x0ab60,0x09570,
0x04af5,0x04970,0x064b0,0x074a3,0x0ea50,0x06b58,0x055c0,0x0ab60,0x096d5,0x092e0,
0x0c960,0x0d954,0x0d4a0,0x0da50,0x07552,0x056a0,0x0abb7,0x025d0,0x092d0,0x0cab5,
0x0a950,0x0b4a0,0x0baa4,0x0ad50,0x055d9,0x04ba0,0x0a5b0,0x15176,0x052b0,0x0a930,
0x07954,0x06aa0,0x0ad50,0x05b52,0x04b60,0x0a6e6,0x0a4e0,0x0d260,0x0ea65,0x0d530,
0x05aa0,0x076a3,0x096d0,0x04afb,0x04ad0,0x0a4d0,0x1d0b6,0x0d250,0x0d520,0x0dd45,
0x0b5a0,0x056d0,0x055b2,0x049b0,0x0a577,0x0a4b0,0x0aa50,0x1b255,0x06d20,0x0ada0,
0x14b63,0x09370,0x049f8,0x04970,0x064b0,0x168a6,0x0ea50,0x06b20,0x1a6c4,0x0aae0,
0x0a2e0,0x0d2e3,0x0c960,0x0d557,0x0d4a0,0x0da50,0x05d55,0x056a0,0x0a6d0,0x055d4,
0x052d0,0x0a9b8,0x0a950,0x0b4a0,0x0b6a6,0x0ad50,0x055a0,0x0aba4,0x0a5b0,0x052b0,
0x0b273,0x06930,0x07337,0x06aa0,0x0ad50,0x14b55,0x04b60,0x0a570,0x054e4,0x0d160,
0x0e968,0x0d520,0x0daa0,0x16aa6,0x056d0,0x04ae0,0x0a9d4,0x0a2d0,0x0d150,0x0f252,
0x0d520
}; // 西元 1900 - 2100 年農曆資料表
// 位元: 16 , 15:4 , 3:0
// 編碼: 閏月 大/小, 各大/小月, 潤月月份
const int lunar_base_y1900[4] = {5, 11, 1, 31}; // 1900 年初(1/31前)是己(5)亥(11)年, 1/31 開始是庚子年正月初一
const int year_normal_days[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};// 常(規)年 = 365 天
const int year_leap_days[12] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};// 閏(補)年 = 366 天
bool is_leap_year(int ad_year) { // 判斷公(西)元是潤年的條件: (4 倍數且非 100 倍數) 或是 400 倍數
return (ad_year % 4 == 0) && (ad_year % 100 != 0) || (ad_year % 400 == 0);
}
int days_of_lunar_year(int ad_year) {// 當年農曆天數
if (ad_year < 1900 || ad_year > 2100) return -1;
unsigned int idx = ad_year - 1900;
unsigned int info = y1900_2099[idx];// 查表
int lunar_days = 29 * 12 + (info & 0xf ? (info & 0x10000 ? 30 : 29) : 0); // 小月 29 天, 共 12 個月, 外加閏月天數
for (unsigned int bit_test = 0x8000; bit_test >= 0x10; bit_test >>= 1) {// 補大月的天數
if (info & bit_test) lunar_days ++;
}
return lunar_days;
}
bool next_lunar_new_year(int ad_year, int *ad_month, int *ad_day) { // 明年的春節日
if (ad_year < 1900 || ad_year > 2100) return false;
*ad_day += days_of_lunar_year(ad_year) - (is_leap_year(ad_year) ? 366 : 365); // 新的春節日, 只需補足陰陽曆日差天數
if (*ad_day > 31) {// 當日期超過 31 天(1月)需修正
*ad_day -= 31;
*ad_month = 2;// 春節會跨到 2 月
} else if (*ad_day <= 0) {// 或是日期不足時也需修正
*ad_day += 31;
*ad_month = 1;// 春節回落至 1 月
}
return true;
}
int *find_lunar_new_year(int ad_year) {
if (ad_year < 1900 || ad_year > 2100) return nullptr;
static int day_info[2] = {1, 31};
int month = lunar_base_y1900[2];
int day = lunar_base_y1900[3];
for (int year = 1900; year < ad_year; year++) {
if (! next_lunar_new_year(year, &month, &day)) break;
}
day_info[0] = month;
day_info[1] = day;
return day_info;
}
int main() {
int year = 2024;
int *day_info = find_lunar_new_year(year);
if (day_info == nullptr) return -1;
int month = day_info[0];
unsigned int idx = year - 1900;
int sky = (idx + 1 + lunar_base_y1900[0]) % 10;
int gnd = (idx + 1 + lunar_base_y1900[1]) % 12;
printf(" %s%s(%s)年-月曆\t\t\t\t%8d 月\t\t\t\t西元%8d 年\n",
sky_terms[sky], gnd_terms[gnd], animal_terms[gnd],
month, year
);
int y0 = year - 1;// 註: 公(西)元 1 年 1 月 1 日 是 星期日 (weekday = 0)
int weekday = year + y0/4 + y0/400 - y0/100;// 潤年補天數
const int *days_of_month = is_leap_year(year) ? year_leap_days : year_normal_days;
for (int i = 0; i + 1 < month; i ++) weekday += days_of_month[i];
weekday %= 7;
for (int i = 0; i < 7; i++) {
printf("%s\t", title_weekday[i]);
}
if (weekday != 0) {
printf("\n");
}
int position = 0;
while (position < weekday) {
if (++ position % 7 == 0) printf("\n");
printf(" \t");
}
for (int day = 1; day <= days_of_month[month - 1]; day ++) {
if (position ++ % 7 == 0) printf("\n");
printf(day == day_info[1] ? "春節%4d\t" : "%8d\t", day);
}
printf("\n\n");
return 0;
}
沒有留言:
張貼留言