// @(#)datetime.cpp 1.5 -- 08/28/01 // datetime.cpp - Time class origninally created by Charles Schwarz to // store time in a standard format and provide functions // to allow conversion between different, commonly used // time formats. The code was changed to meet SDB // time definitions // 23-Aug-01 - Gordon Adams // Added SCCS keywords. // Changed the signatures for the initializer methods to have // the parameters passed by constant reference since they are // not changed and are structures. // Changed the signatures of the constructors to have the // parameters passed by reference since they are strucutres. // // 27-Jul-00 - Gordon Adams // Changed the "long double" declarations to "double". After // talking with Steve Hilla I learned that long double was not // providing anything to the effective precision of the // computations and that type is a different size on different // machines (80 to 128 bits). It may evn slow down computations // // 02-Jun-97 - Gordon Adams // Moved constants from the datetime.h file into the datetime.cpp // file since the datetime routines are the only ones that use // the constants. Created the getGPSSeconds() method that returns // the GPS time in seconds. // // Modified the GetYearDay() method to not use the mjd form of the // GPS time when generating the YearDay form. This gives an exact // representation of the seconds, thus preventing rounding errors. // A similar change was made to the // // Removed the old datetime constructor that took a YearDay // argument but went through the mjd format to initialize the // private variables. This step was unnecessary and caused // hassles with round-off errors. // 15-Aug-96 - Gordon Adams // Made modifications to handle the 400 year component // for computing the leap years. Charlie Schwarz did // most of the work and I made the final edits. // I moved the Leap[] and Normal[] arrays from datetime.h // to datetime.cpp since only the methods use them. I // also dropped the operator- that returned a DateTime // object. This was was a wrong idea since one date minus // another date does not yeild a third date. It just // yields a difference, in this case it is the number of // seconds. #include "datetime.h" #include const long DaysIn100Years = 36524; // 25 * 1461 - 1 const long DaysIn4Years = 1461; // 3 * 365 + 366 const long DaysIn400Years = 146097; // 4 * 36524 + 1 const long DaysInNonLeapYear = 365; const long DaysInWeek = 7; const long HoursInDay = 24; const long MJDJan61980 = 44244; // Start of GPS time const long MJDJan1Year1 = -678575; const long MinutesInDay = 1440; const long MinutesInHour = 60; const double SecondsInDay = 86400.0; const double SecondsInHour = 3600.0; const double SecondsInMin = 60.0; const double SecondsInWeek = 604800.0; const long Leap[ 13 ] = { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }; const long Normal[ 13 ] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }; // Constructors DateTime::DateTime() { GPSWeek = 0; secsOfWeek = 0.0; } DateTime::DateTime( GPSTime & gpstime ) { GPSWeek = gpstime.GPSWeek; secsOfWeek = gpstime.secsOfWeek; } DateTime::DateTime( MJD & mjd ) { GPSWeek = ( long ) floor( ( mjd.mjd - MJDJan61980 ) / (double) DaysInWeek ); secsOfWeek = ( ( double ) ( mjd.mjd - MJDJan61980 - GPSWeek * DaysInWeek ) + mjd.fmjd ) * SecondsInDay; } DateTime::DateTime( YearDay & yearday ) { long adjustedYear = yearday.year - 1; long mjd; mjd = ( adjustedYear/400 * DaysIn400Years ) + ( ( adjustedYear % 400 )/100 * DaysIn100Years ) + ( ( adjustedYear % 100 )/4 * DaysIn4Years ) + ( ( adjustedYear % 4 ) * DaysInNonLeapYear ) + ( yearday.yday - 1 ) + MJDJan1Year1; GPSWeek = ( long ) floor( ( mjd - MJDJan61980 ) / (double) DaysInWeek ); secsOfWeek = ( mjd - MJDJan61980 - GPSWeek * DaysInWeek ) * SecondsInDay; secsOfWeek += yearday.hour * SecondsInHour + yearday.min * SecondsInMin + yearday.sec; } DateTime::DateTime( const YearMonthDay & yearmonthday ) { YearDay yd; yd.year = yearmonthday.year; if ( yearmonthday.year % 400 == 0 || // leap year ( yearmonthday.year % 100 != 0 && yearmonthday.year % 4 == 0 ) ) { yd.yday = Leap[ yearmonthday.month - 1 ] + yearmonthday.monthday; } else // normal year { yd.yday = Normal[ yearmonthday.month - 1 ] + yearmonthday.monthday; } yd.hour = yearmonthday.hour; yd.min = yearmonthday.min; yd.sec = yearmonthday.sec; DateTime tt = DateTime( yd ); GPSWeek = tt.GPSWeek; secsOfWeek = tt.secsOfWeek; } DateTime::DateTime( unsigned long year, unsigned long month, unsigned long monthday, unsigned long hour, unsigned long min, double sec ) { YearDay yd; yd.year = year; if ( year % 400 == 0 || ( year % 100 != 0 && year % 4 == 0 ) ) { // leap year yd.yday = Leap[ month - 1 ] + monthday; } else // normal year { yd.yday = Normal[ month - 1 ] + monthday; } yd.hour = hour; yd.min = min; yd.sec = sec; DateTime tt = DateTime( yd ); GPSWeek = tt.GPSWeek; secsOfWeek = tt.secsOfWeek; } // Initializers - used to set the value of an existing variable. void DateTime::SetGPSTime( GPSTime & gpstime ) { *this = DateTime( gpstime ); } void DateTime::SetMJD( MJD & mjd ) { *this = DateTime( mjd ); } void DateTime::SetYearDay( YearDay & yearday ) { *this = DateTime( yearday ); } void DateTime::SetYearMonthDay( const YearMonthDay & yearmonthday ) { *this = DateTime( yearmonthday ); } void DateTime::SetYMDHMS( unsigned long year, unsigned long month, unsigned long monthday, unsigned long hour, unsigned long min, double sec ) { *this = DateTime( year, month, monthday, hour, min, sec ); } // Selectors - return the contents of a variable. double DateTime::GetGPSSeconds() { return ( ( GPSWeek * SecondsInWeek ) + secsOfWeek ); } GPSTime DateTime::GetGPSTime() { GPSTime tt; tt.GPSWeek = GPSWeek; tt.secsOfWeek = secsOfWeek; return tt; } MJD DateTime::GetMJD() { MJD mjd; mjd.mjd = ( long ) floor( ( GPSWeek * DaysInWeek ) + MJDJan61980 + secsOfWeek / SecondsInDay ); mjd.fmjd = fmod( secsOfWeek, SecondsInDay ) / SecondsInDay; return mjd; } YearDay DateTime::GetYearDay() { long dayCount; long daysFromJan1Year1; long extraDays; long fourHundredYearHunks; long fourYearHunks; long oneHundredYearHunks; long oneYearHunks; double secsOfDay; YearDay yd; daysFromJan1Year1 = ( long ) floor( ( GPSWeek * DaysInWeek ) + MJDJan61980 + ( secsOfWeek / SecondsInDay ) ) - MJDJan1Year1; fourHundredYearHunks = daysFromJan1Year1 / DaysIn400Years; oneHundredYearHunks = ( daysFromJan1Year1 - ( fourHundredYearHunks * DaysIn400Years ) ) / DaysIn100Years; fourYearHunks = ( daysFromJan1Year1 - ( fourHundredYearHunks * DaysIn400Years ) - ( oneHundredYearHunks * DaysIn100Years ) ) / DaysIn4Years; extraDays = ( daysFromJan1Year1 - ( fourHundredYearHunks * DaysIn400Years ) - ( oneHundredYearHunks * DaysIn100Years ) - ( fourYearHunks * DaysIn4Years ) ); // If the number of extra days is less than three years, the number // of one-year-hunks is the integer part of quotient of the extra days // divided by the number of days on a non leap year. // If the number of extra days falls anywhere in the fourth year the // one-year-hunks is set to 3. This is to prevent the last day of the // leap year (12/31) from causing the one-year-hunks from being 4, pushing // the computed date ahead one day and into the next year. oneYearHunks = ( extraDays < 1095 ) ? ( extraDays / DaysInNonLeapYear ) : 3; yd.year = 1 + fourHundredYearHunks * 400 + oneHundredYearHunks * 100 + fourYearHunks * 4 + oneYearHunks; yd.yday = ( daysFromJan1Year1 - ( fourHundredYearHunks * DaysIn400Years ) - ( oneHundredYearHunks * DaysIn100Years ) - ( fourYearHunks * DaysIn4Years ) - ( oneYearHunks * DaysInNonLeapYear ) + 1 ); dayCount = ( long ) ( secsOfWeek / SecondsInDay ); secsOfDay = secsOfWeek - ( SecondsInDay * dayCount ); yd.hour = ( long ) ( secsOfDay / SecondsInHour ); yd.min = ( long ) ( secsOfDay - ( yd.hour * SecondsInHour ) ) / SecondsInMin; yd.sec = secsOfDay - ( yd.hour * SecondsInHour ) - ( yd.min * SecondsInMin ) ; return yd; } YearMonthDay DateTime::GetYearMonthDay() { int done = 0; int i; YearMonthDay ymd; YearDay yd = this->GetYearDay(); ymd.year = yd.year; if ( ymd.year % 400 == 0 || ( ymd.year % 100 != 0 && ymd.year % 4 == 0 ) ) { // leap year for ( i = 0; i < 12 && !done; i++ ) { if ( yd.yday > Leap[i] && yd.yday <= Leap[i+1] ) { ymd.month = i+1; ymd.monthday = yd.yday - Leap[i]; done = 1; } } } else { // normal year for ( i = 0; i < 12 && !done; i++ ) { if ( yd.yday > Normal[i] && yd.yday <= Normal[i+1]) { ymd.month = i+1; ymd.monthday = yd.yday - Normal[i]; done = 1; } } } // end normal year. end if. ymd.hour = yd.hour; ymd.min = yd.min; ymd.sec = yd.sec; return ymd; } // Operators DateTime DateTime::operator + ( const double secs ) { DateTime DT; DT.GPSWeek = GPSWeek; DT.secsOfWeek = secsOfWeek + secs; DT.GPSWeek = ( long ) floor( GPSWeek + double( secsOfWeek + secs ) / SecondsInWeek ); DT.secsOfWeek = secsOfWeek + secs + ( GPSWeek - DT.GPSWeek ) * SecondsInWeek; return DT; } double DateTime::operator - ( const DateTime &DT2 ) { return ( ( double ) ( ( GPSWeek - DT2.GPSWeek ) * SecondsInWeek ) + ( secsOfWeek - DT2.secsOfWeek ) ); } int DateTime::operator == ( const DateTime &DT2 ) { return ( GPSWeek == DT2.GPSWeek && secsOfWeek == DT2.secsOfWeek ); } int DateTime::operator != ( const DateTime &DT2 ) { return ( GPSWeek != DT2.GPSWeek || secsOfWeek != DT2.secsOfWeek ); } int DateTime::operator >= ( const DateTime &DT2 ) { if ( GPSWeek > DT2.GPSWeek || GPSWeek == DT2.GPSWeek && secsOfWeek >= DT2.secsOfWeek ) { return 1; } return 0; } int DateTime::operator < ( const DateTime &DT2 ) { if ( GPSWeek < DT2.GPSWeek || GPSWeek == DT2.GPSWeek && secsOfWeek < DT2.secsOfWeek ) { return 1; } return 0; }