mxlib
c++ tools for analyzing astronomical data and other tasks by Jared R. Males. [git repo]
Loading...
Searching...
No Matches
timeUtils.cpp
Go to the documentation of this file.
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
31namespace mx
32{
33namespace sys
34{
35
36namespace timeUtilsDetail
37{
38
39operations &operationsInstance()
40{
41 static operations ops = { ::gmtime_r, sofa::iauDat, sofa::iauCal2jd };
42 return ops;
43}
44
45void resetOperations()
46{
47 operationsInstance() = { ::gmtime_r, sofa::iauDat, sofa::iauCal2jd };
48}
49
50} // namespace timeUtilsDetail
51
52template <>
53double get_curr_time<double, CLOCK_REALTIME>( timespec &tsp )
54{
55 clock_gettime( CLOCK_REALTIME, &tsp );
56
57 return ( (double)tsp.tv_sec ) + ( (double)tsp.tv_nsec ) / 1e9;
58}
59
60template <>
62{
63 struct timespec tsp;
65}
66
67void sleep( unsigned sec )
68{
69 std::this_thread::sleep_for( std::chrono::seconds( sec ) );
70}
71
72void milliSleep( unsigned msec )
73{
74 std::this_thread::sleep_for( std::chrono::milliseconds( msec ) );
75}
76
77void microSleep( unsigned usec )
78{
79 std::this_thread::sleep_for( std::chrono::microseconds( usec ) );
80}
81
82void nanoSleep( unsigned nsec )
83{
84 std::this_thread::sleep_for( std::chrono::nanoseconds( nsec ) );
85}
86
87void timespecAddNsec( timespec &ts, unsigned nsec )
88{
89 ts.tv_nsec += nsec % 1000000000;
90 ts.tv_sec += nsec / 1000000000;
91
92 if( ts.tv_nsec > 999999999 )
93 {
94 ts.tv_nsec -= 1000000000;
95 ts.tv_sec += 1;
96 }
97}
98
99double Cal2mjd( int yr, int mon, int day, int hr, int min, double sec )
100{
101 double djm0;
102 double djm;
103
104 int rv = timeUtilsDetail::operationsInstance().iauCal2jd( yr, mon, day, &djm0, &djm );
105
106 if( rv < 0 )
107 return (double)rv;
108
109 djm0 = djm + ( ( (double)hr ) / ( 24.0 ) + ( (double)min ) / ( 60.0 * 24.0 ) + sec / ( 3600.0 * 24.0 ) );
110
111 return djm0;
112}
113
114int ISO8601dateBreakdown( int &yr, int &mon, int &day, int &hr, int &min, double &sec, const std::string &fdate )
115{
116 if( fdate.length() < 19 )
117 return -4;
118
119 yr = atoi( fdate.substr( 0, 4 ).c_str() );
120 mon = atoi( fdate.substr( 5, 2 ).c_str() );
121 day = atoi( fdate.substr( 8, 2 ).c_str() );
122
123 double _hr, _min;
124 parse_hms( _hr, _min, sec, fdate.substr( 11 ) );
125
126 hr = floor( _hr );
127 min = floor( _min );
128
129 return 0;
130}
131
132double ISO8601date2mjd( const std::string &fdate )
133{
134 if( fdate.length() < 19 )
135 return -4;
136
137 int yr, mon, day, hr, min;
138 // double hr, min, sec;
139 double sec;
140
141 ISO8601dateBreakdown( yr, mon, day, hr, min, sec, fdate );
142
143 return Cal2mjd( yr, mon, day, hr, min, sec );
144}
145
146template <>
147std::string ISO8601DateTimeStr<time_t>( const time_t &timeIn, int timeZone )
148{
149 tm bdt;
150 if( timeUtilsDetail::operationsInstance().gmtimeR( &timeIn, &bdt ) == nullptr )
151 {
152 return {};
153 }
154
155 char tstr[25];
156
157 strftime( tstr, 25, "%FT%H:%M:%S", &bdt );
158
159 std::string result = tstr;
160
161 if( timeZone == 1 )
162 result += "Z";
163 if( timeZone == 2 )
164 result += "+00:00";
165
166 return result;
167}
168
169template <>
170std::string ISO8601DateTimeStr<timespec>( const timespec &timeIn, int timeZone )
171{
172 std::string result = ISO8601DateTimeStr<time_t>( timeIn.tv_sec, 0 );
173 if( result.empty() )
174 {
175 return result;
176 }
177
178 char tstr[20];
179
180 snprintf( tstr, 20, ".%09ld", timeIn.tv_nsec );
181
182 result += tstr;
183
184 if( timeZone == 1 )
185 result += "Z";
186 if( timeZone == 2 )
187 result += "+00:00";
188
189 return result;
190} // LCOV_EXCL_LINE
191
192std::string ISO8601DateTimeStr( int timeZone )
193{
194 return ISO8601DateTimeStr<time_t>( ::time( 0 ), timeZone );
195}
196
197std::string ISO8601DateTimeStrMJD( const double &timeIn, int timeZone )
198{
199 int iy, im, id;
200 double fd;
201
202 sofa::iauJd2cal( DJM0, timeIn, &iy, &im, &id, &fd );
203
204 int hr, mn;
205
206 hr = floor( fd * 24.0 );
207 fd = ( fd - hr / 24.0 ) * 24.0;
208
209 mn = floor( fd * 60. );
210
211 fd = ( fd - mn / 60.0 ) * 3600.0;
212
213 char tstr[32];
214
215 snprintf( tstr, 32, "%04d-%02d-%02dT%02d:%02d:%012.9f", iy, im, id, hr, mn, fd );
216
217 std::string result = tstr;
218
219 if( timeZone == 1 )
220 result += "Z";
221 if( timeZone == 2 )
222 result += "+00:00";
223
224 return result;
225} // LCOV_EXCL_LINE
226
227int timeStamp( std::string &tstamp, timespec &ts )
228{
229 tm uttime; // The broken down time.
230
231 time_t t0 = ts.tv_sec;
232
233 if( timeUtilsDetail::operationsInstance().gmtimeR( &t0, &uttime ) == nullptr )
234 {
235 std::cerr << "Error getting UT time (gmtime_r returned 0). At: " << __FILE__ << " " << __LINE__ << "\n";
236 return -1;
237 }
238
239 char buffer[48];
240
241 snprintf( buffer,
242 sizeof( buffer ),
243 "%04i%02i%02i%02i%02i%02i%09i",
244 uttime.tm_year + 1900,
245 uttime.tm_mon + 1,
246 uttime.tm_mday,
247 uttime.tm_hour,
248 uttime.tm_min,
249 uttime.tm_sec,
250 static_cast<int>( ts.tv_nsec ) ); // casting in case we switch type of time_ns.
251
252 tstamp = buffer;
253
254 return 0;
255}
256
257int 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 if( tm0 == nullptr )
265 {
266 tm0 = &localTm;
267 }
268
269 // Get the broken down time corresponding to tsp0
270 tmrv = timeUtilsDetail::operationsInstance().gmtimeR( &tsp.tv_sec, tm0 );
271 if( tmrv == 0 )
272 return -10;
273
274 // Then determine deltaAT = TAI-UTC
275 rv1 = timeUtilsDetail::operationsInstance().iauDat( 1900 + tm0->tm_year, 1 + tm0->tm_mon, tm0->tm_mday, 0.0, &dat );
276 if( rv1 < 0 )
277 return rv1;
278
279 // And get the MJD
280 rv2 = timeUtilsDetail::operationsInstance().iauCal2jd( 1900 + tm0->tm_year,
281 1 + tm0->tm_mon,
282 tm0->tm_mday,
283 &djm0,
284 &djm );
285 if( rv2 < 0 )
286 return rv2;
287
288 // Finally calculate the day fraction
289 djmf = ( (double)tm0->tm_hour ) / 24.0 + ( (double)tm0->tm_min ) / ( 24.0 * 60. ) +
290 ( ( (double)tm0->tm_sec ) + ( (double)tsp.tv_nsec / 1e9 ) + dat ) / ( 24.0 * 3600.0 );
291
292 if( djmf >= 1.0 )
293 {
294 djmf -= 1.0;
295 djm += 1.0;
296 }
297
298 if( rv1 )
299 return rv1;
300 return 0;
301}
302
303timespec meanTimespec( timespec ts1, timespec ts2 )
304{
305 double means = ( ts1.tv_sec + ts2.tv_sec ) / 2.0;
306 double meanns = ( ts1.tv_nsec + ts2.tv_nsec ) / 2.0;
307
308 ts1.tv_sec = floor( means );
309 ts1.tv_nsec = round( meanns );
310
311 if( means != floor( means ) )
312 {
313 ts1.tv_nsec += 5e8;
314
315 if( ts1.tv_nsec >= 1e9 )
316 {
317 ts1.tv_sec += 1;
318 ts1.tv_nsec -= 1e9;
319 }
320 }
321
322 return ts1;
323}
324
325namespace tscomp
326{
327
328bool operator<( timespec const &tsL, timespec const &tsR )
329{
330 return ( ( ( tsL.tv_sec == tsR.tv_sec ) && ( tsL.tv_nsec < tsR.tv_nsec ) ) || ( tsL.tv_sec < tsR.tv_sec ) );
331}
332
333bool operator>( timespec const &tsL, timespec const &tsR )
334{
335 return ( ( ( tsL.tv_sec == tsR.tv_sec ) && ( tsL.tv_nsec > tsR.tv_nsec ) ) || ( tsL.tv_sec > tsR.tv_sec ) );
336}
337
338bool operator==( timespec const &tsL, timespec const &tsR )
339{
340 return ( ( tsL.tv_sec == tsR.tv_sec ) && ( tsL.tv_nsec == tsR.tv_nsec ) );
341}
342
343bool operator<=( timespec const &tsL, timespec const &tsR )
344{
345 return ( tsL < tsR || tsL == tsR );
346}
347
348bool operator>=( timespec const &tsL, timespec const &tsR )
349{
350 return ( tsL > tsR || tsL == tsR );
351}
352
353} // namespace tscomp
354
355} // namespace sys
356} // namespace mx
#define DJM0
Julian Date of Modified Julian Date zero (defined in the SOFA library sofam.h).
void nanoSleep(unsigned nsec)
Sleep for a specified period in nanoseconds.
Definition timeUtils.cpp:82
void sleep(unsigned sec)
Sleep for a specified period in seconds.
Definition timeUtils.cpp:67
void milliSleep(unsigned msec)
Sleep for a specified period in milliseconds.
Definition timeUtils.cpp:72
void microSleep(unsigned usec)
Sleep for a specified period in microseconds.
Definition timeUtils.cpp:77
bool operator<(timespec const &tsL, timespec const &tsR)
Timespec comparison operator < (see caveats).
bool operator==(timespec const &tsL, timespec const &tsR)
Timespec comparison operator == (see caveats).
bool operator>(timespec const &tsL, timespec const &tsR)
Timespec comparison operator > (see caveats).
bool operator>=(timespec const &tsL, timespec const &tsR)
Timespec comparison operator >= (see caveats).
bool operator<=(timespec const &tsL, timespec const &tsR)
Timespec comparison operator <= (see caveats).
int ISO8601dateBreakdown(int &yr, int &mon, int &day, int &hr, int &min, double &sec, const std::string &fdate)
Parse an ISO8601 date of the form "YYYY-MM-DDTHH:MM:SS.S" into the individual components.
std::string ISO8601DateTimeStr(const timeT &timeIn, int timeZone=0)
Get a date-time string in ISO 8601 format.
std::string ISO8601DateTimeStrMJD(const double &timeIn, int timeZone=0)
Get a date-time string in ISO 8601 format for an MJD.
int timespecUTC2TAIMJD(double &djm, double &djmf, const timespec &tsp, tm *tm0)
Convert a UTC timespec to TAI modified Julian date.
std::string ISO8601DateTimeStr< timespec >(const timespec &timeIn, int timeZone)
Get a date-time string in ISO 8601 format for timespec.
void timespecAddNsec(timespec &ts, unsigned nsec)
Adds a time offset to an existing timespec.
Definition timeUtils.cpp:87
void parse_hms(floatT &h, floatT &m, floatT &s, const std::string &hmsstr)
int timeStamp(std::string &tstamp, timespec &ts)
Get a timestamp string in the form YYYYMMDDHHMMSS.SSSSSSSSS.
double Cal2mjd(int yr, int mon, int day, int hr, int min, double sec)
Converts a Gregorian calendar date into modified Julian date (MJD).
Definition timeUtils.cpp:99
typeT get_curr_time(timespec &tsp)
Get the current system time in seconds.
Definition timeUtils.hpp:91
double ISO8601date2mjd(const std::string &fdate)
Parse an ISO8601 date of the form "YYYY-MM-DDTHH:MM:SS.S" and return the modified Julian date (MJD).
std::string ISO8601DateTimeStr< time_t >(const time_t &timeIn, int timeZone)
Get a date-time string in ISO 8601 format for time_t.
The mxlib c++ namespace.
Definition mxlib.hpp:37
Utilities for working with time.
timespec meanTimespec(timespec ts1, timespec ts2)
Calculate the mean time of two times given by timespecs.