LCOV - code coverage report
Current view: top level - source/sys - timeUtils.cpp (source / functions) Coverage Total Hit
Test: mxlib Lines: 100.0 % 140 140
Test Date: 2026-08-30 22:23:37 Functions: 100.0 % 24 24

            Line data    Source code
       1              : /** \file timeUtils.cpp
       2              :  * \brief Definitions for utilities for working with time
       3              :  *
       4              :  * \author Jared R. Males (jaredmales@gmail.com)
       5              :  *
       6              :  * \ingroup utils_files
       7              :  *
       8              :  */
       9              : 
      10              : //***********************************************************************//
      11              : // Copyright 2020 Jared R. Males (jaredmales@gmail.com)
      12              : //
      13              : // This file is part of mxlib.
      14              : //
      15              : // mxlib is free software: you can redistribute it and/or modify
      16              : // it under the terms of the GNU General Public License as published by
      17              : // the Free Software Foundation, either version 3 of the License, or
      18              : // (at your option) any later version.
      19              : //
      20              : // mxlib is distributed in the hope that it will be useful,
      21              : // but WITHOUT ANY WARRANTY; without even the implied warranty of
      22              : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      23              : // GNU General Public License for more details.
      24              : //
      25              : // You should have received a copy of the GNU General Public License
      26              : // along with mxlib.  If not, see <http://www.gnu.org/licenses/>.
      27              : //***********************************************************************//
      28              : 
      29              : #include "sys/timeUtils.hpp"
      30              : 
      31              : namespace mx
      32              : {
      33              : namespace sys
      34              : {
      35              : 
      36              : namespace timeUtilsDetail
      37              : {
      38              : 
      39           48 : operations &operationsInstance()
      40              : {
      41              :     static operations ops = { ::gmtime_r, sofa::iauDat, sofa::iauCal2jd };
      42           48 :     return ops;
      43              : }
      44              : 
      45            1 : void resetOperations()
      46              : {
      47            1 :     operationsInstance() = { ::gmtime_r, sofa::iauDat, sofa::iauCal2jd };
      48            1 : }
      49              : 
      50              : } // namespace timeUtilsDetail
      51              : 
      52              : template <>
      53           84 : double get_curr_time<double, CLOCK_REALTIME>( timespec &tsp )
      54              : {
      55           84 :     clock_gettime( CLOCK_REALTIME, &tsp );
      56              : 
      57           84 :     return ( (double)tsp.tv_sec ) + ( (double)tsp.tv_nsec ) / 1e9;
      58              : }
      59              : 
      60              : template <>
      61           82 : double get_curr_time<double, CLOCK_REALTIME>()
      62              : {
      63              :     struct timespec tsp;
      64          164 :     return get_curr_time<double, CLOCK_REALTIME>( tsp );
      65              : }
      66              : 
      67            1 : void sleep( unsigned sec )
      68              : {
      69            1 :     std::this_thread::sleep_for( std::chrono::seconds( sec ) );
      70            1 : }
      71              : 
      72            1 : void milliSleep( unsigned msec )
      73              : {
      74            1 :     std::this_thread::sleep_for( std::chrono::milliseconds( msec ) );
      75            1 : }
      76              : 
      77            1 : void microSleep( unsigned usec )
      78              : {
      79            1 :     std::this_thread::sleep_for( std::chrono::microseconds( usec ) );
      80            1 : }
      81              : 
      82            1 : void nanoSleep( unsigned nsec )
      83              : {
      84            1 :     std::this_thread::sleep_for( std::chrono::nanoseconds( nsec ) );
      85            1 : }
      86              : 
      87           19 : void timespecAddNsec( timespec &ts, unsigned nsec )
      88              : {
      89           19 :     ts.tv_nsec += nsec % 1000000000;
      90           19 :     ts.tv_sec += nsec / 1000000000;
      91              : 
      92           19 :     if( ts.tv_nsec > 999999999 )
      93              :     {
      94            1 :         ts.tv_nsec -= 1000000000;
      95            1 :         ts.tv_sec += 1;
      96              :     }
      97           19 : }
      98              : 
      99            7 : double Cal2mjd( int yr, int mon, int day, int hr, int min, double sec )
     100              : {
     101              :     double djm0;
     102              :     double djm;
     103              : 
     104            7 :     int rv = timeUtilsDetail::operationsInstance().iauCal2jd( yr, mon, day, &djm0, &djm );
     105              : 
     106            7 :     if( rv < 0 )
     107            3 :         return (double)rv;
     108              : 
     109            4 :     djm0 = djm + ( ( (double)hr ) / ( 24.0 ) + ( (double)min ) / ( 60.0 * 24.0 ) + sec / ( 3600.0 * 24.0 ) );
     110              : 
     111            4 :     return djm0;
     112              : }
     113              : 
     114            5 : int ISO8601dateBreakdown( int &yr, int &mon, int &day, int &hr, int &min, double &sec, const std::string &fdate )
     115              : {
     116            5 :     if( fdate.length() < 19 )
     117            1 :         return -4;
     118              : 
     119            4 :     yr = atoi( fdate.substr( 0, 4 ).c_str() );
     120            4 :     mon = atoi( fdate.substr( 5, 2 ).c_str() );
     121            4 :     day = atoi( fdate.substr( 8, 2 ).c_str() );
     122              : 
     123              :     double _hr, _min;
     124            4 :     parse_hms( _hr, _min, sec, fdate.substr( 11 ) );
     125              : 
     126            4 :     hr = floor( _hr );
     127            4 :     min = floor( _min );
     128              : 
     129            4 :     return 0;
     130              : }
     131              : 
     132            3 : double ISO8601date2mjd( const std::string &fdate )
     133              : {
     134            3 :     if( fdate.length() < 19 )
     135            1 :         return -4;
     136              : 
     137              :     int yr, mon, day, hr, min;
     138              :     // double hr, min, sec;
     139              :     double sec;
     140              : 
     141            2 :     ISO8601dateBreakdown( yr, mon, day, hr, min, sec, fdate );
     142              : 
     143            2 :     return Cal2mjd( yr, mon, day, hr, min, sec );
     144              : }
     145              : 
     146              : template <>
     147           12 : std::string ISO8601DateTimeStr<time_t>( const time_t &timeIn, int timeZone )
     148              : {
     149              :     tm bdt;
     150           12 :     if( timeUtilsDetail::operationsInstance().gmtimeR( &timeIn, &bdt ) == nullptr )
     151              :     {
     152            2 :         return {};
     153              :     }
     154              : 
     155              :     char tstr[25];
     156              : 
     157           10 :     strftime( tstr, 25, "%FT%H:%M:%S", &bdt );
     158              : 
     159           10 :     std::string result = tstr;
     160              : 
     161           10 :     if( timeZone == 1 )
     162            2 :         result += "Z";
     163           10 :     if( timeZone == 2 )
     164            2 :         result += "+00:00";
     165              : 
     166           10 :     return result;
     167           10 : }
     168              : 
     169              : template <>
     170            4 : std::string ISO8601DateTimeStr<timespec>( const timespec &timeIn, int timeZone )
     171              : {
     172            4 :     std::string result = ISO8601DateTimeStr<time_t>( timeIn.tv_sec, 0 );
     173            4 :     if( result.empty() )
     174              :     {
     175            1 :         return result;
     176              :     }
     177              : 
     178              :     char tstr[20];
     179              : 
     180            3 :     snprintf( tstr, 20, ".%09ld", timeIn.tv_nsec );
     181              : 
     182            3 :     result += tstr;
     183              : 
     184            3 :     if( timeZone == 1 )
     185            1 :         result += "Z";
     186            3 :     if( timeZone == 2 )
     187            1 :         result += "+00:00";
     188              : 
     189            3 :     return result;
     190              : } // LCOV_EXCL_LINE
     191              : 
     192            3 : std::string ISO8601DateTimeStr( int timeZone )
     193              : {
     194            3 :     return ISO8601DateTimeStr<time_t>( ::time( 0 ), timeZone );
     195              : }
     196              : 
     197            3 : std::string ISO8601DateTimeStrMJD( const double &timeIn, int timeZone )
     198              : {
     199              :     int iy, im, id;
     200              :     double fd;
     201              : 
     202            3 :     sofa::iauJd2cal( DJM0, timeIn, &iy, &im, &id, &fd );
     203              : 
     204              :     int hr, mn;
     205              : 
     206            3 :     hr = floor( fd * 24.0 );
     207            3 :     fd = ( fd - hr / 24.0 ) * 24.0;
     208              : 
     209            3 :     mn = floor( fd * 60. );
     210              : 
     211            3 :     fd = ( fd - mn / 60.0 ) * 3600.0;
     212              : 
     213              :     char tstr[32];
     214              : 
     215            3 :     snprintf( tstr, 32, "%04d-%02d-%02dT%02d:%02d:%012.9f", iy, im, id, hr, mn, fd );
     216              : 
     217            3 :     std::string result = tstr;
     218              : 
     219            3 :     if( timeZone == 1 )
     220            1 :         result += "Z";
     221            3 :     if( timeZone == 2 )
     222            1 :         result += "+00:00";
     223              : 
     224            3 :     return result;
     225              : } // LCOV_EXCL_LINE
     226              : 
     227            2 : int timeStamp( std::string &tstamp, timespec &ts )
     228              : {
     229              :     tm uttime; // The broken down time.
     230              : 
     231            2 :     time_t t0 = ts.tv_sec;
     232              : 
     233            2 :     if( timeUtilsDetail::operationsInstance().gmtimeR( &t0, &uttime ) == nullptr )
     234              :     {
     235            1 :         std::cerr << "Error getting UT time (gmtime_r returned 0). At: " << __FILE__ << " " << __LINE__ << "\n";
     236            1 :         return -1;
     237              :     }
     238              : 
     239              :     char buffer[48];
     240              : 
     241            1 :     snprintf( buffer,
     242              :               sizeof( buffer ),
     243              :               "%04i%02i%02i%02i%02i%02i%09i",
     244            1 :               uttime.tm_year + 1900,
     245            1 :               uttime.tm_mon + 1,
     246              :               uttime.tm_mday,
     247              :               uttime.tm_hour,
     248              :               uttime.tm_min,
     249              :               uttime.tm_sec,
     250            1 :               static_cast<int>( ts.tv_nsec ) ); // casting in case we switch type of time_ns.
     251              : 
     252            1 :     tstamp = buffer;
     253              : 
     254            1 :     return 0;
     255              : }
     256              : 
     257            6 : int timespecUTC2TAIMJD( double &djm, double &djmf, const timespec &tsp, tm *tm0 )
     258              : {
     259              :     double dat, djm0;
     260              :     tm localTm;
     261              :     tm *tmrv;
     262              :     int rv1, rv2;
     263              : 
     264            6 :     if( tm0 == nullptr )
     265              :     {
     266            1 :         tm0 = &localTm;
     267              :     }
     268              : 
     269              :     // Get the broken down time corresponding to tsp0
     270            6 :     tmrv = timeUtilsDetail::operationsInstance().gmtimeR( &tsp.tv_sec, tm0 );
     271            6 :     if( tmrv == 0 )
     272            1 :         return -10;
     273              : 
     274              :     // Then determine deltaAT = TAI-UTC
     275            5 :     rv1 = timeUtilsDetail::operationsInstance().iauDat( 1900 + tm0->tm_year, 1 + tm0->tm_mon, tm0->tm_mday, 0.0, &dat );
     276            5 :     if( rv1 < 0 )
     277            1 :         return rv1;
     278              : 
     279              :     // And get the MJD
     280            4 :     rv2 = timeUtilsDetail::operationsInstance().iauCal2jd( 1900 + tm0->tm_year,
     281            4 :                                                            1 + tm0->tm_mon,
     282              :                                                            tm0->tm_mday,
     283              :                                                            &djm0,
     284              :                                                            &djm );
     285            4 :     if( rv2 < 0 )
     286            1 :         return rv2;
     287              : 
     288              :     // Finally calculate the day fraction
     289            3 :     djmf = ( (double)tm0->tm_hour ) / 24.0 + ( (double)tm0->tm_min ) / ( 24.0 * 60. ) +
     290            3 :            ( ( (double)tm0->tm_sec ) + ( (double)tsp.tv_nsec / 1e9 ) + dat ) / ( 24.0 * 3600.0 );
     291              : 
     292            3 :     if( djmf >= 1.0 )
     293              :     {
     294            1 :         djmf -= 1.0;
     295            1 :         djm += 1.0;
     296              :     }
     297              : 
     298            3 :     if( rv1 )
     299            1 :         return rv1;
     300            2 :     return 0;
     301              : }
     302              : 
     303            3 : timespec meanTimespec( timespec ts1, timespec ts2 )
     304              : {
     305            3 :     double means = ( ts1.tv_sec + ts2.tv_sec ) / 2.0;
     306            3 :     double meanns = ( ts1.tv_nsec + ts2.tv_nsec ) / 2.0;
     307              : 
     308            3 :     ts1.tv_sec = floor( means );
     309            3 :     ts1.tv_nsec = round( meanns );
     310              : 
     311            3 :     if( means != floor( means ) )
     312              :     {
     313            2 :         ts1.tv_nsec += 5e8;
     314              : 
     315            2 :         if( ts1.tv_nsec >= 1e9 )
     316              :         {
     317            1 :             ts1.tv_sec += 1;
     318            1 :             ts1.tv_nsec -= 1e9;
     319              :         }
     320              :     }
     321              : 
     322            3 :     return ts1;
     323              : }
     324              : 
     325              : namespace tscomp
     326              : {
     327              : 
     328            6 : bool operator<( timespec const &tsL, timespec const &tsR )
     329              : {
     330            6 :     return ( ( ( tsL.tv_sec == tsR.tv_sec ) && ( tsL.tv_nsec < tsR.tv_nsec ) ) || ( tsL.tv_sec < tsR.tv_sec ) );
     331              : }
     332              : 
     333            6 : bool operator>( timespec const &tsL, timespec const &tsR )
     334              : {
     335            6 :     return ( ( ( tsL.tv_sec == tsR.tv_sec ) && ( tsL.tv_nsec > tsR.tv_nsec ) ) || ( tsL.tv_sec > tsR.tv_sec ) );
     336              : }
     337              : 
     338            6 : bool operator==( timespec const &tsL, timespec const &tsR )
     339              : {
     340            6 :     return ( ( tsL.tv_sec == tsR.tv_sec ) && ( tsL.tv_nsec == tsR.tv_nsec ) );
     341              : }
     342              : 
     343            3 : bool operator<=( timespec const &tsL, timespec const &tsR )
     344              : {
     345            3 :     return ( tsL < tsR || tsL == tsR );
     346              : }
     347              : 
     348            3 : bool operator>=( timespec const &tsL, timespec const &tsR )
     349              : {
     350            3 :     return ( tsL > tsR || tsL == tsR );
     351              : }
     352              : 
     353              : } // namespace tscomp
     354              : 
     355              : } // namespace sys
     356              : } // namespace mx
        

Generated by: LCOV version 2.0-1