summaryrefslogtreecommitdiffstats
path: root/calendar.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'calendar.cpp')
-rw-r--r--calendar.cpp424
1 files changed, 424 insertions, 0 deletions
diff --git a/calendar.cpp b/calendar.cpp
new file mode 100644
index 0000000..d869d5d
--- /dev/null
+++ b/calendar.cpp
@@ -0,0 +1,424 @@
1// Encoding: UTF-8
2#include <iostream>
3#include <string>
4#include <vector>
5#include <fstream>
6#include <cmath>
7#include <ctime>
8using namespace std;
9
10double pi=3.14159265358979323846;
11double delta=5e-9;
12
13typedef struct tm Date;
14
15
16class Julian
17{
18 private:
19 double d[23][5]={
20 {-4000, 108371.700000, -13036.800000, 392.000000, 0.000000},
21 { -500, 17201.000000, -627.820000, 16.170000, -0.341300},
22 { -150, 12200.600000, -346.410000, 5.403000, -0.159300},
23 { 150, 9113.800000, -328.130000, -1.647000, 0.037700},
24 { 500, 5707.500000, -391.410000, 0.915000, 0.314500},
25 { 900, 2203.400000, -283.450000, 13.034000, -0.177800},
26 { 1300, 490.100000, -57.350000, 2.085000, -0.007200},
27 { 1600, 120.000000, -9.810000, -1.532000, 0.140300},
28 { 1700, 10.200000, -0.910000, 0.510000, -0.037000},
29 { 1800, 13.400000, -0.720000, 0.202000, -0.019300},
30 { 1830, 7.800000, -1.810000, 0.416000, -0.024700},
31 { 1860, 8.300000, -0.130000, -0.406000, 0.029200},
32 { 1880, -5.400000, 0.320000, -0.183000, 0.017300},
33 { 1900, -2.300000, 2.060000, 0.169000, -0.013500},
34 { 1920, 21.200000, 1.690000, -0.304000, 0.016700},
35 { 1940, 24.200000, 1.220000, -0.064000, 0.003100},
36 { 1960, 33.200000, 0.510000, 0.231000, -0.010900},
37 { 1980, 51.000000, 1.290000, -0.026000, 0.003200},
38 { 2000, 63.870000, 0.100000, 0.000000, 0.000000},
39 { 2005, 64.700000, 0.210000, 0.000000, 0.000000},
40 { 2012, 66.800000, 0.220000, 0.000000, 0.000000},
41 { 2018, 69.000000, 0.360000, 0.000000, 0.000000},
42 { 2028, 72.600000, 0.000000, 0.000000, 0.000000}
43 };
44
45 double dt_ext(int y,double jsd)
46 {
47 double dy=(double)(y-1820)/100.0;
48 return -20+jsd*dy*dy;
49 }
50
51 //计算力学时与世界时之差,传入年份
52 double delta_t(int y)
53 {
54 int y0=d[22][0];//表中最后一行的年份
55 double t0=d[22][1];//表中最后一行的delta_t
56 double jsd;
57
58 if(y>y0)
59 {
60 jsd=31;
61 if(y-y0>100)
62 {
63 return dt_ext(y,jsd);
64 }
65
66 double v=dt_ext(y,jsd);
67 double dv=dt_ext(y0,jsd)-t0;
68 return v-dv*(y0+100-y)/100;
69 }
70
71 double res;
72 for(int i=0;i<22;i++)
73 {
74 if(y<d[i+1][0])
75 {
76 break;
77 }
78 double t1=(y-d[i][0])/(d[i+1][0]-d[i][0])*10;
79 double t2=t1*t1;
80 double t3=t2*t1;
81 res=d[i][1]+d[i][2]*t1+d[i][3]*t2+d[i][4]*t3;
82 }
83 return res;
84
85
86 }
87 public:
88 // 计算儒略日
89 double getJulianDay(time_t time)
90 {
91 double t=(double)time;
92 return (double)t/86400.0+2440587.5;
93 }
94
95 // 计算儒略千年数
96 double getJulianKiloYear(time_t time)
97 {
98 double jd = getJulianDay(time);
99 return (double)(jd-2451545.0)/365250.0;
100 }
101
102 //儒略千年数转时间戳
103 time_t kiloYearToTime(double t,int year)
104 {
105 double jd=t*365250.0+2451545.0;
106 time_t time=(time_t)((jd-2440587.5)*86400.0-delta_t(year));
107 return time;
108 }
109};
110
111class parameter{
112 private:
113
114 // 计算地球日心黄经
115 double get_longitude(vector<double> l,double t)
116 {
117 double L=l[0];
118 for(int i=1;i<l.size();i++)
119 {
120 L+=l[i]*pow(t,i);
121 }
122 //返回弧度制
123 return L+pi;
124 }
125
126 // 计算地球日心黄纬
127 double get_latitude(vector<double> b,double t)
128 {
129 double B=b[0];
130 for(int i=1;i<b.size();i++)
131 {
132 B+=b[i]*pow(t,i);
133 }
134 //返回弧度制
135 //地心黄纬=-太阳黄纬
136 return -B;
137 }
138
139 double get_R(vector<double> r,double t)
140 {
141 double R=r[0];
142 for(int i=1;i<r.size();i++)
143 {
144 R+=r[i]*pow(t,i);
145 }
146 return R;
147 }
148
149 // 转换FK5误差,返回弧度制
150 double delta_FK5(double L,double B,double T)
151 {
152 //L转角度制
153 L*=180/pi;
154 //计算L',角度制
155 double L_p=L-1.397*T-0.00031*T*T;
156 //计算L',弧度制
157 L_p*=pi/180;
158 while(L_p<0)
159 L_p+=2*pi;
160 while(L_p>2*pi)
161 L_p-=2*pi;
162 //计算delta_L,单位为角秒
163 double delta_L=-0.09033+0.03916*(cos(L_p)+sin(L_p))*tan(B);
164 //转换为弧度制
165 delta_L*=pi/(180*3600);
166 return delta_L;
167 }
168
169 //获取章动有关角
170 vector<double> get_angle(double T)
171 {
172 vector<double> ang;
173 //计算平距角
174 ang.push_back(297.85036+445267.111480*T-0.0019142*T*T+T*T*T/189474);
175 //计算日地平近点角
176 ang.push_back(357.52772+35999.050340*T-0.0001603*T*T-T*T*T/300000);
177 //计算月球平近点角
178 ang.push_back(134.96298+477198.867398*T+0.0086972*T*T+T*T*T/56250);
179 //计算月球纬度参数
180 ang.push_back(93.27191+483202.017538*T-0.0036825*T*T+T*T*T/327270);
181 //计算黄道与月球平轨道交点黄经
182 ang.push_back(125.04452-1934.136261*T+0.0020708*T*T+T*T*T/450000);
183 return ang;
184 }
185
186
187 //章动修正
188 double nution(double T)
189 {
190 vector<double> ang=get_angle(T);
191 fstream fr;
192 fr.open("data/nutation.txt",ios::in);
193 string str;
194 double sita;
195 double s,s1,s2;
196 double c,c1,c2;
197 double m,n,o,p,q;
198
199 s=c=0;
200 while(getline(fr,str))
201 {
202 sscanf(str.c_str(),"%lf%lf%lf%lf%lf%lf%lf%lf%lf",&m,&n,&o,&p,&q,&s1,&s2,&c1,&c2);
203 sita=m*ang[0]+n*ang[1]+o*ang[2]+p*ang[3]+q*ang[4];
204
205 //sita为角度制,转换为弧度制
206 sita*=pi/180;
207 //计算黄经章动,单位为0.0001角秒
208 s+=(s1+s2*T)*sin(sita);
209 //计算交角章动,单位为0.0001角秒
210 //c+=(c1+c2*T)*cos(sita);
211 }
212 //关闭文件
213 fr.close();
214 // 计算得到的s和c单位0.0001秒,转换为弧度制
215 s*=0.0001;
216 s*=pi/(180*3600);
217 return s;
218 }
219
220 //光行差修正,返回弧度制
221 double aberration(double R)
222 {
223 //return -20.4898/R/3600.0*pi/180.0;
224 //公式,单位0.0001角秒
225 double delta=-20.4898/R;
226 //转换为弧度制
227 delta*=pi/(180*3600);
228 return delta;
229 }
230
231 // 获取地日运行参数,L为地球日心黄经,B为地球日心黄纬,R为地日距离
232 vector<vector<double>> get_parameters(double t)
233 {
234 fstream fr;
235 fr.open("data/earth.txt",ios::in);
236 string s;
237 double l=0;
238 double a,b,c,num_tmp=0;
239 vector<vector<double>> parameters;
240 vector<double> tmp;
241 while(getline(fr,s))
242 {
243 //当分割符为/时,表明一组参数结束,将参数存入parameters中,并清空tmp
244 if(s[0]=='/')
245 {
246 parameters.push_back(tmp);
247 tmp.resize(0);
248 num_tmp=0;
249 }
250 //当分割符为=时,表明一组参数中的一类结束,将参数存入tmp中,并清空num_tmp
251 else if(s[0]=='=')
252 {
253 tmp.push_back(num_tmp);
254 num_tmp=0;
255 }
256 else
257 {
258 sscanf(s.c_str(),"%lf%lf%lf",&a,&b,&c);
259 num_tmp+=a*cos(b+c*t);
260 }
261 }
262 //关闭文件
263 fr.close();
264 /* 最终传参情况:
265 * parameters[0]为L系列,用来计算地球日心黄经
266 * parameters[1]为B系列,用来计算地球日心黄纬
267 * parameters[2]为R系列,用来计算地日距离
268 */
269 return parameters;
270 }
271
272 public:
273
274 double longitude(double t)
275 {
276 //从文件中计算地日运行参数
277 vector<vector<double>> p=get_parameters(t);
278
279 //取出各类参数
280 vector<double> l=p[0],b=p[1],r=p[2];
281
282 //计算地球日心黄经纬,返回弧度制/天文单位
283 double L=get_longitude(l,t);
284 double B=get_latitude(b,t);
285 double R=get_R(r,t);
286
287
288 //以下修正需要的都是儒略世纪数而非千年数
289 //转FK5误差,返回弧度制
290 L+=delta_FK5(L,B,10*t);
291 //章动修正,返回弧度制
292 L+=nution(10*t);
293 //光行差修正,返回弧度制
294 L+=aberration(R);
295
296
297 //L转角度制
298 L*=180/pi;
299 while(L<0)
300 L+=360;
301 while(L>=360)
302 L-=360;
303 if(360-L<=5)
304 {
305 L-=360;
306 }
307 return L;
308 }
309};
310
311void Plus(Date &date)
312{
313 if(date.tm_mday<10)
314 {
315 date.tm_mday=20;
316 }
317 else
318 {
319 date.tm_mday=6;
320 date.tm_mon++;
321 }
322 return;
323}
324
325double fuck(double a,double b)
326{
327 while(b<0)
328 b+=360;
329 while(b>=360)
330 b-=360;
331 if(b==0)
332 {
333 return min(fabs(b),fabs(360-b));
334 }
335 else
336 {
337 return fabs(a-b);
338 }
339}
340
341int main()
342{
343 Date* date=new Date;
344 cout<<"Please input the year: "<<endl;
345
346 //时间确认
347 cin>>date->tm_year;
348 date->tm_year-=1900;//年份减去1900
349 //当年元旦零时
350 date->tm_mon=0;
351 date->tm_mday=1;
352 date->tm_hour=0;
353 date->tm_min=0;
354 date->tm_sec=0;
355
356 //输出年份
357 cout<<"Year: "<<date->tm_year+1900<<endl;
358
359 //计算当年二十四节气准确时刻
360 parameter p;
361 Julian julian;
362 time_t time;
363 //double dL;//dL为L对t导数
364 double t,t_end,t_middle;
365 double target;
366 char JieQi[24][10]={"小寒","大寒","立春","雨水","惊蛰","春分","清明","谷雨","立夏","小满","芒种","夏至","小暑","大暑","立秋","处暑","白露","秋分","寒露","霜降","立冬","小雪","大雪","冬至"};
367 //date->tm_mday=6;
368 for(int i=0;date->tm_mon<12;Plus(*date),i++)
369 {
370 //转换为时间戳
371 time=mktime(date);
372 //暂时放弃牛顿迭代法
373 //t=julian.getJulianKiloYear(time);
374 //while(fuck(p.longitude(t),(double)i*15-75)>=1e-8)
375 //{
376 // dL=(p.longitude(t+delta)-p.longitude(t-delta))/(2*delta);
377 // t=t-p.longitude(t)/dL;
378 //}
379
380
381 //计算儒略千年数
382 t=julian.getJulianKiloYear(time);
383 t_end=julian.getJulianKiloYear(time+86400);
384 target=i*15-75;
385 if(target<0)
386 {
387 target+=360;
388 }
389
390 //二分法
391 while(p.longitude(t)>target)
392 {
393 time-=86400;
394 t_end=t;
395 t=julian.getJulianKiloYear(time);
396 }
397 while(p.longitude(t_end)<=target)
398 {
399 time+=86400;
400 t=t_end;
401 t_end=julian.getJulianKiloYear(time);
402 }
403 while(t_end-t>=1e-10)
404 {
405 t_middle=(t+t_end)/2;
406 if(p.longitude(t_middle)>target)
407 {
408 t_end=t_middle;
409 }
410 else
411 {
412 t=t_middle;
413 }
414 }
415 //double t转为时间戳
416 time=julian.kiloYearToTime(t,date->tm_year+1900);
417
418 //date换新
419 date=localtime(&time);
420 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]);
421 }
422 printf("\n\n");
423 return 0;
424}