| 1 |
kusanagi |
1.1 |
//
|
| 2 |
|
|
// cJulian.cpp
|
| 3 |
|
|
//
|
| 4 |
|
|
// This class encapsulates Julian dates with the epoch of 12:00 noon (12:00 UT)
|
| 5 |
|
|
// on January 1, 4713 B.C. Some epoch dates:
|
| 6 |
|
|
// 01/01/1990 00:00 UTC - 2447892.5
|
| 7 |
|
|
// 01/01/1990 12:00 UTC - 2447893.0
|
| 8 |
|
|
// 01/01/2000 00:00 UTC - 2451544.5
|
| 9 |
|
|
// 01/01/2001 00:00 UTC - 2451910.5
|
| 10 |
|
|
//
|
| 11 |
|
|
// Note the Julian day begins at noon, which allows astronomers to have all
|
| 12 |
|
|
// the dates in a single observing session the same.
|
| 13 |
|
|
//
|
| 14 |
|
|
// References:
|
| 15 |
|
|
// "Astronomical Formulae for Calculators", Jean Meeus
|
| 16 |
|
|
// "Satellite Communications", Dennis Roddy, 2nd Edition, 1995.
|
| 17 |
|
|
//
|
| 18 |
|
|
// Copyright (c) 2003 Michael F. Henry
|
| 19 |
|
|
//
|
| 20 |
|
|
// mfh 12/24/2003
|
| 21 |
|
|
//
|
| 22 |
|
|
#include "stdafx.h"
|
| 23 |
|
|
#include "globals.h"
|
| 24 |
|
|
#include "cJulian.h"
|
| 25 |
|
|
#include "math.h"
|
| 26 |
|
|
#include "time.h"
|
| 27 |
|
|
|
| 28 |
|
|
//////////////////////////////////////////////////////////////////////////////
|
| 29 |
|
|
// Create a Julian date object from a time_t object. time_t objects store the
|
| 30 |
|
|
// number of seconds since midnight UTC January 1, 1970.
|
| 31 |
|
|
cJulian::cJulian(time_t time)
|
| 32 |
|
|
{
|
| 33 |
|
|
struct tm *ptm = gmtime(&time);
|
| 34 |
|
|
assert(ptm);
|
| 35 |
|
|
|
| 36 |
|
|
int year = ptm->tm_year + 1900;
|
| 37 |
|
|
double day = ptm->tm_yday + 1 +
|
| 38 |
|
|
(ptm->tm_hour +
|
| 39 |
|
|
((ptm->tm_min +
|
| 40 |
|
|
(ptm->tm_sec / 60.0)) / 60.0)) / 24.0;
|
| 41 |
|
|
|
| 42 |
|
|
Initialize(year, day);
|
| 43 |
|
|
}
|
| 44 |
|
|
|
| 45 |
|
|
//////////////////////////////////////////////////////////////////////////////
|
| 46 |
|
|
// Create a Julian date object from a year and day of year.
|
| 47 |
|
|
// Example parameters: year = 2001, day = 1.5 (Jan 1 12h)
|
| 48 |
|
|
cJulian::cJulian(int year, double day)
|
| 49 |
|
|
{
|
| 50 |
|
|
Initialize(year, day);
|
| 51 |
|
|
}
|
| 52 |
|
|
|
| 53 |
|
|
//////////////////////////////////////////////////////////////////////////////
|
| 54 |
|
|
// Create a Julian date object.
|
| 55 |
|
|
cJulian::cJulian(int year, // i.e., 2004
|
| 56 |
|
|
int mon, // 1..12
|
| 57 |
|
|
int day, // 1..31
|
| 58 |
|
|
int hour, // 0..23
|
| 59 |
|
|
int min, // 0..59
|
| 60 |
|
|
double sec /* = 0.0 */) // 0..(59.999999...)
|
| 61 |
|
|
|
| 62 |
|
|
{
|
| 63 |
|
|
// Calculate N, the day of the year (1..366)
|
| 64 |
|
|
int N;
|
| 65 |
|
|
int F1 = (int)((275.0 * mon) / 9.0);
|
| 66 |
|
|
int F2 = (int)((mon + 9.0) / 12.0);
|
| 67 |
|
|
|
| 68 |
|
|
if (IsLeapYear(year))
|
| 69 |
|
|
{
|
| 70 |
|
|
// Leap year
|
| 71 |
|
|
N = F1 - F2 + day - 30;
|
| 72 |
|
|
}
|
| 73 |
|
|
else
|
| 74 |
|
|
{
|
| 75 |
|
|
// Common year
|
| 76 |
|
|
N = F1 - (2 * F2) + day - 30;
|
| 77 |
|
|
}
|
| 78 |
|
|
|
| 79 |
|
|
double dblDay = N + (hour + (min + (sec / 60.0)) / 60.0) / 24.0;
|
| 80 |
|
|
|
| 81 |
|
|
Initialize(year, dblDay);
|
| 82 |
|
|
}
|
| 83 |
|
|
|
| 84 |
|
|
//////////////////////////////////////////////////////////////////////////////
|
| 85 |
|
|
void cJulian::Initialize(int year, double day)
|
| 86 |
|
|
{
|
| 87 |
|
|
// 1582 A.D.: 10 days removed from calendar
|
| 88 |
|
|
// 3000 A.D.: Arbitrary error checking limit
|
| 89 |
|
|
assert((year > 1582) && (year < 3000));
|
| 90 |
|
|
assert((day >= 0.0) && (day <= 366.5));
|
| 91 |
|
|
|
| 92 |
|
|
// Now calculate Julian date
|
| 93 |
|
|
|
| 94 |
|
|
year--;
|
| 95 |
|
|
|
| 96 |
|
|
// Centuries are not leap years unless they divide by 400
|
| 97 |
|
|
int A = (year / 100);
|
| 98 |
|
|
int B = 2 - A + (A / 4);
|
| 99 |
|
|
|
| 100 |
|
|
double NewYears = (int)(365.25 * year) +
|
| 101 |
|
|
(int)(30.6001 * 14) +
|
| 102 |
|
|
1720994.5 + B; // 1720994.5 = Oct 30, year -1
|
| 103 |
|
|
|
| 104 |
|
|
m_Date = NewYears + day;
|
| 105 |
|
|
}
|
| 106 |
|
|
|
| 107 |
|
|
//////////////////////////////////////////////////////////////////////////////
|
| 108 |
|
|
// getComponent()
|
| 109 |
|
|
// Return requested components of date.
|
| 110 |
|
|
// Year : Includes the century.
|
| 111 |
|
|
// Month: 1..12
|
| 112 |
|
|
// Day : 1..31 including fractional part
|
| 113 |
|
|
void cJulian::getComponent(int *pYear,
|
| 114 |
|
|
int *pMon /* = NULL */,
|
| 115 |
|
|
double *pDOM /* = NULL */) const
|
| 116 |
|
|
{
|
| 117 |
|
|
assert(pYear != NULL);
|
| 118 |
|
|
|
| 119 |
|
|
double jdAdj = getDate() + 0.5;
|
| 120 |
|
|
int Z = (int)jdAdj; // integer part
|
| 121 |
|
|
double F = jdAdj - Z; // fractional part
|
| 122 |
|
|
double alpha = (int)((Z - 1867216.25) / 36524.25);
|
| 123 |
|
|
double A = Z + 1 + alpha - (int)(alpha / 4.0);
|
| 124 |
|
|
double B = A + 1524.0;
|
| 125 |
|
|
int C = (int)((B - 122.1) / 365.25);
|
| 126 |
|
|
int D = (int)(C * 365.25);
|
| 127 |
|
|
int E = (int)((B - D) / 30.6001);
|
| 128 |
|
|
|
| 129 |
|
|
double DOM = B - D - (int)(E * 30.6001) + F;
|
| 130 |
|
|
int month = (E < 13.5) ? (E - 1) : (E - 13);
|
| 131 |
|
|
int year = (month > 2.5) ? (C - 4716) : (C - 4715);
|
| 132 |
|
|
|
| 133 |
|
|
*pYear = year;
|
| 134 |
|
|
|
| 135 |
|
|
if (pMon != NULL)
|
| 136 |
|
|
*pMon = month;
|
| 137 |
|
|
|
| 138 |
|
|
if (pDOM != NULL)
|
| 139 |
|
|
*pDOM = DOM;
|
| 140 |
|
|
}
|
| 141 |
|
|
|
| 142 |
|
|
//////////////////////////////////////////////////////////////////////////////
|
| 143 |
|
|
// toGMST()
|
| 144 |
|
|
// Calculate Greenwich Mean Sidereal Time for the Julian date. The return value
|
| 145 |
|
|
// is the angle, in radians, measuring eastward from the Vernal Equinox to the
|
| 146 |
|
|
// prime meridian. This angle is also referred to as "ThetaG" (Theta GMST).
|
| 147 |
|
|
//
|
| 148 |
|
|
// References:
|
| 149 |
|
|
// The 1992 Astronomical Almanac, page B6.
|
| 150 |
|
|
// Explanatory Supplement to the Astronomical Almanac, page 50.
|
| 151 |
|
|
// Orbital Coordinate Systems, Part III, Dr. T.S. Kelso, Satellite Times,
|
| 152 |
|
|
// Nov/Dec 1995
|
| 153 |
|
|
double cJulian::toGMST() const
|
| 154 |
|
|
{
|
| 155 |
|
|
const double UT = fmod(m_Date + 0.5, 1.0);
|
| 156 |
|
|
const double TU = (FromJan1_12h_2000() - UT) / 36525.0;
|
| 157 |
|
|
|
| 158 |
|
|
double GMST = 24110.54841 + TU *
|
| 159 |
|
|
(8640184.812866 + TU * (0.093104 - TU * 6.2e-06));
|
| 160 |
|
|
|
| 161 |
|
|
GMST = fmod(GMST + SEC_PER_DAY * OMEGA_E * UT, SEC_PER_DAY);
|
| 162 |
|
|
|
| 163 |
|
|
if (GMST < 0.0)
|
| 164 |
|
|
GMST += SEC_PER_DAY; // "wrap" negative modulo value
|
| 165 |
|
|
|
| 166 |
|
|
return (TWOPI * (GMST / SEC_PER_DAY));
|
| 167 |
|
|
}
|
| 168 |
|
|
|
| 169 |
|
|
//////////////////////////////////////////////////////////////////////////////
|
| 170 |
|
|
// toLMST()
|
| 171 |
|
|
// Calculate Local Mean Sidereal Time for given longitude (for this date).
|
| 172 |
|
|
// The longitude is assumed to be in radians measured west from Greenwich.
|
| 173 |
|
|
// The return value is the angle, in radians, measuring eastward from the
|
| 174 |
|
|
// Vernal Equinox to the given longitude.
|
| 175 |
|
|
double cJulian::toLMST(double lon) const
|
| 176 |
|
|
{
|
| 177 |
|
|
return fmod(toGMST() + lon, TWOPI);
|
| 178 |
|
|
}
|
| 179 |
|
|
|
| 180 |
|
|
//////////////////////////////////////////////////////////////////////////////
|
| 181 |
|
|
// toTime()
|
| 182 |
|
|
// Convert to type time_t
|
| 183 |
|
|
// Avoid using this function as it discards the fractional seconds of the
|
| 184 |
|
|
// time component.
|
| 185 |
|
|
time_t cJulian::toTime() const
|
| 186 |
|
|
{
|
| 187 |
|
|
int nYear;
|
| 188 |
|
|
int nMonth;
|
| 189 |
|
|
double dblDay;
|
| 190 |
|
|
|
| 191 |
|
|
getComponent(&nYear, &nMonth, &dblDay);
|
| 192 |
|
|
|
| 193 |
|
|
// dblDay is the fractional Julian Day (i.e., 29.5577).
|
| 194 |
|
|
// Save the whole number day in nDOM and convert dblDay to
|
| 195 |
|
|
// the fractional portion of day.
|
| 196 |
|
|
int nDOM = (int)dblDay;
|
| 197 |
|
|
|
| 198 |
|
|
dblDay -= nDOM;
|
| 199 |
|
|
|
| 200 |
|
|
const int SEC_PER_MIN = 60;
|
| 201 |
|
|
const int SEC_PER_HR = 60 * SEC_PER_MIN;
|
| 202 |
|
|
const int SEC_PER_DAY = 24 * SEC_PER_HR;
|
| 203 |
|
|
|
| 204 |
|
|
int secs = (int)((dblDay * SEC_PER_DAY) + 0.5);
|
| 205 |
|
|
|
| 206 |
|
|
// Create a "struct tm" type.
|
| 207 |
|
|
// NOTE:
|
| 208 |
|
|
// The "struct tm" type has a 1-second resolution. Any fractional
|
| 209 |
|
|
// component of the "seconds" time value is discarded.
|
| 210 |
|
|
struct tm tGMT;
|
| 211 |
|
|
memset(&tGMT, 0, sizeof(tGMT));
|
| 212 |
|
|
|
| 213 |
|
|
tGMT.tm_year = nYear - 1900; // 2001 is 101
|
| 214 |
|
|
tGMT.tm_mon = nMonth - 1; // January is 0
|
| 215 |
|
|
tGMT.tm_mday = nDOM; // First day is 1
|
| 216 |
|
|
tGMT.tm_hour = secs / SEC_PER_HR;
|
| 217 |
|
|
tGMT.tm_min = (secs % SEC_PER_HR) / SEC_PER_MIN;
|
| 218 |
|
|
tGMT.tm_sec = (secs % SEC_PER_HR) % SEC_PER_MIN;
|
| 219 |
|
|
tGMT.tm_isdst = 0; // No conversion desired
|
| 220 |
|
|
|
| 221 |
|
|
time_t tEpoch = mktime(&tGMT);
|
| 222 |
|
|
|
| 223 |
|
|
if (tEpoch != -1)
|
| 224 |
|
|
{
|
| 225 |
|
|
// Valid time_t value returned from mktime().
|
| 226 |
|
|
// mktime() expects a local time which means that tEpoch now needs
|
| 227 |
|
|
// to be adjusted by the difference between this time zone and GMT.
|
| 228 |
|
|
tEpoch -= timezone;
|
| 229 |
|
|
}
|
| 230 |
|
|
|
| 231 |
|
|
return tEpoch;
|
| 232 |
|
|
}
|