1 /*
2 * This library is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU Lesser General Public
4 * License as published by the Free Software Foundation; either
5 * version 2 of the License, or (at your option) any later version.
6 *
7 * This library is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10 * Lesser General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15 *
16 * Copyright (C) 2000 - 2005 Liam Girdwood
17 */
18
19 #include <time.h>
20 #include <string.h>
21 #include <stdlib.h>
22 #include <math.h>
23 #include <libnova/julian_day.h>
24 #include <libnova/utility.h>
25
26 /* Standard Win32 apps do not have POSIX support. */
27 #ifndef __WIN32__
28 #include <sys/time.h>
29 #endif
30
31 /*! \fn double ln_get_julian_day (struct ln_date * date)
32 * \param date Date required.
33 * \return Julian day
34 *
35 * Calculate the julian day from a calendar day.
36 * Valid for positive and negative years but not for negative JD.
37 */
38 /* Formula 7.1 on pg 61
39 */
ln_get_julian_day(struct ln_date * date)40 double ln_get_julian_day (struct ln_date * date)
41 {
42 double JD;
43 double days;
44 int a,b;
45 struct ln_date local_date;
46
47 /* create local copy */
48 memcpy (&local_date, date, sizeof (struct ln_date));
49
50 /* check for month = January or February */
51 if (local_date.months < 3 ) {
52 local_date.years--;
53 local_date.months += 12;
54 }
55
56 a = local_date.years / 100;
57
58 /* check for Julian or Gregorian calendar (starts Oct 4th 1582) */
59 if (local_date.years > 1582 ||
60 (local_date.years == 1582 &&
61 (local_date.months > 10 ||
62 (local_date.months == 10 && local_date.days >= 4)))) {
63 /* Gregorian calendar */
64 b = 2 - a + (a / 4);
65 } else {
66 /* Julian calendar */
67 b = 0;
68 }
69
70 /* add a fraction of hours, minutes and secs to days*/
71 days = local_date.days + (double)(local_date.hours / 24.0) + (double)(local_date.minutes / 1440.0) + (double)(local_date.seconds / 86400.0);
72
73 /* now get the JD */
74 JD = (int)(365.25 * (local_date.years + 4716)) +
75 (int)(30.6001 * (local_date.months + 1)) + days + b - 1524.5;
76
77 return JD;
78 }
79
80
81 /*! \fn unsigned int ln_get_day_of_week (struct ln_date *date)
82 * \param date Date required
83 * \return Day of the week
84 *
85 * Calculate the day of the week.
86 * Returns 0 = Sunday .. 6 = Saturday
87 */
ln_get_day_of_week(struct ln_date * date)88 unsigned int ln_get_day_of_week (struct ln_date *date)
89 {
90 unsigned int day;
91 double JD;
92
93 /* get julian day */
94 JD = ln_get_julian_day (date);
95 JD += 1.5;
96 day = (int)JD % 7;
97
98 return day;
99 }
100
101 /*! \fn void ln_get_date (double JD, struct ln_date * date)
102 * \param JD Julian day
103 * \param date Pointer to new calendar date.
104 *
105 * Calculate the date from the Julian day
106 */
ln_get_date(double JD,struct ln_date * date)107 void ln_get_date (double JD, struct ln_date * date)
108 {
109 int A,a,B,C,D,E;
110 double F,Z;
111
112 JD += 0.5;
113 Z = (int) JD;
114 F = JD - Z;
115
116 if (Z < 2299161)
117 A = (int) Z;
118 else {
119 a = (int) ((Z - 1867216.25) / 36524.25);
120 A = (int) (Z + 1 + a - (int)(a / 4));
121 }
122
123 B = A + 1524;
124 C = (int) ((B - 122.1) / 365.25);
125 D = (int) (365.25 * C);
126 E = (int) ((B - D) / 30.6001);
127
128 /* get the hms */
129 date->hours = (int) (F * 24);
130 F -= (double)date->hours / 24;
131 date->minutes = (int) (F * 1440);
132 F -= (double)date->minutes / 1440;
133 date->seconds = F * 86400;
134
135 /* get the day */
136 date->days = B - D - (int)(30.6001 * E);
137
138 /* get the month */
139 if (E < 14)
140 date->months = E - 1;
141 else
142 date->months = E - 13;
143
144 /* get the year */
145 if (date->months > 2)
146 date->years = C - 4716;
147 else
148 date->years = C - 4715;
149 }
150
151 /*! \fn void ln_get_date_from_timet (time_t * t, struct ln_date * date)
152 * \param t system time
153 * \param date Pointer to new calendar date.
154 *
155 * Set date from system time
156 */
ln_get_date_from_timet(time_t * t,struct ln_date * date)157 void ln_get_date_from_timet (time_t * t, struct ln_date * date)
158 {
159 struct tm gmt;
160
161 /* convert to UTC time representation */
162 gmtime_r (t, &gmt);
163
164 ln_get_date_from_tm (&gmt, date);
165 }
166
167 /*! \fn void ln_get_date_from_tm (struct tm * t, struct ln_date * date)
168 * \param tm system tm structure
169 * \param date Pointer to new calendar date.
170 *
171 * Set date from system tm structure
172 */
ln_get_date_from_tm(struct tm * t,struct ln_date * date)173 void ln_get_date_from_tm (struct tm * t, struct ln_date * date)
174 {
175 /* fill in date struct */
176 date->seconds = t->tm_sec;
177 date->minutes = t->tm_min;
178 date->hours = t->tm_hour;
179 date->days = t->tm_mday;
180 date->months = t->tm_mon + 1;
181 date->years = t->tm_year + 1900;
182 }
183
184 /*! \fn void ln_get_date_from_sys (struct ln_date * date)
185 * \param date Pointer to store date.
186 *
187 * Calculate local date from system date.
188 */
ln_get_date_from_sys(struct ln_date * date)189 void ln_get_date_from_sys (struct ln_date * date)
190 {
191 struct tm * gmt;
192 struct timeval tv;
193 struct timezone tz;
194
195 /* get current time with microseconds precission*/
196 gettimeofday (&tv, &tz);
197
198 /* convert to UTC time representation */
199 gmt = gmtime(&tv.tv_sec);
200
201 /* fill in date struct */
202 date->seconds = gmt->tm_sec + ((double)tv.tv_usec / 1000000);
203 date->minutes = gmt->tm_min;
204 date->hours = gmt->tm_hour;
205 date->days = gmt->tm_mday;
206 date->months = gmt->tm_mon + 1;
207 date->years = gmt->tm_year + 1900;
208 }
209
210
211 /*! \fn double ln_get_julian_from_timet (time_t * in_time)
212 * \param time The time_t.
213 * \return Julian day.
214 *
215 * Calculate Julian day from time_t.
216 */
ln_get_julian_from_timet(time_t * in_time)217 double ln_get_julian_from_timet (time_t * in_time)
218 {
219 // 1.1.1970 = JD 2440587.5
220 return (double)(2440587.5 + (double)(*in_time / (double) 86400.0));
221 }
222
223 #ifndef HAVE_ROUND
224
225 /* Simple round to nearest */
round(double x)226 double round (double x)
227 {
228 return floor(x + 0.5);
229 }
230
231 #endif /* ! HAVE_ROUND */
232
233 /*! \fn void ln_get_timet_from_julian (double JD, time_t * in_time)
234 * \param JD Julian day
235 * \param in_time Pointer to store time_t
236 *
237 * Calculate time_t from julian day
238 */
ln_get_timet_from_julian(double JD,time_t * in_time)239 void ln_get_timet_from_julian (double JD, time_t * in_time)
240 {
241 *in_time = (time_t)round((JD - (double) 2440587.5) * (double) 86400.0);
242 }
243
244 /*! \fn double ln_get_julian_from_sys()
245 * \return Julian day (UT)
246 *
247 * Calculate the julian day (UT) from the local system time
248 */
ln_get_julian_from_sys()249 double ln_get_julian_from_sys()
250 {
251 double JD;
252 struct ln_date date;
253
254 /* get sys date */
255 ln_get_date_from_sys (&date);
256 JD = ln_get_julian_day (&date);
257
258 return JD;
259 }
260
261 /*! \fn double ln_get_julian_local_date(struct ln_zonedate* zonedate)
262 * \param zonedate Local date
263 * \return Julian day (UT)
264 *
265 * Calculate Julian day (UT) from zone date
266 */
ln_get_julian_local_date(struct ln_zonedate * zonedate)267 double ln_get_julian_local_date(struct ln_zonedate* zonedate)
268 {
269 struct ln_date date;
270
271 ln_zonedate_to_date (zonedate, &date);
272
273 return ln_get_julian_day (&date);
274 }
275
276 /*! \fn void ln_get_local_date (double JD, struct ln_zonedate * zonedate)
277 * \param JD Julian day
278 * \param zonedate Pointer to new calendar date.
279 *
280 * Calculate the zone date from the Julian day (UT). Gets zone info from
281 * system using either _timezone or tm_gmtoff fields.
282 */
ln_get_local_date(double JD,struct ln_zonedate * zonedate)283 void ln_get_local_date (double JD, struct ln_zonedate * zonedate)
284 {
285 struct ln_date date;
286 time_t curtime;
287 struct tm *loctime;
288 long gmtoff;
289
290 ln_get_date (JD, &date);
291
292 /* add day light savings time and hour angle */
293 #ifdef __WIN32__
294 _tzset();
295 gmtoff = _timezone;
296 if (_daylight)
297 gmtoff += 3600;
298 #else
299 curtime = time (NULL);
300 loctime = localtime(&curtime);
301 gmtoff = loctime->tm_gmtoff;
302 // otherwise there is no reasonable way how to get that:(
303 // tm_gmtoff already included DST
304 #endif
305 ln_date_to_zonedate (&date, zonedate, gmtoff);
306 }
307
308 /*! \fn int ln_get_date_from_mpc (struct ln_date* date, char* mpc_date)
309 * \param date Pointer to new calendar date.
310 * \param mpc_date Pointer to string MPC date
311 * \return 0 for valid date
312 *
313 * Calculate the local date from the a MPC packed date.
314 * See http://cfa-www.harvard.edu/iau/info/PackedDates.html for info.
315 */
ln_get_date_from_mpc(struct ln_date * date,char * mpc_date)316 int ln_get_date_from_mpc (struct ln_date* date, char* mpc_date)
317 {
318 char year[3];
319 char month[2];
320 char day[2];
321
322 /* is mpc_date correct length */
323 if (strlen(mpc_date) !=5)
324 return -1;
325
326 /* get the century */
327 switch (*mpc_date) {
328 case 'I':
329 date->years = 1800;
330 break;
331 case 'J':
332 date->years = 1900;
333 break;
334 case 'K':
335 date->years = 2000;
336 break;
337 default:
338 return -1;
339 }
340
341 /* get the year */
342 year[0] = *(mpc_date + 1);
343 year[1] = *(mpc_date + 2);
344 year[2] = 0;
345 date->years += strtol (year,0,10);
346
347 /* month */
348 month[0] = *(mpc_date + 3);
349 month[1] = 0;
350 date->months = strtol (month, 0, 16);
351
352 /* day */
353 day[0] = *(mpc_date + 4);
354 day[1] = 0;
355 date->days = strtol (day, 0, 31);
356
357 /* reset hours,min,secs to 0 */
358 date->hours = 0;
359 date->minutes = 0;
360 date->seconds = 0;
361 return 0;
362 }
363
364 /*! \fn double ln_get_julian_from_mpc (char* mpc_date)
365 * \param mpc_date Pointer to string MPC date
366 * \return Julian day.
367 *
368 * Calculate the julian day from the a MPC packed date.
369 * See http://cfa-www.harvard.edu/iau/info/PackedDates.html for info.
370 */
ln_get_julian_from_mpc(char * mpc_date)371 double ln_get_julian_from_mpc (char* mpc_date)
372 {
373 struct ln_date date;
374 double JD;
375
376 ln_get_date_from_mpc(&date, mpc_date);
377 JD = ln_get_julian_day(&date);
378
379 return JD;
380 }
381
382 /*! \fn void ln_date_to_zonedate (struct ln_date * date, struct ln_zonedate * zonedate, long gmtoff)
383 * \param zonedate Ptr to zonedate
384 * \param gmtoff Offset in seconds from UT
385 * \param date Ptr to date
386 *
387 * Converts a ln_date (UT) to a ln_zonedate (local time).
388 */
ln_date_to_zonedate(struct ln_date * date,struct ln_zonedate * zonedate,long gmtoff)389 void ln_date_to_zonedate (struct ln_date * date, struct ln_zonedate * zonedate, long gmtoff)
390 {
391 double jd;
392 struct ln_date dat;
393
394 jd = ln_get_julian_day (date);
395 jd += gmtoff / 86400.0;
396 ln_get_date (jd, &dat);
397
398 zonedate->years = dat.years;
399 zonedate->months = dat.months;
400 zonedate->days = dat.days;
401 zonedate->hours = dat.hours;
402 zonedate->minutes = dat.minutes;
403 zonedate->seconds = dat.seconds;
404
405 zonedate->gmtoff = gmtoff;
406 }
407
408 /*! \fn void ln_zonedate_to_date (struct ln_zonedate * zonedate, struct ln_date * date)
409 * \param zonedate Ptr to zonedate
410 * \param date Ptr to date
411 *
412 * Converts a ln_zonedate (local time) to a ln_date (UT).
413 */
ln_zonedate_to_date(struct ln_zonedate * zonedate,struct ln_date * date)414 void ln_zonedate_to_date (struct ln_zonedate * zonedate, struct ln_date * date)
415 {
416 double jd;
417 struct ln_date dat;
418
419 dat.years = zonedate->years;
420 dat.months = zonedate->months;
421 dat.days = zonedate->days;
422 dat.hours = zonedate->hours;
423 dat.minutes = zonedate->minutes;
424 dat.seconds = zonedate->seconds;
425
426 jd = ln_get_julian_day (&dat);
427 jd -= zonedate->gmtoff / 86400.0;
428 ln_get_date (jd, date);
429 }
430