summaryrefslogtreecommitdiffstats
path: root/src/calendar.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/calendar.cpp')
-rw-r--r--src/calendar.cpp291
1 files changed, 209 insertions, 82 deletions
diff --git a/src/calendar.cpp b/src/calendar.cpp
index c81316a..492cdbc 100644
--- a/src/calendar.cpp
+++ b/src/calendar.cpp
@@ -1,120 +1,247 @@
1// Encoding: UTF-8 1// Encoding: UTF-8
2#include "calendar.h" 2#include "calendar.h"
3#include <cstdio>
4#include <ctime>
3 5
6/*以下为"calendar.h规定之量*/
4double pi=3.14159265358979323846; 7double pi=3.14159265358979323846;
5double delta=5e-9; 8double day=86400;
9double delta=1e-11;
10char jieqi[25][10]={"冬至","小寒","大寒","立春","雨水","惊蛰","春分","清明","谷雨","立夏","小满","芒种","夏至","小暑","大暑","立秋","处暑","白露","秋分","寒露","霜降","立冬","小雪","大雪","冬至"};
6 11
7void Plus(Date &date) 12/*计算需要用的类的实例化*/
8{ 13Julian julian;
9 if(date.tm_mday<10) 14parameter p;
10 { 15List list;
11 date.tm_mday=20;
12 }
13 else
14 {
15 date.tm_mday=6;
16 date.tm_mon++;
17 }
18 return;
19}
20 16
21double fuck(double a,double b)
22{
23 while(b<0)
24 b+=360;
25 while(b>=360)
26 b-=360;
27 if(b==0)
28 {
29 return min(fabs(b),fabs(360-b));
30 }
31 else
32 {
33 return fabs(a-b);
34 }
35}
36 17
37int main() 18Date* input(char* argv)
38{ 19{
39 Date* date=new Date; 20 Date* date=new Date;
40 cout<<"Please input the year: "<<endl;
41 21
42 //时间确认 22 // 输入年份,自当年元旦起算
43 cin>>date->tm_year; 23 date->tm_year=atoi(argv)-1900;
44 date->tm_year-=1900;//年份减去1900
45 //当年元旦零时
46 date->tm_mon=0; 24 date->tm_mon=0;
47 date->tm_mday=1; 25 date->tm_mday=1;
48 date->tm_hour=0; 26 date->tm_hour=0;
49 date->tm_min=0; 27 date->tm_min=0;
50 date->tm_sec=0; 28 date->tm_sec=0;
51 29
52 //输出年份 30 return date;
53 cout<<"Year: "<<date->tm_year+1900<<endl; 31}
54 32
55 //计算当年二十四节气准确时刻 33/*计算当年二十四节气时刻,自去年冬至到本年冬至*/
56 parameter p; 34void JieQi(Date* date)
57 Julian julian; 35{
58 time_t time; 36 //计算起始时间为去年12月19日0时,开始寻找去年冬至
59 //double dL;//dL为L对t导数 37 time_t time=mktime(date);
60 double t,t_end,t_middle; 38 time-=13*day;
61 double target; 39
62 char JieQi[24][10]={"小寒","大寒","立春","雨水","惊蛰","春分","清明","谷雨","立夏","小满","芒种","夏至","小暑","大暑","立秋","处暑","白露","秋分","寒露","霜降","立冬","小雪","大雪","冬至"}; 40 double t,t_end,t_middle;//采用二分法计算,t与t_end为间隔24h的两个时刻
63 //date->tm_mday=6; 41 double target_angle;//目标角度
64 for(int i=0;date->tm_mon<12;Plus(*date),i++) 42 Date* date_tmp;
43
44 //计算每个节气对应太阳地心黄经
45 for(int i=0;i<25;i++,time+=12*day)
65 { 46 {
66 //转换为时间戳 47 target_angle=15*i+270;
67 time=mktime(date); 48 if(target_angle>=360)
68 //暂时放弃牛顿迭代法 49 target_angle-=360;
69 //t=julian.getJulianKiloYear(time); 50
70 //while(fuck(p.longitude(t),(double)i*15-75)>=1e-8)
71 //{
72 // dL=(p.longitude(t+delta)-p.longitude(t-delta))/(2*delta);
73 // t=t-p.longitude(t)/dL;
74 //}
75
76
77 //计算儒略千年数
78 t=julian.getJulianKiloYear(time); 51 t=julian.getJulianKiloYear(time);
79 t_end=julian.getJulianKiloYear(time+86400); 52 t_end=julian.getJulianKiloYear(time+day);
80 target=i*15-75; 53
81 if(target<0) 54 //定春分
55 if(target_angle==0)
82 { 56 {
83 target+=360; 57 /* 春分太阳地心视黄经为0,一般二分法不便于计算
84 } 58 * 因而限定范围为[355,360)∪(0,5],即春分前后各5度
59 * 当t_end时刻太阳地心视黄经在[355,360)时,证明春分在后边,t和t_end前进24h
60 */
61 while(p.sun_longitude(t_end)<360&&p.sun_longitude(t_end)>355)
62 {
63 time+=day;
64 t=t_end;
65 t_end=julian.getJulianKiloYear(time+day);
66 }
67 /* 循环体time每次在已经计算出的上一节气基础上前进12日,理论上春分在t_end之后
68 * 当跳出上一while循环时理论上春分时刻正在t与t_end之间
69 * 为保险起见,添加这个循环
70 * 当t时刻太阳地心视黄经在[0,5]时,证明春分在前边,t和t_end后退24h
71 */
72 while(p.sun_longitude(t)<5)
73 {
74 time-=day;
75 t_end=t;
76 t=julian.getJulianKiloYear(time);
77 }
85 78
86 //二分法 79 //二分法计算春分
87 while(p.sun_longitude(t)>target) 80 while(t_end-t>delta)
81 {
82 t_middle=(t+t_end)/2;
83 if(p.sun_longitude(t_middle)<360&&p.sun_longitude(t_middle)>355)
84 {
85 t=t_middle;
86 }
87 else
88 {
89 t_end=t_middle;
90 }
91 }
92 }
93 //其他情况
94 else
88 { 95 {
89 time-=86400; 96 //当t_end时刻太阳地心视黄经小于目标角度,节气在后,t和t_end前进24h
90 t_end=t; 97 while(p.sun_longitude(t_end)<target_angle)
91 t=julian.getJulianKiloYear(time); 98 {
99 time+=day;
100 t=t_end;
101 t_end=julian.getJulianKiloYear(time+day);
102 }
103
104 //当t时刻太阳地心视黄经大于目标角度,节气在前,t和t_end后退24h
105 //该循环也是一个保险循环
106 while(p.sun_longitude(t)>target_angle)
107 {
108 time-=day;
109 t_end=t;
110 t=julian.getJulianKiloYear(time);
111 }
112
113 while(t_end-t>delta)
114 {
115 t_middle=(t+t_end)/2;
116 if(p.sun_longitude(t_middle)<target_angle)
117 {
118 t=t_middle;
119 }
120 else
121 {
122 t_end=t_middle;
123 }
124 }
92 } 125 }
93 while(p.sun_longitude(t_end)<=target) 126
127 //链表记录节气信息
128 time=julian.kiloYearToTime(t,i==0?date->tm_year+1899:date->tm_year+1900);
129 date_tmp=localtime(&time);
130 list.append(date_tmp,false,true,i%2==0,i,t);
131 }
132}
133
134// 用以判断朔日的函数,返回true则太阳地心黄经大于月球地心黄经,即朔日在此后
135bool date_forward(double sun_longitude,double moon_longitude)
136{
137 /* 判断逻辑
138 * 当moon_longitude<sun_longitude时,由于时刻已经在朔日附近
139 * 因而可以判断朔日在该时刻之后
140 * 反之,当moon_longitude>sun_longitude时,
141 * 如果moon_longitude-sun_longitude<20,即度数相差不大,可知朔日在此前
142 * 否则,大于20时候,度数相差过大,理论上只可能为moon_longitude已接近360,sun_longitude略微大于0
143 * 此时实际上是月亮应当追赶太阳,因而朔日在此后
144 */
145 return moon_longitude < sun_longitude ? true : (moon_longitude-sun_longitude >= 20);
146}
147
148void ShuoRi(int year)
149{
150 double t,t_end,end,t_middle;//采用二分法计算,t与t_end为间隔24h的两个时刻
151 time_t time;
152 Date* date_tmp=new Date;
153
154 //根据zhongqi_vec的最后一项(今年冬至)计算冬至下一日的0时刻
155 date_tmp->tm_year=list.zhongqi_vec[12]->year-1900;
156 date_tmp->tm_mon=list.zhongqi_vec[12]->mon-1;
157 date_tmp->tm_mday=list.zhongqi_vec[12]->day+1;
158 date_tmp->tm_hour=0;
159 date_tmp->tm_min=0;
160 date_tmp->tm_sec=0;
161 date_tmp->tm_isdst=-1;
162 time=mktime(date_tmp);
163 end=julian.getJulianKiloYear(time);
164
165 // 计算去年冬至时刻的time
166 date_tmp->tm_year=list.zhongqi_vec[0]->year-1900;
167 date_tmp->tm_mon=list.zhongqi_vec[0]->mon-1;
168 date_tmp->tm_mday=list.zhongqi_vec[0]->day;
169 date_tmp->tm_hour=list.zhongqi_vec[0]->hour;
170 date_tmp->tm_min=list.zhongqi_vec[0]->min;
171 date_tmp->tm_sec=list.zhongqi_vec[0]->sec;
172 date_tmp->tm_isdst=-1;
173 time=mktime(date_tmp);
174
175 delete date_tmp;
176
177 // 定朔日
178 for(t=julian.getJulianKiloYear(time);t<=end;time+=25*day)
179 {
180 // 每月长度为28-30天,因而每次循环前进25天
181 t=julian.getJulianKiloYear(time);
182 t_end=julian.getJulianKiloYear(time+day);
183
184 // 太阳在月亮之前,月亮追赶,故朔日在后,t和t_end前进24h
185 while(date_forward(p.sun_longitude(t_end),p.moon_longitude(t_end)))
94 { 186 {
95 time+=86400; 187 time+=day;
96 t=t_end; 188 t=t_end;
97 t_end=julian.getJulianKiloYear(time); 189 t_end=julian.getJulianKiloYear(time+day);
98 } 190 }
99 while(t_end-t>=1e-10) 191 // 太阳在月亮之后,月亮落后,故朔日在前,t和t_end后退24h(用以保险)
192 while(!date_forward(p.sun_longitude(t),p.moon_longitude(t)))
193 {
194 time-=day;
195 t_end=t;
196 t=julian.getJulianKiloYear(time);
197 }
198
199 while(t_end-t>=delta)
100 { 200 {
101 t_middle=(t+t_end)/2; 201 t_middle=(t+t_end)/2;
102 if(p.sun_longitude(t_middle)>target) 202 if(date_forward(p.sun_longitude(t_middle),p.moon_longitude(t_middle)))
103 { 203 {
104 t_end=t_middle; 204 t=t_middle;
105 } 205 }
106 else 206 else
107 { 207 {
108 t=t_middle; 208 t_end=t_middle;
109 } 209 }
110 } 210 }
111 //double t转为时间戳 211 // 输出朔日信息
112 time=julian.kiloYearToTime(t,date->tm_year+1900); 212 time=julian.kiloYearToTime(t,year-1);
213 date_tmp=localtime(&time);
214 list.append(date_tmp,true,false,false,-1,t);
215 }
216}
217
218int main(int argc,char* argv[])
219{
113 220
114 //date换新 221 if(argc!=2)
115 date=localtime(&time); 222 {
116 printf("%d-%02d-%02d %02d:%02d:%02d %s\n",date->tm_year+1900,date->tm_mon+1,date->tm_mday,date->tm_hour,date->tm_min,date->tm_sec,JieQi[i]); 223 printf("Usage: %s year\\n\n",argv[0]);
224 return 0;
117 } 225 }
118 printf("\n\n"); 226 Date* date=input(argv[1]);
227 int year=date->tm_year+1900;
228 double begin,end;
229
230 JieQi(date);
231 ShuoRi(year);
232
233 list.lunar_sort();
234
235 // 奉旨置闰
236 list.Run();
237
238 // 输出
239 list.output();
240
241 // 释放内存,使用List的析构函数
242
243
244 delete date;
245
119 return 0; 246 return 0;
120} 247}