用來推算未來 24 節氣日期, 雖然推算出來的詳細時間不準, 但日期很準, 若改用今年的小寒時間當基底, 推算未 50 或過去 50 年內的 24 節氣日期, 應該堪用.
#include <stdio.h>
#include <time.h>
const char *climate24_terms[24] = {
"小寒", "大寒", "立春", "雨水", "驚蟄", "春分",//: 節氣索引 5, 日時 = 夜時
"清明", "穀雨", "立夏", "小滿", "芒種", "夏至",//: 節氣索引 11, 日時 > 夜時
"小暑", "大暑", "立秋", "處暑", "白露", "秋分",//: 節氣索引 17, 日時 = 夜時
"寒露", "霜降", "立冬", "小雪", "大雪", "冬至" //: 節氣索引 23, 日時 < 夜時
};//24節氣始於年初小寒,北半球:4(X)季始於立(X), 春分秋分日夜等長, 夏至日長夜短, 冬至夜長日短
bool is_leap_year(int ad_year) { // 公(西)元是潤年的條件: (4 倍數且非 100 倍數) 或是 400 倍數
return (ad_year % 4 == 0) && (ad_year % 100 != 0) || (ad_year % 400 == 0);
}
int *find_climate24(int ad_year) {// 推算當年農曆 24 節氣的陽曆日期
static const int table_2024[24][4] = {
{ 1, 6, 4, 49}, { 1, 20, 22, 7}, { 2, 4, 16, 27}, { 2, 19, 12, 13}, { 3, 5, 10, 23}, { 3, 20, 11, 6},// [ 5][]: 春分
{ 4, 4, 15, 2}, { 4, 19, 22, 0}, { 5, 5, 8, 10}, { 5, 20, 21, 0}, { 6, 5, 12, 10}, { 6, 21, 4, 51},// [11][]: 夏至
{ 7, 6, 22, 20}, { 7, 22, 15, 44}, { 8, 7, 8, 9}, { 8, 22, 22, 55}, { 9, 7, 11, 11}, { 9, 22, 20, 44},// [17][]: 秋分
{10, 8, 3, 0}, {10, 23, 6, 15}, {11, 7, 6, 20}, {11, 22, 3, 56}, {12, 6, 23, 17}, {12, 21, 17, 21} // [23][]: 冬至
}; // 2024 年 24 節氣的時間點 {月, 日, 時, 分} 參考資料 https://www.hko.gov.hk/tc/gts/astronomy/Solar_Term.htm
static long climate24_table[24] = {0}; // 24 節氣時間曲線, 需製表一次
static int days_of_solar_month[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
static int climate24_date[24 * 4]; // 回傳陣列 [月, 日, 時, 分, ...]
if (climate24_table[0] == 0) {
days_of_solar_month[1] = is_leap_year(2024) ? 29 : 28;// 更新 2 月天數
for (int i = 0; i < 24 ; i ++) {
int month = table_2024[i][0]; // 月
long days = table_2024[i][1]; // 日
for (int j = 1; j < month; j ++) days += days_of_solar_month[j - 1]; // 計算總天數
climate24_table[i] = days * 1440 + table_2024[i][2] * 60 + table_2024[i][3];// 分鐘
}
}
days_of_solar_month[1] = is_leap_year(ad_year) ? 29 : 28;// 更新當年 2 月天數
int *target = climate24_date; // 填入 [月, 日, 時, 分, ...]
for (int n = 0; n < 24; n ++) {
int &solar_month = target[0];
int &solar_day = target[1];
int &solar_hour = target[2];
int &solar_min = target[3];
long dT = climate24_table[n];
if (ad_year >= 2024) { // 推算未來
for (int year = 2024; year < ad_year; year ++) {
dT += (365.2421990741f - (is_leap_year(year) ? 366 : 365)) * 1440;
}
} else { // 回推過往
for (int year = ad_year; year < 2024; year ++) {
dT -= (365.2421990741f - (is_leap_year(year) ? 366 : 365)) * 1440;
}
}
solar_day = dT / 1440;// 日
solar_hour = dT % 1440 / 60; // 小時
solar_min = dT % 1440 % 60; // 分鐘
solar_month = 1;// 日期從 1 月 1 日開始運算, 準備轉回當年日期
for (int i = 1; i <= 12; i ++) { // 一年共 12 月
int month_days = days_of_solar_month[solar_month - 1];
if (solar_day <= month_days) break;
solar_day -= month_days;
solar_month ++;
}
target += 4; // 下一節氣
}
return climate24_date;
}
int main() {
time_t now = time(0);// 現在時間
struct tm *today = localtime(&now); // 取得今天的資料, todo: GMT + 8
int ad_year = today->tm_year + 1900;// 今年: 西元年
int ad_month = today->tm_mon + 1; // 當月
int ad_day = today->tm_mday;
printf("今天 西元%d 年 %d 月 %d 日\n\n", ad_year, ad_month, ad_day);
ad_year -= 50;
int *date = find_climate24(ad_year);
for(int i = 0; i < 24; i++) {
printf("%d 年 %s %2d 月 %2d 日 %2d:%2d\n", ad_year, climate24_terms[i], date[0], date[1], date[2], date[3]);
date += 4;
}
}
沒有留言:
張貼留言