Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Class Members | File Members | Related Pages

TimeManager.cpp

Go to the documentation of this file.
00001 /*
00002  * TimeManager.cpp
00003  *
00004  * Part of Fly! Legacy project
00005  *
00006  * Copyright 2003 Chris Wallace
00007  *
00008  * Fly! Legacy is free software; you can redistribute it and/or modify
00009  *   it under the terms of the GNU General Public License as published by
00010  *   the Free Software Foundation; either version 2 of the License, or
00011  *   (at your option) any later version.
00012  *
00013  * Fly! Legacy is distributed in the hope that it will be useful,
00014  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  *   GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License
00019  *   along with Fly! Legacy; if not, write to the Free Software
00020  *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00021  *
00022  */
00023 
00036 #include <time.h>
00037 #include "../Include/TimeManager.h"
00038 #include "../Include/Utility.h"
00039 #include "../Include/Ui.h"
00040 #include "../Include/Globals.h"
00041 
00042 
00043 CTimeManager::CTimeManager (void)
00044 {
00045 #ifdef PRECISION_TIMER_WIN32
00046   // Initialize Win32 performance counter variables
00047   count.QuadPart = 0;
00048   prev_count.QuadPart = 0;
00049 #endif
00050 
00051 #ifdef PRECISION_TIMER_PLIB
00052   // Instantiate ulClock
00053   clock = new ulClock;
00054 #endif
00055 
00056   // Initialize time scale
00057   scale = 1.0;
00058 
00059   // Default to un-paused
00060   paused = false;
00061 
00062   // Initialize epoch to current system time
00063   time_t t;
00064   time (&t);
00065   struct tm* utc = gmtime (&t);
00066   if (utc != NULL) {
00067     epoch.date.year = utc->tm_year;
00068     epoch.date.month = utc->tm_mon + 1;
00069     epoch.date.day = utc->tm_mday;
00070     epoch.time.hour = utc->tm_hour;
00071     epoch.time.minute = utc->tm_min;
00072     epoch.time.second = utc->tm_sec;
00073     epoch.time.msecs = 0;
00074   } else {
00075     // Error converting system time, default to midnight Jan 1 2000
00076     epoch.date.year = 2000;
00077     epoch.date.month = 1;
00078     epoch.date.day = 1;
00079     epoch.time.hour = 0;
00080     epoch.time.minute = 0;
00081     epoch.time.second = 0;
00082     epoch.time.msecs = 0;
00083   }
00084 
00085   // Initialize timezone to UTC
00086   tzDelta.dYears = 0;
00087   tzDelta.dMonths = 0;
00088   tzDelta.dDays = 0;
00089   tzDelta.dHours = 0;
00090   tzDelta.dMinutes = 0;
00091   tzDelta.dSeconds = 0;
00092   tzDelta.dMillisecs = 0;
00093   tzSubtract = false;
00094 
00095   // Initialize simulation elapsed time
00096   elapsed = 0;
00097 }
00098 
00099 
00105 void CTimeManager::SetUTCDateTime (SDateTime dt)
00106 {
00107   epoch = dt;
00108   elapsed = 0;
00109 }
00110 
00118 void CTimeManager::SetLocalDateTime (SDateTime dt)
00119 {
00120   // Adjust local time by timezone delta to get UTC time
00121   if (tzSubtract) {
00122     // TZ delta is subtracted from UTC to get local, so we have to add the delta
00123     //   to the supplied local time to get UTC
00124     dt = AddTimeDelta (dt, tzDelta);
00125   } else {
00126     // TZ delta is added to UTC to get local, so we have to subtract the delta
00127     //   from the supplied local time to get UTC
00128     dt = SubtractTimeDelta (dt, tzDelta);
00129   }
00130 
00131   SetUTCDateTime (dt);
00132 }
00133 
00144 void CTimeManager::SetTimeZoneDelta (bool subtract, SDateTimeDelta delta)
00145 {
00146   tzSubtract = subtract;
00147   tzDelta = delta;
00148 }
00149 
00158 void CTimeManager::SetTimeZoneOffset (float offset)
00159 {
00160   if (offset < 0) {
00161     // Offset should be subtracted from UTC to get local time
00162     tzSubtract = true;
00163     offset = -offset;
00164   } else {
00165     // Offset should be added to UTC to get local time
00166     tzSubtract = false;
00167   }
00168 
00169   // Convert hours offset to SDateTimeDelta struct
00170   tzDelta.dHours = (int)(floor (offset));
00171   tzDelta.dMinutes = (int)(fmod (offset, 1.0) * 60);
00172 
00174 }
00175 
00176 //
00177 // Get local time zone offset in hours relative to UTC
00178 //
00179 void CTimeManager::GetTimeZoneDelta (SDateTimeDelta &delta, bool &subtract)
00180 {
00181   delta = tzDelta;
00182   subtract = tzSubtract;
00183 }
00184 
00185 
00186 //
00187 // Get local time zone offset in hours relative to UTC
00188 //
00189 float CTimeManager::GetTimeZoneOffset (void)
00190 {
00191   float offset = (float)tzDelta.dHours + ((float)tzDelta.dMinutes / 60);
00192   if (tzSubtract) offset = -offset;
00193 
00194   return offset;
00195 }
00196 
00197 
00198 //
00199 // This method is called after all initialization has been done and the simulation
00200 //   is about to begin.  Simulation time "starts" after this method is called
00201 //
00202 void CTimeManager::Prepare (void)
00203 {
00204 #ifdef PRECISION_TIMER_WIN32
00205   // Determine the frequency of the high performance counter
00206   LARGE_INTEGER perf_freq;
00207   if (!QueryPerformanceFrequency (&perf_freq)) {
00208     gtfo ("CTimeManager : QueryPerformanceFrequency failed");
00209   }
00210   freq = (float)perf_freq.QuadPart;
00211 
00212   // Initialize high performance counter for use in delta time comparison in Update()
00213   QueryPerformanceCounter (&prev_count);
00214 #endif
00215 
00216   dSimTime = 0;
00217   dRealTime = 0;
00218   elapsed = 0;
00219 }
00220 
00221 
00222 //
00223 // Returns the simulation UTC date and time
00224 //
00225 // Note: Contrary to localtime() convention, the month value ranges
00226 //   from 1..12 for January..December
00227 //
00228 SDateTime CTimeManager::GetUTCDateTime (void)
00229 {
00230   // Convert sim elapsed time from seconds to days
00231   SDateTimeDelta delta = SecondsToDateTimeDelta (elapsed);
00232 
00233   // Add elapsed time delta to epoch date/time
00234   SDateTime dt = AddTimeDelta (epoch, delta);
00235 
00236   return dt;
00237 }
00238 
00239 //
00240 // Returns the simulation local date and time.  Note this is based on the
00241 //   timezone of the users' PC, not that of the simulation location.
00242 //
00243 // Note: Contrary to localtime() convention, the month value ranges
00244 //   from 1..12 for January..December
00245 //
00246 SDateTime CTimeManager::GetLocalDateTime (void)
00247 {
00248   SDateTime dt = GetUTCDateTime ();
00249 
00250   // Adjust by time zone offset
00251   if (tzSubtract) {
00252     dt = SubtractTimeDelta (dt, tzDelta);
00253   } else {
00254     dt = AddTimeDelta (dt, tzDelta);
00255   }
00256 
00257   return dt;
00258 }
00259 
00260 //
00261 // Return the sim Universal time as julian date
00262 //
00263 double CTimeManager::GetJulianDate (void)
00264 {
00265   SDateTime dt = GetUTCDateTime ();
00266   double jd = JulianDate (dt);
00267   return jd;
00268 }
00269 
00270 //
00271 // Return the sim Universal time as modified julian date
00272 //
00273 double CTimeManager::GetModifiedJulianDate (void)
00274 {
00275   double jd = GetJulianDate ();
00276   double mjd = jd - 2400000.5;
00277   return mjd;
00278 }
00279 
00280 
00281 #define DEGHR(x)        ((x)/15.)
00282 #define ARCSECHR(x)   DEGHR((x)/3600)
00283 
00284 
00285 static const double J2000   = 2451545.0;
00286 static const double SIDRATE = 0.9972695677;
00287 
00288 
00289 //
00290 // Return Greenwich Mean Sidereal Time, in decimal hours
00291 //   
00292 // Algorithm taken based on: http://aa.usno.navy.mil/faq/docs/GAST.html
00293 //   (The T^2 element is not included)
00294 //
00295 double CTimeManager::GetGreenwichSiderealTime (void)
00296 {
00297   double jd = GetJulianDate ();
00298   
00299   // Calculate julian date of the last midnight
00300   double jd0 = floor (jd - 0.5) + 0.5;
00301 
00302   // Calculate hours elapsed since last midnight
00303   double hrs = (jd - jd0) * 24.0;
00304 
00305   // Modify the dates relative to J2000.0 epoch (JD 2451545.0)
00306   double d0 = jd0 -= J2000;
00307 
00308   // Calculate GMST
00309   double gmst = 6.697374558 +
00310               (0.06570982441908 * d0) +
00311           (1.00273790935 * hrs);
00312   gmst = Wrap24 (gmst);
00313 
00314   return gmst;
00315 }
00316 
00317 
00318 //
00319 // Return Local Sidereal Time, in decimal hours, based
00320 //   on the current sim time and the supplied longitude
00321 //   (in arcseconds East of the Prime Meridian)
00322 //
00323 double CTimeManager::GetLocalSiderealTime (double lon)
00324 {
00325   // Get Greenwich Sidereal Time in decimal hours
00326   double gst = GetGreenwichSiderealTime();
00327 
00328   // Convert longitude to decimal hours
00329   double lonh = DEGHR (Wrap180 (lon / 3600));
00330 
00331   // The following is based on Paul Schluyter's web site:
00332   double lst = gst + lonh;
00333   lst = Wrap24 (lst);
00334   return lst;
00335 /*
00336   double lst = gst + (ARCSECHR(lon));
00337   lst -= 24 * floor (lst / 24);
00338   return lst;
00339 */
00340 }
00341 
00342 
00343 void CTimeManager::SetTimeScale (float scale)
00344 {
00345   this->scale = scale;
00346 }
00347 
00348 
00349 float CTimeManager::GetTimeScale (void)
00350 {
00351   return scale;
00352 }
00353 
00354 bool CTimeManager::GetPauseState (void)
00355 {
00356   return paused;
00357 }
00358 
00359 void CTimeManager::Pause (void)
00360 {
00361   paused = true;
00362 }
00363 
00364 void CTimeManager::Unpause (void)
00365 {
00366   paused = false;
00367 }
00368 
00369 #ifdef _MSC_VER
00370 #pragma warning(push)
00371 #pragma warning(disable:4701)
00372 #endif
00373 
00374 void CTimeManager::Update (void)
00375 {
00376 #ifdef PRECISION_TIMER_WIN32
00377   LARGE_INTEGER delta;
00378 
00379   // Get current value of performance timer
00380   if (QueryPerformanceCounter (&count)) {
00381     // Check for wrap-around
00382     if (count.QuadPart < prev_count.QuadPart) {
00383       delta.QuadPart = count.QuadPart + (MAXLONGLONG - prev_count.QuadPart);
00384     } else {
00385       delta.QuadPart = count.QuadPart - prev_count.QuadPart;
00386     }
00387     prev_count = count;
00388   }
00389 
00390   // Calculate time since last time update
00391   dRealTime = (float)delta.QuadPart / freq;
00392 #endif
00393 
00394 #ifdef PRECISION_TIMER_PLIB
00395   dRealTime = (float)(clock->getDeltaTime());
00396 #endif
00397 
00398   // Store frame rate sample
00399   globals->drawRate->AddSample (1.0f / dRealTime);
00400 
00401   // Calculate simulation elapsed time for this update
00402   dSimTime = scale * dRealTime;
00403 
00404 //  char debug[80];
00405 //  sprintf (debug, "TimeManager::Update : dRealTime = %10.8f  dSimTime=%10.8f",
00406 //    dRealTime, dSimTime);
00407 //  DrawNoticeToUser (debug, 1);
00408 
00409   // If sim is not paused, update sim elapsed time
00410   if (!paused) {
00411     elapsed += dSimTime;
00412   }
00413 }
00414 
00415 #ifdef _MSC_VER
00416 #pragma warning(pop)
00417 #endif
00418 
00419 //
00420 // Return sim elapsed time
00421 //
00422 float CTimeManager::GetElapsedSimTime (void)
00423 {
00424   return elapsed;
00425 }
00426 
00427 //
00428 // Return the amount of time between the last time manager update
00429 //
00430 float CTimeManager::GetDeltaRealTime (void)
00431 {
00432   return dRealTime;
00433 }
00434 
00435 //
00436 // Return the amount of sim time between the last time manager updates
00437 //
00438 float CTimeManager::GetDeltaSimTime (void)
00439 {
00440   return dSimTime;
00441 }
00442 
00443 //
00444 // Algorithm supplied from:
00445 //    Almanac for Computers, 1990
00446 //    Nautical Almanac Office
00447 //    United States Naval Observatory
00448 //
00449 void CTimeManager::SunriseSunset (SPosition pos, SDate date, float zenith,
00450                   STime &rise, STime &set,
00451                   bool &neverRises, bool& neverSets)
00452 {
00453   // Step 0 - Initialize
00454   rise.second = 0;
00455   rise.msecs = 0;
00456   set.second = 0;
00457   set.msecs = 0;
00458 
00459   // Step 1 - Calculate day of year
00460   float n1 = (float)(floor(275 * date.month / 9));
00461   float n2 = (float)(floor((date.month + 9) / 12));
00462   float n3 = (float)((1 + floor((date.year - 4 * floor(date.year / 4) + 2) / 3)));
00463   float n = n1 - (n2 * n3) + date.day - 30;
00464 
00465 //  WriteLog ("n1=%f n2=%f n3=%f n=%f\n", n1, n2, n3, n);
00466 
00467   // Step 2 - Convert lon to hour value and compute approximate time
00468   float lonHour = (float)(pos.lon / 15);
00469 
00470 //  WriteLog ("lonHour=%f\n", lonHour);
00471 
00472   float tRise = n + ((6 - lonHour) / 24);
00473   float tSet = n + ((18 - lonHour) / 24);
00474 
00475 //  WriteLog ("tRise=%f  tSet=%f\n", tRise, tSet);
00476 
00477   // Step 3 - Calculate sun's mean anomaly
00478   float mRise = (0.9856f * tRise) - 3.289f;
00479   float mSet = (0.9856f * tSet) - 3.289f;
00480 
00481 //  WriteLog ("mRise=%f mSet=%f\n", mRise, mSet);
00482 
00483   // Step 4 - Calculate sun's true longitude
00484   float lonRise = (float)(mRise + (1.916 * sin(mRise)) + (0.020 * sin(2 * mRise)) + 282.634);
00485   Wrap360 (lonRise);
00486 
00487   float lonSet = (float)(mSet + (1.916 * sin(mSet)) + (0.020 * sin(2 * mSet)) + 282.634);
00488   Wrap360 (lonSet);
00489 
00490 //  WriteLog ("lonRise=%f lonSet=%f\n", lonRise, lonSet);
00491 
00492   // Step 5a - Calculate right ascension
00493   float raRise = RadToDeg ((float)(atan(0.91764 * tan(lonRise))));
00494   Wrap360 (raRise);
00495 
00496   float raSet = RadToDeg ((float)(atan(0.91764 * tan(lonSet))));
00497   Wrap360 (raSet);
00498 
00499 //  WriteLog ("a - raRise=%f raSet=%f\n", raRise, raSet);
00500 
00501   // Step 5b - Adjust RA to same quadrant as longitude
00502   float quadrantLon = (float)(floor(lonRise/90) * 90);
00503   float quadrantRA = (float)(floor(raRise/90) * 90);
00504   raRise += quadrantLon - quadrantRA;
00505   
00506   quadrantLon = (float)(floor(lonSet/90) * 90);
00507   quadrantRA = (float)(floor(raSet/90) * 90);
00508   raSet += quadrantLon - quadrantRA;
00509   
00510 //  WriteLog ("b - raRise=%f raSet=%f\n", raRise, raSet);
00511 
00512   // Step 5c - Convert RA to hours
00513   raRise /= 15;
00514   raSet /= 15;
00515 
00516 //  WriteLog ("c - raRise=%f, raSet=%f\n", raRise, raSet);
00517 
00518   // Step 6 - Calculate sun's declination
00519   double sinDecRise = (0.39782 * sin(lonRise));
00520   double cosDecRise = (cos(asin(sinDecRise)));
00521 
00522   double sinDecSet = (0.39782 * sin(lonSet));
00523   double cosDecSet = (cos(asin(sinDecSet)));
00524 
00525 //  WriteLog ("sinDecRise = %g cosDecRise = %g\n", sinDecRise, cosDecRise);
00526 
00527   // Step 7a - Calculate sun's local hour angle
00528   double cosHRise = (float)(cos(zenith) - (sinDecRise * sin(pos.lat))) / (cosDecRise * cos(pos.lat));
00529   double cosHSet = (float)(cos(zenith) - (sinDecSet * sin(pos.lat))) / (cosDecSet * cos(pos.lat));
00530 
00531 //  WriteLog ("cosHRise = %f\n", cosHRise);
00532 
00533   neverRises = false;
00534   if (cosHRise > 1) {
00535     // Sun never rises
00536     neverRises = true;
00537   }
00538 
00539   neverSets = false;
00540   if (cosHRise < -1) {
00541     // Sun never sets
00542     neverSets = true;
00543   }
00544 
00545   // Step 7b - Finish calculating H and convert into hours
00546   float hRise = (float)(360 - RadToDeg(acos(cosHRise)));
00547   hRise /= 15;
00548 
00549   float hSet = (float)(RadToDeg (acos(cosHSet)));
00550   hSet /= 15;
00551 
00552 //  WriteLog ("hRise=%f hSet=%f\n", hRise, hSet);
00553 
00554   // Step 8 - Calculate local mean time
00555   float timeRise = (float)(hRise + raRise - (0.06571 * tRise) - 6.622);
00556   float timeSet = (float)(hSet + raSet - (0.06571 * tSet) - 6.622);
00557 
00558   // Step 9 - Adjust to UTC
00559   float utRise = timeRise - lonHour;
00560   Wrap24 (utRise);
00561 
00562   float utSet = timeSet - lonHour;
00563   Wrap24 (utSet);
00564 
00565   // Update input arguments
00566   rise.hour = (int)(floor(utRise));
00567   rise.minute = (int)(fmod(utRise, 1.0) * 60);
00568 
00569   set.hour = (int)(floor(utSet));
00570   set.minute = (int)(fmod(utSet, 1.0) * 60);
00571 }
00572 
00573 
00574 int CTimeManager::DaysInMonth (int month, int year)
00575 {
00576   unsigned int rc = 30;
00577 
00578   switch (month) {
00579   case 1:
00580     // January
00581     rc = 31;
00582     break;
00583 
00584   case 2:
00585     // February
00586     if ((year % 4 == 0) && (year % 400 != 0)) {
00587       // Leap year
00588       rc = 29;
00589     } else {
00590       // Normal year
00591       rc = 28;
00592     }
00593     break;
00594 
00595   case 3:
00596     // March
00597     rc = 31;
00598     break;
00599 
00600   case 4:
00601     // April
00602     rc = 30;
00603     break;
00604 
00605   case 5:
00606     // May
00607     rc = 31;
00608     break;
00609 
00610   case 6:
00611     // June
00612     rc = 30;
00613     break;
00614 
00615   case 7:
00616     // July
00617     rc = 31;
00618     break;
00619 
00620   case 8:
00621     // August
00622     rc = 31;
00623     break;
00624 
00625   case 9:
00626     // September
00627     rc = 30;
00628     break;
00629 
00630   case 10:
00631     // October
00632     rc = 31;
00633     break;
00634 
00635   case 11:
00636     // November
00637     rc = 30;
00638     break;
00639 
00640   case 12:
00641     // December
00642     rc = 31;
00643     break;
00644   }
00645 
00646   return rc;
00647 }
00648 
00649 
00650 //
00651 //  This function converts a Gregorian date and time of day into the corresponding
00652 //    Julian day number.
00653 //
00654 //  Parameters:
00655 //    d SDate structure containing year (relative to 1900)/month/day
00656 //    t STime structure containing hour/minute/second
00657 //
00658 double CTimeManager::JulianDate (SDateTime dt)
00659 {
00660   double j = 0;
00661 
00662   // Convert date to julian day number
00663   double yy = (double)dt.date.year + 1900.0;
00664   double mm = (double)dt.date.month;
00665   double dd = (double)dt.date.day;
00666 
00667   // Adjust for January/February if required
00668   if (mm < 3) {
00669     mm += 12;
00670     yy -= 1;
00671   }
00672 
00673   double a = floor (yy / 100);      // Non-leap days on even centuries
00674   double b = floor (a / 4);       // Leap days on even-four year bounds
00675   double c = 2 - a + b;         // Total number of leap days
00676   double e = floor (365.25 * (yy + 4716));// Days to zeroth day of year
00677   double f = floor (30.6001 * (mm + 1));  // Days to zeroth day of month
00678 
00679   j = c + dd + e + f - 1524.5;      // Total number of whole days
00680 
00681   double secs = dt.time.hour * 3600 +     // Number of seconds since midnight
00682           dt.time.minute * 60 +
00683           dt.time.second +
00684           (dt.time.msecs / 1000);
00685   j += secs / 86400;            // Fractional number of days
00686 
00687   return j;
00688 }
00689 
00690 
00691 //
00692 // Algorithm is based on that in Jean Meeus' "Astronomical Formulae for
00693 //   Calculators" as described on the "Ask Dr. Math" web site:
00694 //      http://mathforum.org/library/drmath/view/51907.html
00695 //
00696 SDateTime CTimeManager::CalendarDate (double j)
00697 {
00698   SDateTime dt;
00699 
00700   // Add 0.5 to julian date; z = whole part, f = fract part
00701   j += 0.5;
00702   double z = floor (j);
00703   double f = fmod (j, 1.0);
00704   
00705   // Calculate intermediate variables
00706   double a;
00707   if (z < 229161) {
00708     a = z;
00709   } else {
00710     double alpha = floor ((z - 1867216.25) / 36524.25);
00711     a = z + 1 + alpha - floor (alpha / 4);
00712   }
00713 
00714   double b = a + 1524;
00715   double c = floor ((b - 122.1) / 365.25);
00716   double d = floor (365.25 * c);
00717   double e = floor ((b - d) / 30.6001);
00718 
00719   // Calculate day of month (fractional)
00720   double dd = b - d - floor (30.6001 * e) + f;
00721 
00722   // Calculate month
00723   double mm;
00724   if (e < 13.5) {
00725     mm = e - 1;
00726   } else {
00727     mm = e - 13;
00728   }
00729 
00730   // Calculate year
00731   double yy;
00732   if (mm >= 2.5) {
00733     yy = c - 4716;
00734   } else {
00735     yy = c - 4715;
00736   }
00737 
00738   // Convert float day, month, year in to SDateTime
00739   dt.date.year  = (int) floor (yy);
00740   dt.date.month = (int) floor (mm);
00741   dt.date.day   = (int) floor (dd);
00742 
00743   // Convert fractional day to integer number of seconds
00744   int secs = (int) floor (fmod (dd, 1.0) * 86400);
00745   dt.time.hour  = secs / 3600;
00746   secs -= dt.time.hour * 3600;
00747   dt.time.minute  = secs / 60;
00748   dt.time.second  = secs % 60;
00749   dt.time.msecs = 0;
00750 
00751   return dt;
00752 }
00753 
00754 
00755 
00756 //
00757 // Convert a raw number of seconds into a SDateTimeDelta struct
00758 //
00759 // NOTE: This function cannot compute the number of months and years
00760 //   since this depends on the starting date at which the delta is applied.
00761 //   The dMonths and dYears fields of the returned SDateTime struct will
00762 //   always be zero.  The dDays field may be any number of days (not necessarily
00763 //   less than a month).
00764 //
00765 #define   SECS_PER_MINUTE   (60)
00766 #define   SECS_PER_HOUR   (SECS_PER_MINUTE * 60)
00767 #define   SECS_PER_DAY    (SECS_PER_HOUR * 24)
00768 
00769 SDateTimeDelta CTimeManager::SecondsToDateTimeDelta (float s)
00770 {
00771   SDateTimeDelta delta;
00772 
00773   float days = floorf (s / SECS_PER_DAY);
00774   s -= days * SECS_PER_DAY;
00775   float hrs = floorf (s / SECS_PER_HOUR);
00776   s -= hrs * SECS_PER_HOUR;
00777   float min = floorf (s / SECS_PER_MINUTE);
00778   s -= min * SECS_PER_MINUTE;
00779   float secs = floorf (s);
00780   s -= secs;
00781   float msecs = fmodf (s, 1) * 1000;
00782 
00783   delta.dYears = 0;
00784   delta.dMonths = 0;
00785   delta.dDays = (int)days;
00786   delta.dHours = (int)hrs;
00787   delta.dMinutes = (int)min;
00788   delta.dSeconds = (int)secs;
00789   delta.dMillisecs = (int)msecs;
00790 
00791   return delta;
00792 }
00793 
00794 
00795 double CTimeManager::DateTimeDeltaToDays (SDateTimeDelta delta)
00796 {
00797   double result = 0;
00798 
00799   result += delta.dDays;
00800   result += delta.dHours * (SECS_PER_HOUR / SECS_PER_DAY);
00801   result += delta.dMinutes * (SECS_PER_MINUTE / SECS_PER_DAY);
00802   result += delta.dSeconds * (1 / SECS_PER_DAY);
00803   result += delta.dMillisecs / 1000;
00804 
00805   return result;
00806 }
00807 
00808 
00809 
00810 #define   DAYS_PER_HOUR   (1 / 24)
00811 #define   DAYS_PER_MINUTE   (DAYS_PER_HOUR / 60)
00812 #define   DAYS_PER_SECOND   (DAYS_PER_MINUTE / 60)
00813 #define   DAYS_PER_MSEC   (DAYS_PER_SECOND / 1000)
00814 
00815 SDateTimeDelta CTimeManager::DaysToDateTimeDelta (double d)
00816 {
00817   float days = floorf (d);
00818   d -= days;
00819   float hrs = floorf (d * DAYS_PER_HOUR);
00820   d -= hrs * DAYS_PER_HOUR;
00821   float min = floorf (d * DAYS_PER_MINUTE);
00822   d -= min * DAYS_PER_MINUTE;
00823   float secs = floorf (d * DAYS_PER_SECOND);
00824   d -= secs * DAYS_PER_SECOND;
00825   float msecs = floorf (d * DAYS_PER_MSEC);
00826 
00827   SDateTimeDelta result;
00828 
00829   result.dYears = 0;
00830   result.dMonths = 0;
00831   result.dDays = (int)days;
00832   result.dHours = (int)hrs;
00833   result.dMinutes = (int)min;
00834   result.dSeconds = (int)secs;
00835   result.dMillisecs = (int)msecs;
00836 
00837   return result;
00838 }
00839 
00840 
00841 //
00842 // Add a time delta to the specified time.
00843 //
00844 // NOTE: As per the SDateTimeDelta definition, all delta values are positive
00845 //
00846 // NOTE: The SDateTimeDelta struct is assumed to have been constructed using
00847 //   one of the other CTimeManager functions, which do not support the
00848 //   dMonths and dYears fields.
00849 //
00850 // NOTE: This was first attempted by converting the starting date/time
00851 //   and the delta into julian days, but even double values do not have
00852 //   sufficient precision for small time deltas
00853 //
00854 SDateTime CTimeManager::AddTimeDelta (SDateTime dt, SDateTimeDelta delta)
00855 {
00856   SDateTime result;
00857   int carry = 0;
00858 
00859   // Add milliseconds
00860   result.time.msecs = dt.time.msecs + delta.dMillisecs;
00861   if (result.time.msecs > 999) {
00862     carry = 1;
00863     result.time.msecs -= 1000;
00864   } else {
00865     carry = 0;
00866   }
00867 
00868   // Add seconds
00869   result.time.second = dt.time.second + delta.dSeconds + carry;
00870   if (result.time.second > 59) {
00871     carry = 1;
00872     result.time.second -= 60;
00873   } else {
00874     carry = 0;
00875   }
00876 
00877   // Add minutes
00878   result.time.minute = dt.time.minute + delta.dMinutes + carry;
00879   if (result.time.minute > 59) {
00880     carry = 1;
00881     result.time.minute -= 60;
00882   } else {
00883     carry = 0;
00884   }
00885 
00886   // Add hours
00887   result.time.hour = dt.time.hour + delta.dHours + carry;
00888   if (result.time.hour > 23) {
00889     carry = 1;
00890     result.time.hour -= 24;
00891   } else {
00892     carry = 0;
00893   }
00894 
00895   // Add days
00896   result.date.day = dt.date.day + delta.dDays + carry;
00897   unsigned int daysInMonth = DaysInMonth (dt.date.month, dt.date.year);
00898   if (result.date.day > daysInMonth) {
00899     // Wrap ahead to next month
00900     result.date.month = dt.date.month + 1;
00901     if (result.date.month > 12) {
00902       result.date.year = dt.date.year + 1;
00903       result.date.month -= 12;
00904     } else {
00905       result.date.year = dt.date.year;
00906     }
00907     result.date.day -= daysInMonth;
00908   } else {
00909     result.date.year = dt.date.year;
00910     result.date.month = dt.date.month;
00911   }
00912 
00914 
00915   return result;
00916 }
00917 
00918 //
00919 // Add a time delta to the specified time.
00920 //
00921 // NOTE: As per the SDateTimeDelta definition, all delta values are positive
00922 //
00923 // NOTE: The SDateTimeDelta struct is assumed to have been constructed using
00924 //   one of the other CTimeManager functions, which do not support the
00925 //   dMonths and dYears fields.
00926 //
00927 // NOTE: This was first attempted by converting the starting date/time
00928 //   and the delta into julian days, but even double values do not have
00929 //   sufficient precision for small time deltas
00930 //
00931 SDateTime CTimeManager::SubtractTimeDelta (SDateTime dt, SDateTimeDelta delta)
00932 {
00933   SDateTime result;
00934   int carry = 0;
00935 
00936   int msecs = dt.time.msecs - delta.dMillisecs;
00937   if (msecs < 0) {
00938     carry = 1;
00939     msecs += 1000;
00940   } else {
00941     carry = 0;
00942   }
00943   result.time.msecs = msecs;
00944 
00945   int second =  dt.time.second - delta.dSeconds - carry;
00946   if (second < 0) {
00947     carry = 1;
00948     second += 60;
00949   } else {
00950     carry = 0;
00951   }
00952   result.time.second = second;
00953 
00954   int minute = dt.time.minute - delta.dMinutes - carry;
00955   if (minute < 0) {
00956     carry = 1;
00957     minute += 60;
00958   } else {
00959     carry = 0;
00960   }
00961   result.time.minute = minute;
00962 
00963   int hour = dt.time.hour - delta.dHours - carry;
00964   if (hour < 0) {
00965     carry = 1;
00966     hour += 24;
00967   } else {
00968     carry = 0;
00969   }
00970   result.time.hour = hour;
00971 
00972   int day = dt.date.day - delta.dDays - carry;
00973   if (day < 0) {
00974     // Wrap back to previous month
00975     result.date.year = dt.date.year;
00976     int month = dt.date.month - 1;
00977     if (month < 0) {
00978       result.date.year = dt.date.year - 1;
00979       month += 12;
00980     } else {
00981       result.date.year = dt.date.year;
00982     }
00983     result.date.month = month;
00984     day += DaysInMonth (result.date.month, result.date.year);
00985   } else {
00986     result.date.year = dt.date.year;
00987     result.date.month = dt.date.month;
00988   }
00989   result.date.day = day;
00990 
00991   return result;
00992 }
00993 
00994 
00995 //
00996 // Subtract two calendar date/time values to determine the delta between them
00997 //
00998 // NOTE: For simplicity, this function does not compute the number of months
00999 //   and years.  The dMonths and dYears fields of the returned SDateTimeDelta
01000 //   struct will always be zero.  The dDays field may be any number of days
01001 //   (not necessarily less than a month).
01002 //
01003 SDateTimeDelta CTimeManager::SubtractTime (SDateTime from, SDateTime to)
01004 {
01005   // Convert starting and ending date/time to julian dates
01006   double jdFrom = JulianDate (from);
01007   double jdTo = JulianDate (to);
01008 
01009   // Subtract julian dates
01010   double delta = jdTo - jdFrom;
01011 
01012   // Convert difference to SDateTimeDelta struct
01013   SDateTimeDelta result = DaysToDateTimeDelta (delta);
01014 
01015   return result;
01016 }
01017 
01018 
01019 //
01020 // Dump the contents of the CTimeManager class to a file for debugging
01021 //
01022 void CTimeManager::Print (FILE *f)
01023 {
01024   fprintf (f, "Time Manager :\n\n");
01025 
01026   // Print base date/time data
01027   double jd = GetJulianDate ();
01028   fprintf (f, "JD       : %12.3f\n", jd);
01029   double mjd = GetModifiedJulianDate ();
01030   fprintf (f, "MJD      : %12.3f\n", mjd);
01031   double gst = GetGreenwichSiderealTime();
01032   char st[64];
01033   FormatSiderealTime (gst, st);
01034   fprintf (f, "GST      : %s\n", st);
01035   fprintf (f, "\n");
01036 
01037   // Print UTC date/time
01038   SDateTime ut = GetUTCDateTime ();
01039   fprintf (f, "UTC Date   : %04d/%02d/%02d \n", ut.date.year + 1900, ut.date.month, ut.date.day);
01040   fprintf (f, "UTC Time   : %02d:%02d:%02d.%03d\n",
01041     ut.time.hour, ut.time.minute, ut.time.second, ut.time.msecs);
01042   fprintf (f, "\n");
01043 
01044   // Print local timezone
01045   int tzHours = tzDelta.dHours;
01046   int tzMinutes = tzDelta.dMinutes;
01047   if (tzSubtract) {
01048     tzHours = -tzHours;
01049   }
01050   fprintf (f, "Local timezone : %d h %d m\n", tzHours, tzMinutes);
01051   fprintf (f, "\n");
01052 
01053   // Printe local date/time
01054   SDateTime dt = GetLocalDateTime ();
01055   fprintf (f, "Local Date : %04d/%02d/%02d \n", dt.date.year + 1900, dt.date.month, dt.date.day);
01056   fprintf (f, "Local Time : %02d:%02d:%02d.%03d\n",
01057     dt.time.hour, dt.time.minute, dt.time.second, dt.time.msecs);
01058   fprintf (f, "\n");
01059 }
01060 
SourceForge.net Logo Documentation generated by doxygen