time_conversion.c

Go to the documentation of this file.
00001 /**
00002 \file    time_conversion.c
00003 \brief   GNSS core 'c' function library: converting time information.
00004 \author  Glenn D. MacGougan (GDM)
00005 \date    2007-11-29
00006 \since   2005-07-30
00007 
00008 \b REFERENCES \n
00009 - Hofmann-Wellenhof, B., H. Lichtenegger, and J. Collins (1994). GPS Theory and 
00010   Practice, Third, revised edition. Springer-Verlag, Wien New York. pp. 38-42 \n
00011 - http://aa.usno.navy.mil/data/docs/JulianDate.html - Julian Date Converter \n
00012 - http://aa.usno.navy.mil/faq/docs/UT.html \n
00013 - http://wwwmacho.mcmaster.ca/JAVA/JD.html \n
00014 - Raquet, J. F. (2002), GPS Receiver Design Lecture Notes. Geomatics Engineering, 
00015   University of Calgary Graduate Course. \n
00016 
00017 \b "LICENSE INFORMATION" \n
00018 Copyright (c) 2007, refer to 'author' doxygen tags \n
00019 All rights reserved. \n
00020 
00021 Redistribution and use in source and binary forms, with or without
00022 modification, are permitted provided the following conditions are met: \n
00023 
00024 - Redistributions of source code must retain te above copyright
00025   notice, this list of conditions and the following disclaimer. \n
00026 - Redistributions in binary form must reproduce the above copyright
00027   notice, this list of conditions and the following disclaimer in the
00028   documentation and/or other materials provided with the distribution. \n
00029 - The name(s) of the contributor(s) may not be used to endorse or promote 
00030   products derived from this software without specific prior written 
00031   permission. \n
00032 
00033 THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS 
00034 OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
00035 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00036 DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
00037 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00038 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
00039 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
00040 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
00041 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 
00042 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
00043 SUCH DAMAGE.
00044 */
00045 
00046 #include <sys/timeb.h>
00047 #include <time.h>
00048 #include <math.h> // for fmod()
00049 #include "gnss_error.h"
00050 #include "time_conversion.h"
00051 #include "constants.h"
00052 
00053 #ifndef WIN32
00054   #define _CRT_SECURE_NO_DEPRECATE  
00055 #endif
00056 
00057 #ifdef WIN32
00058   #include <windows.h>
00059 #endif
00060 
00061 
00062 #define TIMECONV_JULIAN_DATE_START_OF_GPS_TIME (2444244.5)  // [days]
00063 #define TIMECONV_JULIAN_DATE_START_OF_PC_TIME  (2440587.5)  // [days]
00064 #define TIMECONV_DAYS_IN_JAN 31
00065 #define TIMECONV_DAYS_IN_MAR 31
00066 #define TIMECONV_DAYS_IN_APR 30
00067 #define TIMECONV_DAYS_IN_MAY 31
00068 #define TIMECONV_DAYS_IN_JUN 30
00069 #define TIMECONV_DAYS_IN_JUL 31
00070 #define TIMECONV_DAYS_IN_AUG 31
00071 #define TIMECONV_DAYS_IN_SEP 30
00072 #define TIMECONV_DAYS_IN_OCT 31
00073 #define TIMECONV_DAYS_IN_NOV 30
00074 #define TIMECONV_DAYS_IN_DEC 31
00075 
00076 
00077 // A static function to check if the utc input values are valid.
00078 // \return TRUE if valid, FALSE otherwise.
00079 static BOOL TIMECONV_IsUTCTimeValid( 
00080  const unsigned short     utc_year,      //!< Universal Time Coordinated  [year]
00081  const unsigned char      utc_month,     //!< Universal Time Coordinated  [1-12 months] 
00082  const unsigned char      utc_day,       //!< Universal Time Coordinated  [1-31 days]
00083  const unsigned char      utc_hour,      //!< Universal Time Coordinated  [hours]
00084  const unsigned char      utc_minute,    //!< Universal Time Coordinated  [minutes]
00085  const float              utc_seconds    //!< Universal Time Coordinated  [s]
00086  );
00087  
00088 
00089 BOOL TIMECONV_IsUTCTimeValid( 
00090  const unsigned short     utc_year,      //!< Universal Time Coordinated  [year]
00091  const unsigned char      utc_month,     //!< Universal Time Coordinated  [1-12 months] 
00092  const unsigned char      utc_day,       //!< Universal Time Coordinated  [1-31 days]
00093  const unsigned char      utc_hour,      //!< Universal Time Coordinated  [hours]
00094  const unsigned char      utc_minute,    //!< Universal Time Coordinated  [minutes]
00095  const float              utc_seconds    //!< Universal Time Coordinated  [s]
00096  )
00097 {
00098   unsigned char daysInMonth;
00099   BOOL result;
00100   if( utc_month == 0 || utc_month > 12 )
00101   {
00102     GNSS_ERROR_MSG( "if( utc_month == 0 || utc_month > 12 )" );
00103     return FALSE;
00104   }
00105   result = TIMECONV_GetNumberOfDaysInMonth( utc_year, utc_month, &daysInMonth );
00106   if( result == FALSE )
00107   {
00108     GNSS_ERROR_MSG( "TIMECONV_GetNumberOfDaysInMonth returned FALSE." );       
00109     return FALSE;
00110   }
00111   if( utc_day == 0 || utc_day > daysInMonth )
00112   {
00113     GNSS_ERROR_MSG( "if( utc_day == 0 || utc_day > daysInMonth )" );
00114     return FALSE;
00115   }
00116   if( utc_hour > 23 )
00117   {
00118     GNSS_ERROR_MSG( "if( utc_hour > 23 )" );
00119     return FALSE;
00120   }
00121   if( utc_minute > 59 )
00122   {
00123     GNSS_ERROR_MSG( "if( utc_minute > 59 )" );
00124     return FALSE;
00125   }
00126   if( utc_seconds > 60 )
00127   {
00128     GNSS_ERROR_MSG( "if( utc_seconds > 60 )" );
00129     return FALSE;
00130   }
00131 
00132   return TRUE;
00133 }
00134 
00135 
00136 BOOL TIMECONV_GetSystemTime(
00137   unsigned short*     utc_year,     //!< Universal Time Coordinated    [year]
00138   unsigned char*      utc_month,    //!< Universal Time Coordinated    [1-12 months] 
00139   unsigned char*      utc_day,      //!< Universal Time Coordinated    [1-31 days]
00140   unsigned char*      utc_hour,     //!< Universal Time Coordinated    [hours]
00141   unsigned char*      utc_minute,   //!< Universal Time Coordinated    [minutes]
00142   float*              utc_seconds,  //!< Universal Time Coordinated    [s]
00143   unsigned char*      utc_offset,   //!< Integer seconds that GPS is ahead of UTC time, always positive             [s], obtained from a look up table
00144   double*             julian_date,  //!< Number of days since noon Universal Time Jan 1, 4713 BCE (Julian calendar) [days]
00145   unsigned short*     gps_week,     //!< GPS week (0-1024+)            [week]
00146   double*             gps_tow       //!< GPS time of week (0-604800.0) [s]
00147   )
00148 {
00149   BOOL result;
00150 
00151 #ifdef WIN32
00152   struct _timeb timebuffer; // found in <sys/timeb.h>   
00153 #else
00154   struct timeb timebuffer;
00155 #endif
00156   double timebuffer_time_in_days;
00157   double timebuffer_time_in_seconds;
00158   //char *timeline; // for debugging
00159 
00160 #ifndef _CRT_SECURE_NO_DEPRECATE
00161   if( _ftime_s( &timebuffer ) != 0 )
00162   {
00163     GNSS_ERROR_MSG( "if( _ftime_s( &timebuffer ) != 0 )" );
00164     return FALSE;
00165   }
00166 #else
00167 
00168 #ifdef WIN32
00169   _ftime( &timebuffer );
00170 #else
00171   ftime( &timebuffer );
00172 #endif 
00173 
00174 #endif
00175   //timeline = ctime( & ( timebuffer.time ) ); // for debugging
00176   //printf( "%s\n", timeline ); // for debugging
00177 
00178   timebuffer_time_in_seconds = timebuffer.time + timebuffer.millitm / 1000.0; // [s] with ms resolution
00179 
00180   // timebuffer_time_in_seconds is the time in seconds since midnight (00:00:00), January 1, 1970, 
00181   // coordinated universal time (UTC). Julian date for (00:00:00), January 1, 1970 is: 2440587.5 [days]
00182 
00183   // convert timebuffer.time from seconds to days
00184   timebuffer_time_in_days = timebuffer_time_in_seconds/SECONDS_IN_DAY; // days since julian date 2440587.5000000 [days]
00185 
00186   // convert to julian date
00187   *julian_date = TIMECONV_JULIAN_DATE_START_OF_PC_TIME + timebuffer_time_in_days;
00188 
00189   result = TIMECONV_DetermineUTCOffset( *julian_date, utc_offset );
00190   if( result == FALSE )
00191   {
00192     GNSS_ERROR_MSG( "TIMECONV_DetermineUTCOffset returned FALSE." );
00193     return FALSE;
00194   }
00195 
00196   result = TIMECONV_GetGPSTimeFromJulianDate(
00197     *julian_date,
00198     *utc_offset,
00199     gps_week,
00200     gps_tow );
00201   if( result == FALSE )
00202   {
00203     GNSS_ERROR_MSG( "TIMECONV_GetGPSTimeFromJulianDate returned FALSE." );
00204     return FALSE;
00205   }
00206 
00207   result = TIMECONV_GetUTCTimeFromJulianDate(
00208     *julian_date,
00209     utc_year,
00210     utc_month,
00211     utc_day,
00212     utc_hour,
00213     utc_minute,
00214     utc_seconds );
00215   if( result == FALSE )
00216   {
00217     GNSS_ERROR_MSG( "TIMECONV_GetUTCTimeFromJulianDate" );
00218     return FALSE;
00219   }
00220 
00221   return TRUE;
00222 }
00223 
00224 
00225 #ifdef WIN32
00226 BOOL TIMECONV_SetSystemTime(
00227   const unsigned short  utc_year,     //!< Universal Time Coordinated    [year]
00228   const unsigned char   utc_month,    //!< Universal Time Coordinated    [1-12 months] 
00229   const unsigned char   utc_day,      //!< Universal Time Coordinated    [1-31 days]
00230   const unsigned char   utc_hour,     //!< Universal Time Coordinated    [hours]
00231   const unsigned char   utc_minute,   //!< Universal Time Coordinated    [minutes]
00232   const float           utc_seconds   //!< Universal Time Coordinated    [s]
00233   )
00234 {
00235   BOOL result;
00236   SYSTEMTIME t;
00237   double julian_date = 0;
00238   unsigned char day_of_week = 0;
00239 
00240   result = TIMECONV_GetJulianDateFromUTCTime(
00241     utc_year,
00242     utc_month,
00243     utc_day,
00244     utc_hour,
00245     utc_minute,
00246     utc_seconds,
00247     &julian_date
00248     );
00249   if( !result )
00250   {
00251     GNSS_ERROR_MSG( "TIMECONV_GetJulianDateFromUTCTime returned FALSE.");
00252     return FALSE;
00253   }
00254 
00255   result = TIMECONV_GetDayOfWeekFromJulianDate( julian_date, &day_of_week );
00256   if( !result )
00257   {
00258     GNSS_ERROR_MSG( "TIMECONV_GetDayOfWeekFromJulianDate returned FALSE.");
00259     return FALSE;
00260   }
00261   
00262   t.wDayOfWeek = day_of_week;
00263   t.wYear = utc_year;
00264   t.wMonth = utc_month;
00265   t.wDay = utc_day;
00266   t.wHour = utc_hour;
00267   t.wMinute = utc_minute;
00268   t.wSecond = (WORD)(floor(utc_seconds));
00269   t.wMilliseconds = (WORD)((utc_seconds - t.wSecond)*1000);
00270 
00271   // Set the PC system time.
00272   result = SetSystemTime( &t );
00273   
00274   return result;
00275 }
00276 #endif
00277 
00278 
00279 BOOL TIMECONV_GetDayOfWeekFromJulianDate(
00280   const double julian_date,   //!< Number of days since noon Universal Time Jan 1, 4713 BCE (Julian calendar) [days]
00281   unsigned char *day_of_week  //!< 0-Sunday, 1-Monday, 2-Tuesday, 3-Wednesday, 4-Thursday, 5-Friday, 6-Saturday [].
00282   )
00283 {
00284   // "If the Julian date of noon is applied to the entire midnight-to-midnight civil 
00285   // day centered on that noon,[5] rounding Julian dates (fractional days) for the 
00286   // twelve hours before noon up while rounding those after noon down, then the remainder 
00287   // upon division by 7 represents the day of the week, with 0 representing Monday, 
00288   // 1 representing Tuesday, and so forth. Now at 17:48, Wednesday December 3 2008 (UTC) 
00289   // the nearest noon JDN is 2454804 yielding a remainder of 2." (http://en.wikipedia.org/wiki/Julian_day, 2008-12-03)
00290   int dow = 0;
00291   int jd = 0;
00292 
00293   if( julian_date - floor(julian_date) > 0.5 )
00294   {
00295     jd = (int)floor(julian_date+0.5);
00296   }
00297   else
00298   {
00299     jd = (int)floor(julian_date);
00300   }
00301   dow = jd%7; // 0 is monday, 1 is tuesday, etc
00302 
00303   switch( dow )
00304   {
00305     case 0: *day_of_week = 1; break;
00306     case 1: *day_of_week = 2; break;
00307     case 2: *day_of_week = 3; break;
00308     case 3: *day_of_week = 4; break;
00309     case 4: *day_of_week = 5; break;
00310     case 5: *day_of_week = 6; break;
00311     case 6: *day_of_week = 0; break;
00312     default: return FALSE; break;
00313   }
00314   
00315   return TRUE;
00316 }
00317 
00318 
00319 BOOL TIMECONV_GetJulianDateFromGPSTime(
00320   const unsigned short    gps_week,      //!< GPS week (0-1024+)             [week]
00321   const double            gps_tow,       //!< GPS time of week (0-604800.0)  [s]
00322   const unsigned char     utc_offset,    //!< Integer seconds that GPS is ahead of UTC time, always positive [s]
00323   double*                 julian_date    //!< Number of days since noon Universal Time Jan 1, 4713 BCE (Julian calendar) [days]
00324   )
00325 {   
00326   if( gps_tow < 0.0  || gps_tow > 604800.0 )
00327   {
00328     GNSS_ERROR_MSG( "if( gps_tow < 0.0  || gps_tow > 604800.0 )" );
00329     return FALSE;  
00330   }
00331 
00332   // GPS time is ahead of UTC time and Julian time by the UTC offset
00333   *julian_date = ((double)gps_week + (gps_tow-(double)utc_offset)/604800.0)*7.0 + TIMECONV_JULIAN_DATE_START_OF_GPS_TIME;  
00334   return TRUE;
00335 }
00336 
00337 
00338 BOOL TIMECONV_GetJulianDateFromUTCTime(
00339  const unsigned short     utc_year,      //!< Universal Time Coordinated  [year]
00340  const unsigned char      utc_month,     //!< Universal Time Coordinated  [1-12 months] 
00341  const unsigned char      utc_day,       //!< Universal Time Coordinated  [1-31 days]
00342  const unsigned char      utc_hour,      //!< Universal Time Coordinated  [hours]
00343  const unsigned char      utc_minute,    //!< Universal Time Coordinated  [minutes]
00344  const float              utc_seconds,   //!< Universal Time Coordinated  [s]
00345  double*                  julian_date    //!< Number of days since noon Universal Time Jan 1, 4713 BCE (Julian calendar) [days]
00346  )
00347 {   
00348   double y; // temp for year
00349   double m; // temp for month
00350   BOOL result;
00351 
00352   // Check the input.
00353   result = TIMECONV_IsUTCTimeValid( utc_year, utc_month, utc_day, utc_hour, utc_minute, utc_seconds );
00354   if( result == FALSE )
00355   {
00356     GNSS_ERROR_MSG( "TIMECONV_IsUTCTimeValid returned FALSE." );
00357     return FALSE;
00358   }
00359 
00360   if( utc_month <= 2 )
00361   {
00362     y = utc_year - 1;
00363     m = utc_month + 12;
00364   }
00365   else 
00366   {
00367     y = utc_year;
00368     m = utc_month;
00369   }
00370 
00371   *julian_date = (int)(365.25*y) + (int)(30.6001*(m+1.0)) + utc_day + utc_hour/24.0 + utc_minute/1440.0 + utc_seconds/86400.0 + 1720981.5;
00372   return TRUE;
00373 }
00374 
00375 
00376 
00377 BOOL TIMECONV_GetGPSTimeFromJulianDate(
00378   const double            julian_date, //!< Number of days since noon Universal Time Jan 1, 4713 BCE (Julian calendar) [days]
00379   const unsigned char     utc_offset,  //!< Integer seconds that GPS is ahead of UTC time, always positive [s]
00380   unsigned short*         gps_week,    //!< GPS week (0-1024+)            [week]
00381   double*                 gps_tow      //!< GPS time of week [s]
00382   )
00383 {
00384   // Check the input.
00385   if( julian_date < 0.0 )
00386   {
00387     GNSS_ERROR_MSG( "if( julian_date < 0.0 )" );
00388     return FALSE;
00389   }
00390 
00391   *gps_week = (unsigned short)((julian_date - TIMECONV_JULIAN_DATE_START_OF_GPS_TIME)/7.0); //
00392 
00393   *gps_tow   = (julian_date - TIMECONV_JULIAN_DATE_START_OF_GPS_TIME)*SECONDS_IN_DAY; // seconds since start of gps time [s]
00394   *gps_tow  -= (*gps_week)*SECONDS_IN_WEEK;                                  // seconds into the current week [s] 
00395 
00396   // however, GPS time is ahead of utc time by the UTC offset (and thus the Julian date as well)
00397   *gps_tow += utc_offset;
00398   if( *gps_tow > SECONDS_IN_WEEK )
00399   {
00400     *gps_tow  -= SECONDS_IN_WEEK;
00401     *gps_week += 1;
00402   }
00403   return TRUE;
00404 }
00405 
00406 
00407 BOOL TIMECONV_GetUTCTimeFromJulianDate(
00408   const double        julian_date,  //!< Number of days since noon Universal Time Jan 1, 4713 BCE (Julian calendar) [days]
00409   unsigned short*     utc_year,     //!< Universal Time Coordinated    [year]
00410   unsigned char*      utc_month,    //!< Universal Time Coordinated    [1-12 months] 
00411   unsigned char*      utc_day,      //!< Universal Time Coordinated    [1-31 days]
00412   unsigned char*      utc_hour,     //!< Universal Time Coordinated    [hours]
00413   unsigned char*      utc_minute,   //!< Universal Time Coordinated    [minutes]
00414   float*              utc_seconds   //!< Universal Time Coordinated    [s]
00415   )
00416 {
00417   int a, b, c, d, e; // temporary values
00418   
00419   unsigned short year;  
00420   unsigned char month;
00421   unsigned char day;
00422   unsigned char hour;
00423   unsigned char minute;        
00424   unsigned char days_in_month = 0;  
00425   double td; // temporary double
00426   double seconds;
00427   BOOL result;
00428 
00429   // Check the input.
00430   if( julian_date < 0.0 )
00431   {
00432     GNSS_ERROR_MSG( "if( julian_date < 0.0 )" );
00433     return FALSE;
00434   }
00435   
00436   a = (int)(julian_date+0.5);
00437   b = a + 1537;
00438   c = (int)( ((double)b-122.1)/365.25 );
00439   d = (int)(365.25*c);
00440   e = (int)( ((double)(b-d))/30.6001 );
00441   
00442   td      = b - d - (int)(30.6001*e) + fmod( julian_date+0.5, 1.0 );   // [days]
00443   day     = (unsigned char)td;   
00444   td     -= day;
00445   td     *= 24.0;        // [hours]
00446   hour    = (unsigned char)td;
00447   td     -= hour;
00448   td     *= 60.0;        // [minutes]
00449   minute  = (unsigned char)td;
00450   td     -= minute;
00451   td     *= 60.0;        // [s]
00452   seconds = td;
00453   month   = (unsigned char)(e - 1 - 12*(int)(e/14));
00454   year    = (unsigned short)(c - 4715 - (int)( (7.0+(double)month) / 10.0 ));
00455   
00456   // check for rollover issues
00457   if( seconds >= 60.0 )
00458   {
00459     seconds -= 60.0;
00460     minute++;
00461     if( minute >= 60 )
00462     {
00463       minute -= 60;
00464       hour++;
00465       if( hour >= 24 )
00466       {
00467         hour -= 24;
00468         day++;
00469         
00470         result = TIMECONV_GetNumberOfDaysInMonth( year, month, &days_in_month );
00471         if( result == FALSE )
00472         {
00473           GNSS_ERROR_MSG( "TIMECONV_GetNumberOfDaysInMonth returned FALSE." );
00474           return FALSE;
00475         }
00476         
00477         if( day > days_in_month )
00478         {
00479           day = 1;
00480           month++;
00481           if( month > 12 )
00482           {
00483             month = 1;
00484             year++;
00485           }
00486         }
00487       }
00488     }
00489   }   
00490   
00491   *utc_year       = year;
00492   *utc_month      = month;
00493   *utc_day        = day;
00494   *utc_hour       = hour;
00495   *utc_minute     = minute;
00496   *utc_seconds    = (float)seconds;   
00497 
00498   return TRUE;
00499 }
00500 
00501 BOOL TIMECONV_GetGPSTimeFromUTCTime(
00502   unsigned short     utc_year,     //!< Universal Time Coordinated    [year]
00503   unsigned char      utc_month,    //!< Universal Time Coordinated    [1-12 months] 
00504   unsigned char      utc_day,      //!< Universal Time Coordinated    [1-31 days]
00505   unsigned char      utc_hour,     //!< Universal Time Coordinated    [hours]
00506   unsigned char      utc_minute,   //!< Universal Time Coordinated    [minutes]
00507   float              utc_seconds,  //!< Universal Time Coordinated    [s]
00508   unsigned short*    gps_week,     //!< GPS week (0-1024+)            [week]
00509   double*            gps_tow       //!< GPS time of week (0-604800.0) [s]
00510   )
00511 {
00512   double julian_date=0.0;
00513   unsigned char utc_offset=0;
00514   BOOL result;
00515 
00516   // Check the input.
00517   result = TIMECONV_IsUTCTimeValid( utc_year, utc_month, utc_day, utc_hour, utc_minute, utc_seconds );
00518   if( result == FALSE )
00519   {
00520     GNSS_ERROR_MSG( "TIMECONV_IsUTCTimeValid returned FALSE." );
00521     return FALSE;
00522   }
00523 
00524   result = TIMECONV_GetJulianDateFromUTCTime(
00525     utc_year,
00526     utc_month,
00527     utc_day,
00528     utc_hour,
00529     utc_minute,
00530     utc_seconds,
00531     &julian_date );
00532   if( result == FALSE )
00533   {
00534     GNSS_ERROR_MSG( "TIMECONV_GetJulianDateFromUTCTime returned FALSE." );
00535     return FALSE;
00536   }
00537 
00538   result = TIMECONV_DetermineUTCOffset( julian_date, &utc_offset );
00539   if( result == FALSE )
00540   {
00541     GNSS_ERROR_MSG( "TIMECONV_DetermineUTCOffset returned FALSE." );
00542     return FALSE;
00543   }
00544 
00545   result = TIMECONV_GetGPSTimeFromJulianDate(
00546     julian_date,
00547     utc_offset,
00548     gps_week,
00549     gps_tow );
00550   if( result == FALSE )
00551   {
00552     GNSS_ERROR_MSG( "TIMECONV_GetGPSTimeFromJulianDate returned FALSE." );
00553     return FALSE;
00554   }
00555 
00556   return TRUE;
00557 }
00558 
00559 
00560 
00561 BOOL TIMECONV_GetGPSTimeFromRinexTime(
00562   unsigned short     utc_year,     //!< Universal Time Coordinated    [year]
00563   unsigned char      utc_month,    //!< Universal Time Coordinated    [1-12 months] 
00564   unsigned char      utc_day,      //!< Universal Time Coordinated    [1-31 days]
00565   unsigned char      utc_hour,     //!< Universal Time Coordinated    [hours]
00566   unsigned char      utc_minute,   //!< Universal Time Coordinated    [minutes]
00567   float              utc_seconds,  //!< Universal Time Coordinated    [s]
00568   unsigned short*    gps_week,     //!< GPS week (0-1024+)            [week]
00569   double*            gps_tow       //!< GPS time of week (0-604800.0) [s]
00570   )
00571 {
00572   double julian_date=0.0;
00573   unsigned char utc_offset=0;
00574   BOOL result;
00575 
00576   // Check the input.
00577   result = TIMECONV_IsUTCTimeValid( utc_year, utc_month, utc_day, utc_hour, utc_minute, utc_seconds );
00578   if( result == FALSE )
00579   {
00580     GNSS_ERROR_MSG( "TIMECONV_IsUTCTimeValid returned FALSE." );
00581     return FALSE;
00582   }
00583 
00584   result = TIMECONV_GetJulianDateFromUTCTime(
00585     utc_year,
00586     utc_month,
00587     utc_day,
00588     utc_hour,
00589     utc_minute,
00590     utc_seconds,
00591     &julian_date );
00592   if( result == FALSE )
00593   {
00594     GNSS_ERROR_MSG( "TIMECONV_GetJulianDateFromUTCTime returned FALSE." );
00595     return FALSE;
00596   }
00597 
00598   result = TIMECONV_GetGPSTimeFromJulianDate(
00599     julian_date,
00600     utc_offset,
00601     gps_week,
00602     gps_tow );
00603   if( result == FALSE )
00604   {
00605     GNSS_ERROR_MSG( "TIMECONV_GetGPSTimeFromJulianDate returned FALSE." );
00606     return FALSE;
00607   }
00608 
00609   return TRUE;
00610 }
00611 
00612 
00613 
00614 BOOL TIMECONV_GetUTCTimeFromGPSTime(
00615   unsigned short     gps_week,     //!< GPS week (0-1024+)            [week]
00616   double             gps_tow,      //!< GPS time of week (0-604800.0) [s]
00617   unsigned short*    utc_year,     //!< Universal Time Coordinated    [year]
00618   unsigned char*     utc_month,    //!< Universal Time Coordinated    [1-12 months] 
00619   unsigned char*     utc_day,      //!< Universal Time Coordinated    [1-31 days]
00620   unsigned char*     utc_hour,     //!< Universal Time Coordinated    [hours]
00621   unsigned char*     utc_minute,   //!< Universal Time Coordinated    [minutes]
00622   float*             utc_seconds   //!< Universal Time Coordinated    [s]
00623   )
00624 {
00625   double julian_date = 0.0; 
00626   unsigned char utc_offset = 0;
00627   int i;
00628   BOOL result;
00629 
00630   if( gps_tow < 0.0 || gps_tow > 604800.0 )
00631   {
00632     GNSS_ERROR_MSG( "if( gps_tow < 0.0 || gps_tow > 604800.0 )" );
00633     return FALSE;  
00634   }
00635 
00636   // iterate to get the right utc offset
00637   for( i = 0; i < 4; i++ )
00638   {
00639     result = TIMECONV_GetJulianDateFromGPSTime(
00640       gps_week,
00641       gps_tow,
00642       utc_offset,
00643       &julian_date );
00644     if( result == FALSE )
00645     {
00646       GNSS_ERROR_MSG( "TIMECONV_GetJulianDateFromGPSTime returned FALSE." );
00647       return FALSE;
00648     }
00649 
00650     result = TIMECONV_DetermineUTCOffset( julian_date, &utc_offset );
00651     if( result == FALSE )
00652     {
00653       GNSS_ERROR_MSG( "TIMECONV_DetermineUTCOffset returned FALSE." );
00654       return FALSE;
00655     }
00656   }
00657 
00658   result = TIMECONV_GetUTCTimeFromJulianDate(
00659     julian_date,
00660     utc_year,
00661     utc_month,
00662     utc_day,
00663     utc_hour,
00664     utc_minute,
00665     utc_seconds );
00666   if( result == FALSE )
00667   {
00668     GNSS_ERROR_MSG( "TIMECONV_GetUTCTimeFromJulianDate returned FALSE." );
00669     return FALSE;
00670   }
00671 
00672   return TRUE;
00673 }
00674 
00675 
00676 
00677 BOOL TIMECONV_DetermineUTCOffset(
00678   double julian_date,       //!< Number of days since noon Universal Time Jan 1, 4713 BCE (Julian calendar) [days]
00679   unsigned char* utc_offset //!< Integer seconds that GPS is ahead of UTC time, always positive             [s], obtained from a look up table
00680   )
00681 {
00682   if( julian_date < 0.0 )
00683   {
00684     GNSS_ERROR_MSG( "if( julian_date < 0.0 )" );
00685     return FALSE;
00686   }
00687 
00688   if(      julian_date < 2444786.5000 ) *utc_offset = 0;
00689   else if( julian_date < 2445151.5000 ) *utc_offset = 1;
00690   else if( julian_date < 2445516.5000 ) *utc_offset = 2;
00691   else if( julian_date < 2446247.5000 ) *utc_offset = 3;
00692   else if( julian_date < 2447161.5000 ) *utc_offset = 4;
00693   else if( julian_date < 2447892.5000 ) *utc_offset = 5;
00694   else if( julian_date < 2448257.5000 ) *utc_offset = 6;
00695   else if( julian_date < 2448804.5000 ) *utc_offset = 7;
00696   else if( julian_date < 2449169.5000 ) *utc_offset = 8;
00697   else if( julian_date < 2449534.5000 ) *utc_offset = 9;
00698   else if( julian_date < 2450083.5000 ) *utc_offset = 10;
00699   else if( julian_date < 2450630.5000 ) *utc_offset = 11;
00700   else if( julian_date < 2451179.5000 ) *utc_offset = 12;  
00701   else if( julian_date < 2453736.5000 ) *utc_offset = 13;  
00702   else                                  *utc_offset = 14;
00703 
00704   return TRUE;
00705 }  
00706 
00707 
00708   
00709 
00710 BOOL TIMECONV_GetNumberOfDaysInMonth(
00711   const unsigned short year,        //!< Universal Time Coordinated    [year]
00712   const unsigned char month,        //!< Universal Time Coordinated    [1-12 months] 
00713   unsigned char* days_in_month      //!< Days in the specified month   [1-28|29|30|31 days]
00714   )
00715 {
00716   BOOL is_a_leapyear;
00717   unsigned char utmp = 0;
00718   
00719   is_a_leapyear = TIMECONV_IsALeapYear( year );
00720   
00721   switch(month)
00722   {
00723   case  1: utmp = TIMECONV_DAYS_IN_JAN; break;
00724   case  2: if( is_a_leapyear ){ utmp = 29; }else{ utmp = 28; }break;    
00725   case  3: utmp = TIMECONV_DAYS_IN_MAR; break;
00726   case  4: utmp = TIMECONV_DAYS_IN_APR; break;
00727   case  5: utmp = TIMECONV_DAYS_IN_MAY; break;
00728   case  6: utmp = TIMECONV_DAYS_IN_JUN; break;
00729   case  7: utmp = TIMECONV_DAYS_IN_JUL; break;
00730   case  8: utmp = TIMECONV_DAYS_IN_AUG; break;
00731   case  9: utmp = TIMECONV_DAYS_IN_SEP; break;
00732   case 10: utmp = TIMECONV_DAYS_IN_OCT; break;
00733   case 11: utmp = TIMECONV_DAYS_IN_NOV; break;
00734   case 12: utmp = TIMECONV_DAYS_IN_DEC; break;
00735   default: 
00736     { 
00737       GNSS_ERROR_MSG( "unexpected default case." ); 
00738       return FALSE; 
00739       break;    
00740     }
00741   }
00742   
00743   *days_in_month = utmp;
00744 
00745   return TRUE;
00746 }
00747 
00748   
00749 
00750 
00751 BOOL TIMECONV_IsALeapYear( const unsigned short year )
00752 {
00753   BOOL is_a_leap_year = FALSE;
00754 
00755   if( (year%4) == 0 )
00756   {
00757     is_a_leap_year = TRUE;
00758     if( (year%100) == 0 )
00759     {
00760       if( (year%400) == 0 )
00761       {
00762         is_a_leap_year = TRUE;
00763       }
00764       else
00765       {
00766         is_a_leap_year = FALSE;
00767       }
00768     }
00769   }
00770   if( is_a_leap_year )
00771   {
00772     return TRUE;
00773   }
00774   else
00775   {    
00776     return FALSE;
00777   }
00778 }
00779 
00780 
00781 
00782 
00783 
00784 BOOL TIMECONV_GetDayOfYear(
00785   const unsigned short utc_year,    // Universal Time Coordinated           [year]
00786   const unsigned char  utc_month,   // Universal Time Coordinated           [1-12 months] 
00787   const unsigned char  utc_day,     // Universal Time Coordinated           [1-31 days]
00788   unsigned short*      dayofyear    // number of days into the year (1-366) [days]
00789   )
00790 {
00791   unsigned char days_in_feb = 0;
00792   BOOL result;
00793   result = TIMECONV_GetNumberOfDaysInMonth( utc_year, 2, &days_in_feb );
00794   if( result == FALSE )
00795   {
00796     GNSS_ERROR_MSG( "TIMECONV_GetNumberOfDaysInMonth returned FALSE." );
00797     return FALSE;
00798   }
00799 
00800   switch( utc_month )
00801   {
00802   case  1: *dayofyear = utc_day; break;
00803   case  2: *dayofyear = (unsigned short)(TIMECONV_DAYS_IN_JAN               + utc_day); break;
00804   case  3: *dayofyear = (unsigned short)(TIMECONV_DAYS_IN_JAN + days_in_feb + utc_day); break;
00805   case  4: *dayofyear = (unsigned short)(62          + days_in_feb + utc_day); break;
00806   case  5: *dayofyear = (unsigned short)(92          + days_in_feb + utc_day); break;
00807   case  6: *dayofyear = (unsigned short)(123         + days_in_feb + utc_day); break;
00808   case  7: *dayofyear = (unsigned short)(153         + days_in_feb + utc_day); break;
00809   case  8: *dayofyear = (unsigned short)(184         + days_in_feb + utc_day); break;
00810   case  9: *dayofyear = (unsigned short)(215         + days_in_feb + utc_day); break;
00811   case 10: *dayofyear = (unsigned short)(245         + days_in_feb + utc_day); break;
00812   case 11: *dayofyear = (unsigned short)(276         + days_in_feb + utc_day); break;
00813   case 12: *dayofyear = (unsigned short)(306         + days_in_feb + utc_day); break;
00814   default: 
00815     {
00816       GNSS_ERROR_MSG( "unexpected default case." );
00817       return FALSE; 
00818       break;
00819     }
00820   }
00821 
00822   return TRUE;
00823 }
00824 
00825 
00826 BOOL TIMECONV_GetGPSTimeFromYearAndDayOfYear(
00827  const unsigned short year,      // The year [year]
00828  const unsigned short dayofyear, // The number of days into the year (1-366) [days]
00829  unsigned short*      gps_week,  //!< GPS week (0-1024+)            [week]
00830  double*              gps_tow    //!< GPS time of week (0-604800.0) [s]
00831  )
00832 {
00833   BOOL result;
00834   double julian_date = 0;
00835 
00836   if( gps_week == NULL )
00837   {
00838     GNSS_ERROR_MSG( "if( gps_week == NULL )" );
00839     return FALSE;
00840   }
00841   if( gps_tow == NULL )
00842   {
00843     GNSS_ERROR_MSG( "if( gps_tow == NULL )" );
00844     return FALSE;
00845   }
00846   if( dayofyear > 366 )
00847   {
00848     GNSS_ERROR_MSG( "if( dayofyear > 366 )" );
00849     return FALSE;
00850   }
00851 
00852   result = TIMECONV_GetJulianDateFromUTCTime(
00853     year,
00854     1,
00855     1,
00856     0,
00857     0,
00858     0,
00859     &julian_date 
00860     );
00861   if( result == FALSE )
00862   {
00863     GNSS_ERROR_MSG( "TIMECONV_GetJulianDateFromUTCTime returned FALSE." );
00864     return FALSE;
00865   }
00866 
00867   julian_date += dayofyear - 1; // at the start of the day so -1.
00868 
00869   result = TIMECONV_GetGPSTimeFromJulianDate(
00870     julian_date,
00871     0,
00872     gps_week,
00873     gps_tow );
00874   if( result == FALSE )
00875   {
00876     GNSS_ERROR_MSG( "TIMECONV_GetGPSTimeFromJulianDate returned FALSE." );
00877     return FALSE;
00878   }
00879 
00880   return TRUE;
00881 }
SourceForge.net Logo