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