// Encoding: UTF-8 #include "calendar.h" #include #include /*以下为"calendar.h规定之量*/ double pi = 3.14159265358979323846; double day = 86400; double delta = 1e-11; char jieqi[25][10] = {"冬至", "小寒", "大寒", "立春", "雨水", "惊蛰", "春分", "清明", "谷雨", "立夏", "小满", "芒种", "夏至", "小暑", "大暑", "立秋", "处暑", "白露", "秋分", "寒露", "霜降", "立冬", "小雪", "大雪", "冬至"}; /*计算需要用的类的实例化*/ Julian julian; parameter p; List list; Date *input(char *argv) { Date *date = new Date; // 输入年份,自当年元旦起算 date->tm_year = atoi(argv) - 1900; date->tm_mon = 0; date->tm_mday = 1; date->tm_hour = 0; date->tm_min = 0; date->tm_sec = 0; return date; } /*计算当年二十四节气时刻,自去年冬至到本年冬至*/ void JieQi(Date *date) { //计算起始时间为去年12月19日0时,开始寻找去年冬至 time_t time = mktime(date); time -= 13 * day; double t, t_end, t_middle; //采用二分法计算,t与t_end为间隔24h的两个时刻 double target_angle; //目标角度 Date *date_tmp; //计算每个节气对应太阳地心黄经 for (int i = 0; i < 25; i++, time += 12 * day) { target_angle = 15 * i + 270; if (target_angle >= 360) target_angle -= 360; t = julian.getJulianKiloYear(time); t_end = julian.getJulianKiloYear(time + day); if (target_angle == 0) { while (p.sun_longitude(t_end) > 300) { time += day; t = t_end; t_end = julian.getJulianKiloYear(time + day); } if (!(p.sun_longitude(t) > 300 && p.sun_longitude(t_end) < 2)) { fprintf(stderr, "Error: Can't find the target angle\n"); exit(1); } while (t_end - t > delta) { t_middle = (t + t_end) / 2; if (p.sun_longitude(t_middle) < 2) { t_end = t_middle; } else { t = t_middle; } } } else { while (p.sun_longitude(t_end) < target_angle) { time += day; t = t_end; t_end = julian.getJulianKiloYear(time + day); } while (t_end - t > delta) { t_middle = (t + t_end) / 2; if (p.sun_longitude(t_middle) < target_angle) { t = t_middle; } else { t_end = t_middle; } } } //链表记录节气信息 time = julian.kiloYearToTime(t, i == 0 ? date->tm_year + 1899 : date->tm_year + 1900); date_tmp = localtime(&time); list.append(date_tmp, false, true, i % 2 == 0, i, t); } } // 用以判断朔日的函数,返回true则太阳地心黄经大于月球地心黄经,即朔日在此后 bool date_forward(double sun_longitude, double moon_longitude) { /* 判断逻辑 * 当moon_longitudesun_longitude时, * 如果moon_longitude-sun_longitude<20,即度数相差不大,可知朔日在此前 * 否则,大于20时候,度数相差过大,理论上只可能为moon_longitude已接近360,sun_longitude略微大于0 * 此时实际上是月亮应当追赶太阳,因而朔日在此后 */ return moon_longitude < sun_longitude ? true : (moon_longitude - sun_longitude >= 20); } void ShuoRi(int year) { double t, t_end, end, t_middle; //采用二分法计算,t与t_end为间隔24h的两个时刻 time_t time; Date *date_tmp = new Date; //根据zhongqi_vec的最后一项(今年冬至)计算冬至下一日的0时刻 date_tmp->tm_year = list.zhongqi_vec[12]->year - 1900; date_tmp->tm_mon = list.zhongqi_vec[12]->mon - 1; date_tmp->tm_mday = list.zhongqi_vec[12]->day + 1; date_tmp->tm_hour = 0; date_tmp->tm_min = 0; date_tmp->tm_sec = 0; date_tmp->tm_isdst = -1; time = mktime(date_tmp); end = julian.getJulianKiloYear(time); // 计算去年冬至时刻的time date_tmp->tm_year = list.zhongqi_vec[0]->year - 1900; date_tmp->tm_mon = list.zhongqi_vec[0]->mon - 1; date_tmp->tm_mday = list.zhongqi_vec[0]->day; date_tmp->tm_hour = list.zhongqi_vec[0]->hour; date_tmp->tm_min = list.zhongqi_vec[0]->min; date_tmp->tm_sec = list.zhongqi_vec[0]->sec; date_tmp->tm_isdst = -1; time = mktime(date_tmp); delete date_tmp; // 定朔日 for (t = julian.getJulianKiloYear(time); t <= end; time += 25 * day) { // 每月长度为28-30天,因而每次循环前进25天 t = julian.getJulianKiloYear(time); t_end = julian.getJulianKiloYear(time + day); // 太阳在月亮之前,月亮追赶,故朔日在后,t和t_end前进24h while (date_forward(p.sun_longitude(t_end), p.moon_longitude(t_end))) { time += day; t = t_end; t_end = julian.getJulianKiloYear(time + day); } // 太阳在月亮之后,月亮落后,故朔日在前,t和t_end后退24h(用以保险) while (!date_forward(p.sun_longitude(t), p.moon_longitude(t))) { time -= day; t_end = t; t = julian.getJulianKiloYear(time); } while (t_end - t >= delta) { t_middle = (t + t_end) / 2; if (date_forward(p.sun_longitude(t_middle), p.moon_longitude(t_middle))) { t = t_middle; } else { t_end = t_middle; } } // 输出朔日信息 time = julian.kiloYearToTime(t, year - 1); date_tmp = localtime(&time); list.append(date_tmp, true, false, false, -1, t); } } int main(int argc, char *argv[]) { if (argc != 2) { printf("Usage: %s year\\n\n", argv[0]); return 0; } Date *date = input(argv[1]); int year = date->tm_year + 1900; double begin, end; JieQi(date); ShuoRi(year); list.lunar_sort(); // 奉旨置闰 list.Run(); // 输出 list.output(); // 释放内存,使用List的析构函数 delete date; return 0; }