Line | Branch | Exec | Source |
---|---|---|---|
1 | // This file is part of INSTINCT, the INS Toolkit for Integrated | ||
2 | // Navigation Concepts and Training by the Institute of Navigation of | ||
3 | // the University of Stuttgart, Germany. | ||
4 | // | ||
5 | // This Source Code Form is subject to the terms of the Mozilla Public | ||
6 | // License, v. 2.0. If a copy of the MPL was not distributed with this | ||
7 | // file, You can obtain one at https://mozilla.org/MPL/2.0/. | ||
8 | |||
9 | /// @file InsTime.hpp | ||
10 | /// @brief The class is responsible for all time-related tasks | ||
11 | /// @author T. Topp (topp@ins.uni-stuttgart.de) | ||
12 | /// @author T. Lambertus (tomke-jantje.lambertus@nav.uni-stuttgart.de) | ||
13 | /// @date 2020-12-02 | ||
14 | /// | ||
15 | /// @details This class contains all time-transformations functions. One instance is created for each InsTime object (defined in the structs). | ||
16 | /// Internally, only the MJD-time (Modified Julien Date) is stored (here MJD is a struct which has mjd_day and mjd_frac). | ||
17 | |||
18 | #pragma once | ||
19 | |||
20 | #include <cstdint> | ||
21 | #include <string> | ||
22 | #include <array> | ||
23 | #include <limits> | ||
24 | #include <iostream> | ||
25 | #include <chrono> | ||
26 | |||
27 | #include <fmt/ostream.h> | ||
28 | #include "gcem.hpp" | ||
29 | |||
30 | #include <nlohmann/json.hpp> | ||
31 | using json = nlohmann::json; ///< json namespace | ||
32 | |||
33 | #include "TimeSystem.hpp" | ||
34 | #include "Navigation/Math/Math.hpp" | ||
35 | |||
36 | namespace NAV | ||
37 | { | ||
38 | /// @brief Utility Namespace for Time related tasks | ||
39 | namespace InsTimeUtil | ||
40 | { | ||
41 | constexpr int32_t END_OF_THE_CENTURY_MJD = 400000; ///< Modified Julian Date of the end of the century (15.01.2954) | ||
42 | constexpr int32_t WEEKS_PER_GPS_CYCLE = 1024; ///< Weeks per GPS cycle | ||
43 | constexpr int32_t DIFF_TO_6_1_1980_MJD = 44244; ///< 06.01.1980 in Modified Julian Date | ||
44 | constexpr int32_t DIFF_TO_1_1_1970_MJD = 40587; ///< 01.01.1970 00:00:00 UTC in Modified Julian Date (UNIX epoch) | ||
45 | constexpr int32_t DIFF_BDT_WEEK_TO_GPST_WEEK = 1356; ///< BeiDou starts zero at 1-Jan-2006 and GPS starts 6-Jan-1980 | ||
46 | |||
47 | constexpr int32_t DIFF_MJD_TO_JD_DAYS = 2400000; ///< Difference of the days between MJD and JD | ||
48 | constexpr long double DIFF_MJD_TO_JD_FRAC = 0.5L; ///< Difference of the fraction between MJD and JD | ||
49 | |||
50 | constexpr int32_t MONTHS_PER_YEAR = 12; ///< Months / Year | ||
51 | constexpr int32_t DAYS_PER_YEAR = 365; ///< Days / Year | ||
52 | constexpr int32_t DAYS_PER_WEEK = 7; ///< Days / Week | ||
53 | constexpr int32_t HOURS_PER_DAY = 24; ///< Hours / Day | ||
54 | constexpr int32_t HOURS_PER_WEEK = HOURS_PER_DAY * DAYS_PER_WEEK; ///< Hours / Week | ||
55 | constexpr int32_t MINUTES_PER_HOUR = 60; ///< Minutes / Hour | ||
56 | constexpr int32_t MINUTES_PER_DAY = MINUTES_PER_HOUR * HOURS_PER_DAY; ///< Minutes / Day | ||
57 | constexpr int32_t MINUTES_PER_WEEK = MINUTES_PER_DAY * DAYS_PER_WEEK; ///< Minutes / Week | ||
58 | constexpr int32_t SECONDS_PER_MINUTE = 60; ///< Seconds / Minute | ||
59 | constexpr int32_t SECONDS_PER_HOUR = SECONDS_PER_MINUTE * MINUTES_PER_HOUR; ///< Seconds / Hour | ||
60 | constexpr int32_t SECONDS_PER_DAY = SECONDS_PER_MINUTE * MINUTES_PER_HOUR * HOURS_PER_DAY; ///< Seconds / Day | ||
61 | constexpr int32_t SECONDS_PER_WEEK = SECONDS_PER_DAY * DAYS_PER_WEEK; ///< Seconds / Week | ||
62 | |||
63 | /// Numerical precision/epsilon for 'long double' variables | ||
64 | /// - Linux/x64: 1e-19 | ||
65 | /// - Windows/x64 1e-16 | ||
66 | /// - Linux/armv8: 1e-34 (Epsilon reports too small precision. Real precision is only approx. 1e-17) | ||
67 | constexpr long double EPSILON = std::max(1e-17L, 10 * std::numeric_limits<long double>::epsilon()); | ||
68 | |||
69 | /// Maps GPS leap seconds to a time: array<mjd_day>, index + 1 is amount of leap seconds | ||
70 | constexpr std::array<int32_t, 20> GPS_LEAP_SEC_MJD = { | ||
71 | 0, // + 0 at 1 Jan 1980 and before | ||
72 | 44786, // + 1 at 1 Jul 1981 = diff UTC-TAI: 20 | ||
73 | 45151, // + 2 at 1 Jul 1982 = diff UTC-TAI: 21 | ||
74 | 45516, // + 3 at 1 Jul 1983 = diff UTC-TAI: 22 | ||
75 | 46247, // + 4 at 1 Jul 1985 = diff UTC-TAI: 23 | ||
76 | 47161, // + 5 at 1 Jan 1988 = diff UTC-TAI: 24 | ||
77 | 47892, // + 6 at 1 Jan 1990 = diff UTC-TAI: 25 | ||
78 | 48257, // + 7 at 1 Jan 1991 = diff UTC-TAI: 26 | ||
79 | 48804, // + 8 at 1 Jul 1992 = diff UTC-TAI: 27 | ||
80 | 49169, // + 9 at 1 Jul 1993 = diff UTC-TAI: 28 | ||
81 | 49534, // +10 at 1 Jul 1994 = diff UTC-TAI: 29 | ||
82 | 50083, // +11 at 1 Jan 1996 = diff UTC-TAI: 30 | ||
83 | 50630, // +12 at 1 Jul 1997 = diff UTC-TAI: 31 | ||
84 | 51179, // +13 at 1 Jan 1999 = diff UTC-TAI: 32 | ||
85 | 53736, // +14 at 1 Jan 2006 = diff UTC-TAI: 33 | ||
86 | 54832, // +15 at 1 Jan 2009 = diff UTC-TAI: 34 | ||
87 | 56109, // +16 at 1 Jul 2012 = diff UTC-TAI: 35 | ||
88 | 57204, // +17 at 1 Jul 2015 = diff UTC-TAI: 36 | ||
89 | 57754, // +18 at 1 Jan 2017 = diff UTC-TAI: 37 | ||
90 | 99999, // future | ||
91 | }; | ||
92 | |||
93 | /// @brief Returns true if the provided year is a leap year, false otherwise | ||
94 | /// @param[in] year The year to check | ||
95 | /// @return True if the year is a leap year, otherwise false | ||
96 | 818472 | constexpr bool isLeapYear(int32_t year) | |
97 | { | ||
98 |
6/6✓ Branch 0 taken 187295 times.
✓ Branch 1 taken 631177 times.
✓ Branch 2 taken 14377 times.
✓ Branch 3 taken 172918 times.
✓ Branch 4 taken 14316 times.
✓ Branch 5 taken 631238 times.
|
818472 | return (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0)); |
99 | } | ||
100 | |||
101 | /// @brief Returns the number of days in the specified month of the year | ||
102 | /// @param[in] month Month [1-12] | ||
103 | /// @param[in] year Year to determine the leap year | ||
104 | /// @return Number of days in the specified month | ||
105 | 243865 | constexpr int32_t daysInMonth(int32_t month, int32_t year) | |
106 | { | ||
107 | 243865 | --month; // Make month 0 based | |
108 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 243859 times.
|
243865 | if (month >= InsTimeUtil::MONTHS_PER_YEAR) |
109 | { | ||
110 | 6 | year += month / InsTimeUtil::MONTHS_PER_YEAR; | |
111 | 6 | month %= InsTimeUtil::MONTHS_PER_YEAR; | |
112 | } | ||
113 |
2/2✓ Branch 0 taken 3010 times.
✓ Branch 1 taken 243865 times.
|
246875 | while (month < 0) |
114 | { | ||
115 | 3010 | month += MONTHS_PER_YEAR; | |
116 | 3010 | year--; | |
117 | } | ||
118 | 243865 | ++month; // Make month 1 based | |
119 | |||
120 |
13/13✓ Branch 0 taken 96588 times.
✓ Branch 1 taken 16543 times.
✓ Branch 2 taken 11081 times.
✓ Branch 3 taken 8312 times.
✓ Branch 4 taken 7246 times.
✓ Branch 5 taken 38774 times.
✓ Branch 6 taken 5829 times.
✓ Branch 7 taken 16016 times.
✓ Branch 8 taken 9284 times.
✓ Branch 9 taken 9022 times.
✓ Branch 10 taken 10647 times.
✓ Branch 11 taken 14521 times.
✓ Branch 12 taken 2 times.
|
243865 | switch (month) |
121 | { | ||
122 | 96588 | case 1: | |
123 | 96588 | return 31; | |
124 | 16543 | case 2: | |
125 |
2/2✓ Branch 1 taken 13146 times.
✓ Branch 2 taken 3397 times.
|
16543 | if (isLeapYear(year)) |
126 | { | ||
127 | 13146 | return 29; | |
128 | } | ||
129 | 3397 | return 28; | |
130 | 11081 | case 3: | |
131 | 11081 | return 31; | |
132 | 8312 | case 4: | |
133 | 8312 | return 30; | |
134 | 7246 | case 5: | |
135 | 7246 | return 31; | |
136 | 38774 | case 6: | |
137 | 38774 | return 30; | |
138 | 5829 | case 7: | |
139 | 5829 | return 31; | |
140 | 16016 | case 8: | |
141 | 16016 | return 31; | |
142 | 9284 | case 9: | |
143 | 9284 | return 30; | |
144 | 9022 | case 10: | |
145 | 9022 | return 31; | |
146 | 10647 | case 11: | |
147 | 10647 | return 30; | |
148 | 14521 | case 12: | |
149 | 14521 | return 31; | |
150 | 2 | default: | |
151 | 2 | return 366; | |
152 | } | ||
153 | } | ||
154 | |||
155 | /// @brief Formats a duration given in seconds into days, hours, minutes and seconds | ||
156 | /// @param[in] seconds Amount of seconds | ||
157 | /// @param[in] digits Digits to round the seconds to | ||
158 | /// @return Formatted string of the duration | ||
159 | 12 | constexpr std::string formatDuration(double seconds, size_t digits = 9) | |
160 | { | ||
161 | 12 | std::string str; | |
162 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 8 times.
|
12 | if (seconds >= SECONDS_PER_DAY) |
163 | { | ||
164 | 4 | auto days = static_cast<int32_t>(seconds) / SECONDS_PER_DAY; | |
165 |
2/4✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 4 times.
✗ Branch 6 not taken.
|
8 | str += fmt::format("{}{:d}d", str.empty() ? "" : " ", days); |
166 | 4 | seconds -= days * SECONDS_PER_DAY; | |
167 | } | ||
168 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 8 times.
|
12 | if (seconds >= SECONDS_PER_HOUR) |
169 | { | ||
170 | 4 | auto hours = static_cast<int32_t>(seconds) / SECONDS_PER_HOUR; | |
171 |
3/4✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
✓ Branch 5 taken 4 times.
✗ Branch 6 not taken.
|
8 | str += fmt::format("{}{:d}h", str.empty() ? "" : " ", hours); |
172 | 4 | seconds -= hours * SECONDS_PER_HOUR; | |
173 | } | ||
174 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 8 times.
|
12 | if (seconds >= SECONDS_PER_MINUTE) |
175 | { | ||
176 | 4 | auto minutes = static_cast<int32_t>(seconds) / SECONDS_PER_MINUTE; | |
177 |
3/4✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
✓ Branch 5 taken 4 times.
✗ Branch 6 not taken.
|
8 | str += fmt::format("{}{:d}m", str.empty() ? "" : " ", minutes); |
178 | 4 | seconds -= minutes * SECONDS_PER_MINUTE; | |
179 | } | ||
180 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
|
12 | if (seconds > 1e-9) |
181 | { | ||
182 | 6 | size_t d = 0; | |
183 |
1/2✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
|
30 | for (; d < digits + 1; d++) |
184 | { | ||
185 | 30 | if (2.0 * std::abs(std::round(seconds * std::pow(10.0, d)) - seconds * std::pow(10.0, d)) | |
186 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 24 times.
|
30 | < std::pow(10.0, -(static_cast<double>(digits) - static_cast<double>(d)))) |
187 | { | ||
188 | 6 | break; | |
189 | } | ||
190 | } | ||
191 |
3/4✓ Branch 1 taken 4 times.
✓ Branch 2 taken 2 times.
✓ Branch 5 taken 6 times.
✗ Branch 6 not taken.
|
12 | str += fmt::format("{}{:.{}f}s", str.empty() ? "" : " ", seconds, d); |
192 | } | ||
193 | 12 | return str; | |
194 | ✗ | } | |
195 | |||
196 | } // namespace InsTimeUtil | ||
197 | |||
198 | /// Modified Julien Date [UTC] | ||
199 | struct InsTime_MJD | ||
200 | { | ||
201 | int32_t mjd_day = 0; ///< Full days since 17. November 1858 [UTC] | ||
202 | long double mjd_frac = 0.0L; ///< Decimal fractions of a day of the Modified Julien Date [UTC] | ||
203 | |||
204 | /// @brief Default constructor | ||
205 | 772179 | constexpr InsTime_MJD() = default; | |
206 | |||
207 | /// @brief Constructor | ||
208 | /// @param[in] mjd_day Full days of the Modified Julien Date [UTC] | ||
209 | /// @param[in] mjd_frac Decimal fractions of a day of the Modified Julien Date [UTC] | ||
210 | 1293175 | constexpr InsTime_MJD(int32_t mjd_day, long double mjd_frac) | |
211 | 1293175 | : mjd_day(mjd_day), mjd_frac(mjd_frac) | |
212 | { | ||
213 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1293172 times.
|
1293175 | if (this->mjd_frac >= 1.0L) |
214 | { | ||
215 | 3 | this->mjd_day += static_cast<int32_t>(this->mjd_frac); | |
216 | 3 | this->mjd_frac -= static_cast<int32_t>(this->mjd_frac); | |
217 | } | ||
218 |
2/2✓ Branch 0 taken 167050 times.
✓ Branch 1 taken 1293175 times.
|
1460225 | while (this->mjd_frac < 0.0L) |
219 | { | ||
220 | 167050 | this->mjd_frac += 1.0L; | |
221 | 167050 | this->mjd_day--; | |
222 | } | ||
223 | 1293175 | } | |
224 | |||
225 | /// @brief Equal comparison operator (takes double precision into account) | ||
226 | /// @param[in] rhs Right-hand side to compare with | ||
227 | /// @return Comparison result | ||
228 | 7389173 | constexpr bool operator==(const InsTime_MJD& rhs) const | |
229 | { | ||
230 |
2/2✓ Branch 0 taken 7354412 times.
✓ Branch 1 taken 34761 times.
|
7389173 | if (mjd_day == rhs.mjd_day) |
231 | { | ||
232 | 7354412 | auto difference = gcem::abs(mjd_frac - rhs.mjd_frac); | |
233 | 7354162 | return difference <= InsTimeUtil::EPSILON; | |
234 | } | ||
235 | 69581 | if (auto diffDays = mjd_day - rhs.mjd_day; | |
236 |
2/2✓ Branch 1 taken 82 times.
✓ Branch 2 taken 34738 times.
|
34761 | gcem::abs(diffDays) == 1) |
237 | { | ||
238 | 82 | auto difference = 1 + diffDays * (mjd_frac - rhs.mjd_frac); | |
239 | 82 | return difference <= InsTimeUtil::EPSILON; | |
240 | } | ||
241 | 34738 | return false; | |
242 | } | ||
243 | /// @brief Inequal comparison operator (takes double precision into account) | ||
244 | /// @param[in] rhs Right-hand side to compare with | ||
245 | /// @return Comparison result | ||
246 | 239957 | constexpr bool operator!=(const InsTime_MJD& rhs) const | |
247 | { | ||
248 | 239957 | return !(*this == rhs); | |
249 | } | ||
250 | /// @brief Smaller or equal comparison operator (takes double precision into account) | ||
251 | /// @param[in] rhs Right-hand side to compare with | ||
252 | /// @return Comparison result | ||
253 | 20 | constexpr bool operator<=(const InsTime_MJD& rhs) const | |
254 | { | ||
255 |
3/4✓ Branch 1 taken 8 times.
✓ Branch 2 taken 12 times.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
|
20 | return *this < rhs || *this == rhs; |
256 | } | ||
257 | /// @brief Greater or equal comparison operator (takes double precision into account) | ||
258 | /// @param[in] rhs Right-hand side to compare with | ||
259 | /// @return Comparison result | ||
260 | 8 | constexpr bool operator>=(const InsTime_MJD& rhs) const | |
261 | { | ||
262 |
3/4✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 4 times.
|
8 | return *this > rhs || *this == rhs; |
263 | } | ||
264 | /// @brief Smaller comparison operator (takes double precision into account) | ||
265 | /// @param[in] rhs Right-hand side to compare with | ||
266 | /// @return Comparison result | ||
267 | 1059318 | constexpr bool operator<(const InsTime_MJD& rhs) const | |
268 | { | ||
269 |
3/4✓ Branch 0 taken 1059359 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 239810 times.
✓ Branch 3 taken 819549 times.
|
1059354 | return (mjd_day < rhs.mjd_day || (mjd_day == rhs.mjd_day && mjd_frac < rhs.mjd_frac)) |
270 |
3/4✓ Branch 0 taken 1059354 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 238761 times.
✓ Branch 4 taken 1074 times.
|
2118672 | && *this != rhs; |
271 | } | ||
272 | /// @brief Greater comparison operator (takes double precision into account) | ||
273 | /// @param[in] rhs Right-hand side to compare with | ||
274 | /// @return Comparison result | ||
275 | 12 | constexpr bool operator>(const InsTime_MJD& rhs) const | |
276 | { | ||
277 | 12 | return !(*this <= rhs); | |
278 | } | ||
279 | |||
280 | /// @brief Converts the object into a readable string | ||
281 | explicit operator std::string() const; | ||
282 | }; | ||
283 | |||
284 | /// Julien Date [UTC] | ||
285 | struct InsTime_JD | ||
286 | { | ||
287 | int32_t jd_day{}; ///< Full days since 1. January −4712 [UTC] | ||
288 | long double jd_frac{}; ///< Decimal fractions of a day of the Julien Date [UTC] | ||
289 | |||
290 | /// @brief Constructor | ||
291 | /// @param[in] jd_day Full days of the Julien Date [UTC] | ||
292 | /// @param[in] jd_frac Decimal fractions of a day of the Julien Date [UTC] | ||
293 | 243622 | constexpr InsTime_JD(int32_t jd_day, long double jd_frac) | |
294 | 243622 | : jd_day(jd_day), jd_frac(jd_frac) | |
295 | { | ||
296 |
2/2✓ Branch 0 taken 21124 times.
✓ Branch 1 taken 222498 times.
|
243622 | if (this->jd_frac >= 1.0L) |
297 | { | ||
298 | 21124 | this->jd_day += static_cast<int32_t>(this->jd_frac); | |
299 | 21124 | this->jd_frac -= static_cast<int32_t>(this->jd_frac); | |
300 | } | ||
301 |
2/2✓ Branch 0 taken 138910 times.
✓ Branch 1 taken 243622 times.
|
382532 | while (this->jd_frac < 0.0L) |
302 | { | ||
303 | 138910 | this->jd_frac += 1.0L; | |
304 | 138910 | this->jd_day--; | |
305 | } | ||
306 | 243622 | } | |
307 | |||
308 | /// @brief Equal comparison operator (takes double precision into account) | ||
309 | /// @param[in] rhs Right-hand side to compare with | ||
310 | /// @return Comparison result | ||
311 | 56 | constexpr bool operator==(const InsTime_JD& rhs) const | |
312 | { | ||
313 |
2/2✓ Branch 0 taken 36 times.
✓ Branch 1 taken 20 times.
|
56 | if (jd_day == rhs.jd_day) |
314 | { | ||
315 | 36 | auto difference = gcem::abs(jd_frac - rhs.jd_frac); | |
316 | 36 | return difference <= InsTimeUtil::EPSILON; | |
317 | } | ||
318 | 40 | if (auto diffDays = jd_day - rhs.jd_day; | |
319 |
1/2✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
|
20 | gcem::abs(diffDays) == 1) |
320 | { | ||
321 | 20 | auto difference = 1 + diffDays * (jd_frac - rhs.jd_frac); | |
322 | 20 | return difference <= InsTimeUtil::EPSILON; | |
323 | } | ||
324 | ✗ | return false; | |
325 | } | ||
326 | /// @brief Inequal comparison operator (takes double precision into account) | ||
327 | /// @param[in] rhs Right-hand side to compare with | ||
328 | /// @return Comparison result | ||
329 | 28 | constexpr bool operator!=(const InsTime_JD& rhs) const | |
330 | { | ||
331 | 28 | return !(*this == rhs); | |
332 | } | ||
333 | /// @brief Smaller or equal comparison operator (takes double precision into account) | ||
334 | /// @param[in] rhs Right-hand side to compare with | ||
335 | /// @return Comparison result | ||
336 | 20 | constexpr bool operator<=(const InsTime_JD& rhs) const | |
337 | { | ||
338 |
3/4✓ Branch 1 taken 8 times.
✓ Branch 2 taken 12 times.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
|
20 | return *this < rhs || *this == rhs; |
339 | } | ||
340 | /// @brief Greater or equal comparison operator (takes double precision into account) | ||
341 | /// @param[in] rhs Right-hand side to compare with | ||
342 | /// @return Comparison result | ||
343 | 8 | constexpr bool operator>=(const InsTime_JD& rhs) const | |
344 | { | ||
345 |
3/4✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 4 times.
|
8 | return *this > rhs || *this == rhs; |
346 | } | ||
347 | /// @brief Smaller comparison operator (takes double precision into account) | ||
348 | /// @param[in] rhs Right-hand side to compare with | ||
349 | /// @return Comparison result | ||
350 | 24 | constexpr bool operator<(const InsTime_JD& rhs) const | |
351 | { | ||
352 |
4/4✓ Branch 0 taken 14 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 2 times.
|
16 | return (jd_day < rhs.jd_day || (jd_day == rhs.jd_day && jd_frac < rhs.jd_frac)) |
353 |
4/4✓ Branch 0 taken 16 times.
✓ Branch 1 taken 8 times.
✓ Branch 3 taken 16 times.
✓ Branch 4 taken 4 times.
|
40 | && *this != rhs; |
354 | } | ||
355 | /// @brief Greater comparison operator (takes double precision into account) | ||
356 | /// @param[in] rhs Right-hand side to compare with | ||
357 | /// @return Comparison result | ||
358 | 12 | constexpr bool operator>(const InsTime_JD& rhs) const | |
359 | { | ||
360 | 12 | return !(*this <= rhs); | |
361 | } | ||
362 | |||
363 | /// @brief Converts the object into a readable string | ||
364 | explicit operator std::string() const; | ||
365 | }; | ||
366 | |||
367 | /// GPS week and time of week in GPS standard time [GPST] | ||
368 | struct InsTime_GPSweekTow | ||
369 | { | ||
370 | int32_t gpsCycle{}; ///< Contains GPS cycle in GPS standard time [GPST] | ||
371 | int32_t gpsWeek{}; ///< Contains GPS week in GPS standard time [GPST] | ||
372 | long double tow{}; ///< Contains GPS time of week in seconds in GPS standard time [GPST] | ||
373 | |||
374 | /// @brief Constructor | ||
375 | /// @param[in] gpsCycle GPS cycle in GPS standard time [GPST] | ||
376 | /// @param[in] gpsWeek GPS week in GPS standard time [GPST] | ||
377 | /// @param[in] tow GPS time of week in seconds in GPS standard time [GPST] | ||
378 | 224248 | constexpr InsTime_GPSweekTow(int32_t gpsCycle, int32_t gpsWeek, long double tow) | |
379 | 224248 | : gpsCycle(gpsCycle), gpsWeek(gpsWeek), tow(tow) | |
380 | { | ||
381 |
2/2✓ Branch 0 taken 122655 times.
✓ Branch 1 taken 101593 times.
|
224248 | if (this->tow >= InsTimeUtil::SECONDS_PER_WEEK) |
382 | { | ||
383 | 122655 | this->gpsWeek += static_cast<int32_t>(this->tow / InsTimeUtil::SECONDS_PER_WEEK); | |
384 | 122655 | this->tow = gcem::fmod(this->tow, InsTimeUtil::SECONDS_PER_WEEK); | |
385 | } | ||
386 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 224248 times.
|
224248 | while (this->tow < 0.0L) |
387 | { | ||
388 | ✗ | this->tow += InsTimeUtil::SECONDS_PER_WEEK; | |
389 | ✗ | this->gpsWeek--; | |
390 | } | ||
391 | |||
392 |
2/2✓ Branch 0 taken 194237 times.
✓ Branch 1 taken 30011 times.
|
224248 | if (this->gpsWeek >= InsTimeUtil::WEEKS_PER_GPS_CYCLE) |
393 | { | ||
394 | 194237 | this->gpsCycle += this->gpsWeek / InsTimeUtil::WEEKS_PER_GPS_CYCLE; | |
395 | 194237 | this->gpsWeek %= InsTimeUtil::WEEKS_PER_GPS_CYCLE; | |
396 | } | ||
397 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 224248 times.
|
224248 | while (this->gpsWeek < 0) |
398 | { | ||
399 | ✗ | this->gpsWeek += InsTimeUtil::WEEKS_PER_GPS_CYCLE; | |
400 | ✗ | this->gpsCycle--; | |
401 | } | ||
402 | 224248 | }; | |
403 | |||
404 | /// @brief Equal comparison operator (takes double precision into account) | ||
405 | /// @param[in] rhs Right-hand side to compare with | ||
406 | /// @return Comparison result | ||
407 | 78 | constexpr bool operator==(const InsTime_GPSweekTow& rhs) const | |
408 | { | ||
409 |
4/4✓ Branch 0 taken 58 times.
✓ Branch 1 taken 20 times.
✓ Branch 2 taken 38 times.
✓ Branch 3 taken 20 times.
|
78 | if (gpsCycle == rhs.gpsCycle && gpsWeek == rhs.gpsWeek) |
410 | { | ||
411 | 38 | return gcem::abs(tow - rhs.tow) <= InsTimeUtil::EPSILON; | |
412 | } | ||
413 | 80 | if (auto diffWeeks = gpsCycle * InsTimeUtil::WEEKS_PER_GPS_CYCLE + gpsWeek - (rhs.gpsCycle * InsTimeUtil::WEEKS_PER_GPS_CYCLE + rhs.gpsWeek); | |
414 |
2/2✓ Branch 1 taken 26 times.
✓ Branch 2 taken 14 times.
|
40 | gcem::abs(diffWeeks) == 1) |
415 | { | ||
416 | 26 | return gcem::abs(tow + diffWeeks * InsTimeUtil::SECONDS_PER_WEEK - rhs.tow) <= InsTimeUtil::EPSILON; | |
417 | } | ||
418 | 14 | return false; | |
419 | } | ||
420 | /// @brief Inequal comparison operator (takes double precision into account) | ||
421 | /// @param[in] rhs Right-hand side to compare with | ||
422 | /// @return Comparison result | ||
423 | 36 | constexpr bool operator!=(const InsTime_GPSweekTow& rhs) const | |
424 | { | ||
425 | 36 | return !(*this == rhs); | |
426 | } | ||
427 | /// @brief Smaller or equal comparison operator (takes double precision into account) | ||
428 | /// @param[in] rhs Right-hand side to compare with | ||
429 | /// @return Comparison result | ||
430 | 30 | constexpr bool operator<=(const InsTime_GPSweekTow& rhs) const | |
431 | { | ||
432 |
3/4✓ Branch 1 taken 12 times.
✓ Branch 2 taken 18 times.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
|
30 | return *this < rhs || *this == rhs; |
433 | } | ||
434 | /// @brief Greater or equal comparison operator (takes double precision into account) | ||
435 | /// @param[in] rhs Right-hand side to compare with | ||
436 | /// @return Comparison result | ||
437 | 12 | constexpr bool operator>=(const InsTime_GPSweekTow& rhs) const | |
438 | { | ||
439 |
3/4✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 6 times.
✓ Branch 5 taken 6 times.
|
12 | return *this > rhs || *this == rhs; |
440 | } | ||
441 | /// @brief Smaller comparison operator (takes double precision into account) | ||
442 | /// @param[in] rhs Right-hand side to compare with | ||
443 | /// @return Comparison result | ||
444 | 36 | constexpr bool operator<(const InsTime_GPSweekTow& rhs) const | |
445 | { | ||
446 | 36 | return (gpsCycle < rhs.gpsCycle | |
447 |
4/4✓ Branch 0 taken 26 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 8 times.
|
28 | || (gpsCycle == rhs.gpsCycle && gpsWeek < rhs.gpsWeek) |
448 |
6/6✓ Branch 0 taken 18 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 16 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 8 times.
✓ Branch 5 taken 8 times.
|
20 | || (gpsCycle == rhs.gpsCycle && gpsWeek == rhs.gpsWeek && tow < rhs.tow)) |
449 |
3/4✓ Branch 0 taken 28 times.
✓ Branch 1 taken 8 times.
✓ Branch 3 taken 24 times.
✗ Branch 4 not taken.
|
64 | && *this != rhs; |
450 | } | ||
451 | /// @brief Greater comparison operator (takes double precision into account) | ||
452 | /// @param[in] rhs Right-hand side to compare with | ||
453 | /// @return Comparison result | ||
454 | 18 | constexpr bool operator>(const InsTime_GPSweekTow& rhs) const | |
455 | { | ||
456 | 18 | return !(*this <= rhs); | |
457 | } | ||
458 | |||
459 | /// @brief Converts the object into a readable string | ||
460 | explicit operator std::string() const; | ||
461 | }; | ||
462 | |||
463 | /// Universal Time Coordinated [UTC] | ||
464 | struct InsTime_YMDHMS | ||
465 | { | ||
466 | int32_t year{}; ///< Contains year in Universal Time Coordinated [UTC] | ||
467 | int32_t month{}; ///< Contains month in Universal Time Coordinated [UTC] | ||
468 | int32_t day{}; ///< Contains day in Universal Time Coordinated [UTC] | ||
469 | int32_t hour{}; ///< Contains hour in Universal Time Coordinated [UTC] | ||
470 | int32_t min{}; ///< Contains minute in Universal Time Coordinated [UTC] | ||
471 | long double sec{}; ///< Contains second in Universal Time Coordinated [UTC] | ||
472 | |||
473 | /// @brief Constructor | ||
474 | /// @param[in] year Year in Universal Time Coordinated [UTC] | ||
475 | /// @param[in] month Month in Universal Time Coordinated (1 = January) [UTC] | ||
476 | /// @param[in] day Day in Universal Time Coordinated (1 = first day) [UTC] | ||
477 | /// @param[in] hour Hour in Universal Time Coordinated [UTC] | ||
478 | /// @param[in] min Minute in Universal Time Coordinated [UTC] | ||
479 | /// @param[in] sec Second in Universal Time Coordinated [UTC] | ||
480 | /// @param[in] digits Amount of digits for the seconds to round to | ||
481 | 243730 | constexpr InsTime_YMDHMS(int32_t year, int32_t month, int32_t day, int32_t hour, int32_t min, long double sec, int digits = -1) | |
482 | 243730 | : year(year), month(month), day(day), hour(hour), min(min), sec(sec) | |
483 | { | ||
484 |
2/2✓ Branch 0 taken 2147 times.
✓ Branch 1 taken 241583 times.
|
243730 | if (digits >= 0) { this->sec = math::round(this->sec, static_cast<size_t>(digits)); } |
485 |
2/2✓ Branch 0 taken 62911 times.
✓ Branch 1 taken 180819 times.
|
243730 | if (this->sec >= InsTimeUtil::SECONDS_PER_MINUTE) |
486 | { | ||
487 | 62911 | this->min += static_cast<int32_t>(this->sec / InsTimeUtil::SECONDS_PER_MINUTE); | |
488 | 62911 | this->sec = gcem::fmod(this->sec, InsTimeUtil::SECONDS_PER_MINUTE); | |
489 | } | ||
490 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 243730 times.
|
243730 | while (this->sec < 0.0L) |
491 | { | ||
492 | ✗ | this->sec += InsTimeUtil::SECONDS_PER_MINUTE; | |
493 | ✗ | this->min--; | |
494 | } | ||
495 |
2/2✓ Branch 0 taken 2147 times.
✓ Branch 1 taken 241583 times.
|
243730 | if (digits >= 0) { this->sec = math::round(this->sec, static_cast<size_t>(digits)); } |
496 | |||
497 |
2/2✓ Branch 0 taken 61207 times.
✓ Branch 1 taken 182523 times.
|
243730 | if (this->min >= InsTimeUtil::MINUTES_PER_HOUR) |
498 | { | ||
499 | 61207 | this->hour += this->min / InsTimeUtil::MINUTES_PER_HOUR; | |
500 | 61207 | this->min %= InsTimeUtil::MINUTES_PER_HOUR; | |
501 | } | ||
502 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 243730 times.
|
243730 | while (this->min < 0) |
503 | { | ||
504 | ✗ | this->min += InsTimeUtil::MINUTES_PER_HOUR; | |
505 | ✗ | this->hour--; | |
506 | } | ||
507 | |||
508 |
2/2✓ Branch 0 taken 6409 times.
✓ Branch 1 taken 237321 times.
|
243730 | if (this->hour >= InsTimeUtil::HOURS_PER_DAY) |
509 | { | ||
510 | 6409 | this->day += this->hour / InsTimeUtil::HOURS_PER_DAY; | |
511 | 6409 | this->hour %= InsTimeUtil::HOURS_PER_DAY; | |
512 | } | ||
513 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 243730 times.
|
243730 | while (this->hour < 0) |
514 | { | ||
515 | ✗ | this->hour += InsTimeUtil::HOURS_PER_DAY; | |
516 | ✗ | this->day--; | |
517 | } | ||
518 | |||
519 |
2/2✓ Branch 1 taken 279094 times.
✓ Branch 2 taken 243727 times.
|
522824 | while (this->day >= InsTimeUtil::DAYS_PER_YEAR + static_cast<int32_t>(InsTimeUtil::isLeapYear(this->year))) |
520 | { | ||
521 | 279094 | this->day -= InsTimeUtil::DAYS_PER_YEAR + static_cast<int32_t>(InsTimeUtil::isLeapYear(this->year)); | |
522 | 279094 | this->year++; | |
523 | } | ||
524 | |||
525 |
2/2✓ Branch 1 taken 14 times.
✓ Branch 2 taken 243728 times.
|
243741 | while (this->day > InsTimeUtil::daysInMonth(this->month, this->year)) |
526 | { | ||
527 | 14 | this->day -= InsTimeUtil::daysInMonth(this->month, this->year); | |
528 | 14 | this->month++; | |
529 | } | ||
530 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 243728 times.
|
243730 | while (this->day < 1) |
531 | { | ||
532 | 2 | this->month--; | |
533 | 2 | this->day += InsTimeUtil::daysInMonth(this->month, this->year); | |
534 | } | ||
535 | |||
536 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 243728 times.
|
243734 | while (this->month > InsTimeUtil::MONTHS_PER_YEAR) |
537 | { | ||
538 | 6 | this->month -= InsTimeUtil::MONTHS_PER_YEAR; | |
539 | 6 | this->year++; | |
540 | } | ||
541 |
2/2✓ Branch 0 taken 3006 times.
✓ Branch 1 taken 243728 times.
|
246734 | while (this->month < 1) |
542 | { | ||
543 | 3006 | this->month += InsTimeUtil::MONTHS_PER_YEAR; | |
544 | 3006 | this->year--; | |
545 | } | ||
546 | 243728 | } | |
547 | |||
548 | /// @brief Equal comparison operator (takes double precision into account) | ||
549 | /// @param[in] rhs Right-hand side to compare with | ||
550 | /// @return Comparison result | ||
551 | 162 | constexpr bool operator==(const InsTime_YMDHMS& rhs) const | |
552 | { | ||
553 |
10/10✓ Branch 0 taken 142 times.
✓ Branch 1 taken 20 times.
✓ Branch 2 taken 128 times.
✓ Branch 3 taken 14 times.
✓ Branch 4 taken 114 times.
✓ Branch 5 taken 14 times.
✓ Branch 6 taken 93 times.
✓ Branch 7 taken 21 times.
✓ Branch 8 taken 86 times.
✓ Branch 9 taken 7 times.
|
162 | if (year == rhs.year && month == rhs.month && day == rhs.day && hour == rhs.hour && min == rhs.min) |
554 | { | ||
555 | 86 | return gcem::abs(sec - rhs.sec) <= InsTimeUtil::EPSILON; | |
556 | } | ||
557 |
1/2✓ Branch 1 taken 76 times.
✗ Branch 2 not taken.
|
76 | InsTime_YMDHMS this_plus = InsTime_YMDHMS(this->year, this->month, this->day, this->hour, this->min, this->sec + 10); |
558 |
1/2✓ Branch 1 taken 76 times.
✗ Branch 2 not taken.
|
76 | InsTime_YMDHMS rhs_plus = InsTime_YMDHMS(rhs.year, rhs.month, rhs.day, rhs.hour, rhs.min, rhs.sec + 10); |
559 |
10/10✓ Branch 0 taken 62 times.
✓ Branch 1 taken 14 times.
✓ Branch 2 taken 48 times.
✓ Branch 3 taken 14 times.
✓ Branch 4 taken 34 times.
✓ Branch 5 taken 14 times.
✓ Branch 6 taken 13 times.
✓ Branch 7 taken 21 times.
✓ Branch 8 taken 6 times.
✓ Branch 9 taken 7 times.
|
76 | if (this_plus.year == rhs_plus.year && this_plus.month == rhs_plus.month && this_plus.day == rhs_plus.day && this_plus.hour == rhs_plus.hour && this_plus.min == rhs_plus.min) |
560 | { | ||
561 | 6 | return gcem::abs(this_plus.sec - rhs_plus.sec) <= InsTimeUtil::EPSILON; | |
562 | } | ||
563 | 70 | return false; | |
564 | } | ||
565 | /// @brief Inequal comparison operator (takes double precision into account) | ||
566 | /// @param[in] rhs Right-hand side to compare with | ||
567 | /// @return Comparison result | ||
568 | 73 | constexpr bool operator!=(const InsTime_YMDHMS& rhs) const | |
569 | { | ||
570 | 73 | return !(*this == rhs); | |
571 | } | ||
572 | /// @brief Smaller or equal comparison operator (takes double precision into account) | ||
573 | /// @param[in] rhs Right-hand side to compare with | ||
574 | /// @return Comparison result | ||
575 | 62 | constexpr bool operator<=(const InsTime_YMDHMS& rhs) const | |
576 | { | ||
577 |
3/4✓ Branch 1 taken 26 times.
✓ Branch 2 taken 36 times.
✓ Branch 4 taken 26 times.
✗ Branch 5 not taken.
|
62 | return *this < rhs || *this == rhs; |
578 | } | ||
579 | /// @brief Greater or equal comparison operator (takes double precision into account) | ||
580 | /// @param[in] rhs Right-hand side to compare with | ||
581 | /// @return Comparison result | ||
582 | 25 | constexpr bool operator>=(const InsTime_YMDHMS& rhs) const | |
583 | { | ||
584 |
3/4✓ Branch 1 taken 25 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 13 times.
✓ Branch 5 taken 12 times.
|
25 | return *this > rhs || *this == rhs; |
585 | } | ||
586 | /// @brief Smaller comparison operator (takes double precision into account) | ||
587 | /// @param[in] rhs Right-hand side to compare with | ||
588 | /// @return Comparison result | ||
589 | 74 | constexpr bool operator<(const InsTime_YMDHMS& rhs) const | |
590 | { | ||
591 | 74 | return (year < rhs.year | |
592 |
4/4✓ Branch 0 taken 64 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 56 times.
✓ Branch 3 taken 8 times.
|
66 | || (year == rhs.year && month < rhs.month) |
593 |
5/6✓ Branch 0 taken 56 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 56 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 48 times.
✓ Branch 5 taken 8 times.
|
58 | || (year == rhs.year && month == rhs.month && day < rhs.day) |
594 |
6/8✓ Branch 0 taken 48 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 48 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 48 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 36 times.
✓ Branch 7 taken 12 times.
|
50 | || (year == rhs.year && month == rhs.month && day == rhs.day && hour < rhs.hour) |
595 |
7/10✓ Branch 0 taken 36 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 36 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 36 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 36 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 32 times.
✓ Branch 9 taken 4 times.
|
38 | || (year == rhs.year && month == rhs.month && day == rhs.day && hour == rhs.hour && min < rhs.min) |
596 |
8/12✓ Branch 0 taken 32 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 32 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 32 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 32 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 32 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 8 times.
✓ Branch 11 taken 24 times.
|
34 | || (year == rhs.year && month == rhs.month && day == rhs.day && hour == rhs.hour && min == rhs.min && sec < rhs.sec)) |
597 |
3/4✓ Branch 0 taken 66 times.
✓ Branch 1 taken 8 times.
✓ Branch 3 taken 48 times.
✗ Branch 4 not taken.
|
140 | && *this != rhs; |
598 | } | ||
599 | /// @brief Greater comparison operator (takes double precision into account) | ||
600 | /// @param[in] rhs Right-hand side to compare with | ||
601 | /// @return Comparison result | ||
602 | 37 | constexpr bool operator>(const InsTime_YMDHMS& rhs) const | |
603 | { | ||
604 | 37 | return !(*this <= rhs); | |
605 | } | ||
606 | |||
607 | /// @brief Converts the object into a readable string | ||
608 | explicit operator std::string() const; | ||
609 | }; | ||
610 | |||
611 | /// GPS year and day of year in GPS standard time [GPST] | ||
612 | struct InsTime_YDoySod | ||
613 | { | ||
614 | int32_t year{}; ///< Contains year in GPS standard time [GPST] | ||
615 | int32_t doy{}; ///< Contains day of year in GPS standard time [GPST] | ||
616 | long double sod{}; ///< Contains second of day in GPS standard time [GPST] | ||
617 | |||
618 | /// @brief Constructor | ||
619 | /// @param[in] year Year in GPS standard time [GPST] | ||
620 | /// @param[in] doy Day of year in GPS standard time [1-365(/366)] | ||
621 | /// @param[in] sod Second of day in GPS standard time [GPST] | ||
622 | 7 | constexpr InsTime_YDoySod(int32_t year, int32_t doy, long double sod) | |
623 | 7 | : year(year), doy(doy), sod(sod) | |
624 | { | ||
625 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
|
7 | if (this->sod >= InsTimeUtil::SECONDS_PER_DAY) |
626 | { | ||
627 | ✗ | this->doy += static_cast<int32_t>(this->sod / InsTimeUtil::SECONDS_PER_DAY); | |
628 | ✗ | this->sod = gcem::fmod(this->sod, InsTimeUtil::SECONDS_PER_DAY); | |
629 | } | ||
630 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
|
7 | while (this->sod < 0) |
631 | { | ||
632 | ✗ | this->sod += InsTimeUtil::SECONDS_PER_DAY; | |
633 | ✗ | this->doy--; | |
634 | } | ||
635 | |||
636 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
|
7 | while (this->doy > InsTimeUtil::DAYS_PER_YEAR + static_cast<int32_t>(InsTimeUtil::isLeapYear(this->year))) |
637 | { | ||
638 | ✗ | this->doy -= InsTimeUtil::DAYS_PER_YEAR + static_cast<int32_t>(InsTimeUtil::isLeapYear(this->year)); | |
639 | ✗ | this->year++; | |
640 | } | ||
641 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
|
7 | while (this->doy < 1) |
642 | { | ||
643 | ✗ | this->doy += InsTimeUtil::DAYS_PER_YEAR + static_cast<int32_t>(InsTimeUtil::isLeapYear(this->year - 1)); | |
644 | ✗ | this->year--; | |
645 | } | ||
646 | 7 | } | |
647 | |||
648 | /// @brief Equal comparison operator (takes double precision into account) | ||
649 | /// @param[in] rhs Right-hand side to compare with | ||
650 | /// @return Comparison result | ||
651 | 78 | constexpr bool operator==(const InsTime_YDoySod& rhs) const | |
652 | { | ||
653 |
4/4✓ Branch 0 taken 58 times.
✓ Branch 1 taken 20 times.
✓ Branch 2 taken 44 times.
✓ Branch 3 taken 14 times.
|
78 | if (year == rhs.year && doy == rhs.doy) |
654 | { | ||
655 | 44 | return gcem::abs(sod - rhs.sod) <= InsTimeUtil::EPSILON; | |
656 | } | ||
657 | 68 | if (auto diffDays = year * InsTimeUtil::DAYS_PER_YEAR + doy - (rhs.year * InsTimeUtil::DAYS_PER_YEAR + rhs.doy); | |
658 |
2/2✓ Branch 1 taken 20 times.
✓ Branch 2 taken 14 times.
|
34 | gcem::abs(diffDays) == 1) |
659 | { | ||
660 | 20 | auto difference = gcem::abs(sod + diffDays * InsTimeUtil::SECONDS_PER_DAY - rhs.sod); | |
661 | 20 | return difference <= InsTimeUtil::EPSILON; | |
662 | } | ||
663 | 14 | return false; | |
664 | } | ||
665 | /// @brief Inequal comparison operator (takes double precision into account) | ||
666 | /// @param[in] rhs Right-hand side to compare with | ||
667 | /// @return Comparison result | ||
668 | 36 | constexpr bool operator!=(const InsTime_YDoySod& rhs) const | |
669 | { | ||
670 | 36 | return !(*this == rhs); | |
671 | } | ||
672 | /// @brief Smaller or equal comparison operator (takes double precision into account) | ||
673 | /// @param[in] rhs Right-hand side to compare with | ||
674 | /// @return Comparison result | ||
675 | 30 | constexpr bool operator<=(const InsTime_YDoySod& rhs) const | |
676 | { | ||
677 |
3/4✓ Branch 1 taken 12 times.
✓ Branch 2 taken 18 times.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
|
30 | return *this < rhs || *this == rhs; |
678 | } | ||
679 | /// @brief Greater or equal comparison operator (takes double precision into account) | ||
680 | /// @param[in] rhs Right-hand side to compare with | ||
681 | /// @return Comparison result | ||
682 | 12 | constexpr bool operator>=(const InsTime_YDoySod& rhs) const | |
683 | { | ||
684 |
3/4✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 6 times.
✓ Branch 5 taken 6 times.
|
12 | return *this > rhs || *this == rhs; |
685 | } | ||
686 | /// @brief Smaller comparison operator (takes double precision into account) | ||
687 | /// @param[in] rhs Right-hand side to compare with | ||
688 | /// @return Comparison result | ||
689 | 36 | constexpr bool operator<(const InsTime_YDoySod& rhs) const | |
690 | { | ||
691 | 36 | return (year < rhs.year | |
692 |
4/4✓ Branch 0 taken 26 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 8 times.
|
28 | || (year == rhs.year && doy < rhs.doy) |
693 |
5/6✓ Branch 0 taken 18 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 8 times.
✓ Branch 5 taken 10 times.
|
20 | || (year == rhs.year && doy == rhs.doy && sod < rhs.sod)) |
694 |
3/4✓ Branch 0 taken 28 times.
✓ Branch 1 taken 8 times.
✓ Branch 3 taken 24 times.
✗ Branch 4 not taken.
|
64 | && *this != rhs; |
695 | } | ||
696 | /// @brief Greater comparison operator (takes double precision into account) | ||
697 | /// @param[in] rhs Right-hand side to compare with | ||
698 | /// @return Comparison result | ||
699 | 18 | constexpr bool operator>(const InsTime_YDoySod& rhs) const | |
700 | { | ||
701 | 18 | return !(*this <= rhs); | |
702 | } | ||
703 | |||
704 | /// @brief Converts the object into a readable string | ||
705 | explicit operator std::string() const; | ||
706 | }; | ||
707 | |||
708 | /// The class is responsible for all time-related tasks | ||
709 | class InsTime | ||
710 | { | ||
711 | public: | ||
712 | /* ------------------------------ Constructors ------------------------------ */ | ||
713 | |||
714 | /// @brief Default Constructor | ||
715 | 477042 | constexpr InsTime() = default; | |
716 | |||
717 | /// @brief Constructor | ||
718 | /// @param[in] mjd Time in Modified Julien Date | ||
719 | /// @param[in] timesys Time System in which the previous values are given in | ||
720 | 31 | constexpr explicit InsTime(const InsTime_MJD& mjd, TimeSystem timesys = UTC) | |
721 | 31 | : _mjd(mjd) | |
722 | { | ||
723 |
2/4✓ Branch 1 taken 31 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 31 times.
✗ Branch 6 not taken.
|
31 | *this -= std::chrono::duration<long double>(differenceToUTC(timesys)); |
724 | 31 | } | |
725 | |||
726 | /// @brief Constructor | ||
727 | /// @param[in] jd Time in Julien Date | ||
728 | /// @param[in] timesys Time System in which the previous values are given in | ||
729 | 193538 | constexpr explicit InsTime(const InsTime_JD& jd, TimeSystem timesys = UTC) | |
730 | 193538 | : _mjd(jd.jd_day - InsTimeUtil::DIFF_MJD_TO_JD_DAYS, jd.jd_frac - InsTimeUtil::DIFF_MJD_TO_JD_FRAC) | |
731 | { | ||
732 |
2/4✓ Branch 1 taken 193526 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 193526 times.
✗ Branch 6 not taken.
|
193532 | *this -= std::chrono::duration<long double>(differenceToUTC(timesys)); |
733 | 193526 | } | |
734 | |||
735 | /// @brief Constructor | ||
736 | /// @param[in] gpsWeekTow Time as week and time of week | ||
737 | /// @param[in] timesys Time System in which the previous values are given in | ||
738 | 101618 | constexpr explicit InsTime(const InsTime_GPSweekTow& gpsWeekTow, TimeSystem timesys = GPST) | |
739 | 101618 | { | |
740 | 101602 | auto mjd_day = static_cast<int32_t>((gpsWeekTow.gpsCycle * InsTimeUtil::WEEKS_PER_GPS_CYCLE + gpsWeekTow.gpsWeek) * InsTimeUtil::DAYS_PER_WEEK | |
741 | 101602 | + gcem::floor(gpsWeekTow.tow / InsTimeUtil::SECONDS_PER_DAY) | |
742 | 101583 | + InsTimeUtil::DIFF_TO_6_1_1980_MJD); | |
743 | 101583 | long double mjd_frac = gcem::fmod(gpsWeekTow.tow, InsTimeUtil::SECONDS_PER_DAY) / InsTimeUtil::SECONDS_PER_DAY; | |
744 | |||
745 | 101598 | _mjd = InsTime_MJD(mjd_day, mjd_frac); | |
746 | |||
747 |
2/4✓ Branch 1 taken 101555 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 101531 times.
✗ Branch 6 not taken.
|
101598 | *this -= std::chrono::duration<long double>(differenceToUTC(timesys)); |
748 | 101531 | } | |
749 | |||
750 | /// @brief Constructor | ||
751 | /// @param[in] yearMonthDayHMS Time in Universal Time Coordinated | ||
752 | /// @param[in] timesys Time System in which the previous values are given in | ||
753 | 193520 | constexpr explicit InsTime(const InsTime_YMDHMS& yearMonthDayHMS, TimeSystem timesys = UTC) | |
754 | 193520 | { | |
755 | 193504 | auto a = static_cast<int32_t>((14 - yearMonthDayHMS.month) / static_cast<double>(InsTimeUtil::MONTHS_PER_YEAR)); | |
756 | 193504 | int32_t y = yearMonthDayHMS.year + 4800 - a; | |
757 | 193504 | int32_t m = yearMonthDayHMS.month + InsTimeUtil::MONTHS_PER_YEAR * a - 3; | |
758 | |||
759 | 193504 | auto jd_day = static_cast<int32_t>(yearMonthDayHMS.day | |
760 | 193504 | + gcem::floor((153.0 * static_cast<double>(m) + 2.0) / 5.0) | |
761 | 193501 | + y * InsTimeUtil::DAYS_PER_YEAR | |
762 | 193501 | + gcem::floor(static_cast<double>(y) / 4.0) | |
763 | 193519 | - gcem::floor(static_cast<double>(y) / 100.0) | |
764 | 193519 | + gcem::floor(static_cast<double>(y) / 400.0) | |
765 | 193524 | - 32045); | |
766 | 193524 | auto jd_frac = (yearMonthDayHMS.sec | |
767 | 193524 | + static_cast<long double>(yearMonthDayHMS.min) * InsTimeUtil::SECONDS_PER_MINUTE | |
768 | 193524 | + static_cast<long double>(yearMonthDayHMS.hour - 12.0) * InsTimeUtil::SECONDS_PER_HOUR) | |
769 | / InsTimeUtil::SECONDS_PER_DAY; | ||
770 | |||
771 |
2/4✓ Branch 3 taken 193508 times.
✗ Branch 4 not taken.
✓ Branch 7 taken 193523 times.
✗ Branch 8 not taken.
|
193524 | _mjd = InsTime(InsTime_JD(jd_day, jd_frac)).toMJD(); |
772 | |||
773 |
2/4✓ Branch 1 taken 193523 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 193524 times.
✗ Branch 6 not taken.
|
193523 | *this -= std::chrono::duration<long double>(differenceToUTC(timesys)); |
774 | 193524 | } | |
775 | |||
776 | /// @brief Constructor | ||
777 | /// @param[in] yearDoySod Time as Year, day of year and seconds of day | ||
778 | /// @param[in] timesys Time System in which the previous values are given in | ||
779 | 28 | constexpr explicit InsTime(const InsTime_YDoySod& yearDoySod, TimeSystem timesys = UTC) | |
780 | 28 | { | |
781 | 28 | auto year = yearDoySod.year; | |
782 | 28 | auto doy = yearDoySod.doy; | |
783 | 28 | auto sod = yearDoySod.sod; | |
784 | |||
785 | 28 | int32_t month = 1; | |
786 |
2/2✓ Branch 1 taken 34 times.
✓ Branch 2 taken 28 times.
|
62 | while (doy > InsTimeUtil::daysInMonth(month, year)) |
787 | { | ||
788 | 34 | doy -= InsTimeUtil::daysInMonth(month, year); | |
789 | 34 | month++; | |
790 | } | ||
791 | |||
792 |
3/6✓ Branch 2 taken 28 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 28 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 28 times.
✗ Branch 10 not taken.
|
28 | _mjd = InsTime(InsTime_YMDHMS(year, month, doy, 0, 0, sod)).toMJD(); |
793 | |||
794 |
2/4✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 28 times.
✗ Branch 6 not taken.
|
28 | *this -= std::chrono::duration<long double>(differenceToUTC(timesys)); |
795 | 28 | } | |
796 | |||
797 | /// @brief Constructor | ||
798 | /// @param[in] gpsCycle GPS cycle in GPS standard time | ||
799 | /// @param[in] gpsWeek GPS week in GPS standard time | ||
800 | /// @param[in] tow GPS time of week in GPS standard time | ||
801 | /// @param[in] timesys Time System in which the previous values are given in | ||
802 | 73101 | constexpr InsTime(int32_t gpsCycle, int32_t gpsWeek, long double tow, TimeSystem timesys = GPST) | |
803 |
1/2✓ Branch 2 taken 73103 times.
✗ Branch 3 not taken.
|
73101 | : InsTime(InsTime_GPSweekTow(gpsCycle, gpsWeek, tow), timesys) {} |
804 | |||
805 | /// @brief Constructor | ||
806 | /// @param[in] year Year | ||
807 | /// @param[in] month Month (1 = January) | ||
808 | /// @param[in] day Day (1 = first day) | ||
809 | /// @param[in] hour Hour | ||
810 | /// @param[in] min Minute | ||
811 | /// @param[in] sec Second | ||
812 | /// @param[in] timesys Time System in which the previous values are given in | ||
813 | 193452 | constexpr InsTime(int32_t year, int32_t month, int32_t day, int32_t hour, int32_t min, long double sec, TimeSystem timesys = UTC) | |
814 |
2/4✓ Branch 1 taken 193448 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 193456 times.
✗ Branch 5 not taken.
|
193452 | : InsTime(InsTime_YMDHMS(year, month, day, hour, min, sec), timesys) {} |
815 | |||
816 | /// @brief Destructor | ||
817 | ~InsTime() = default; | ||
818 | /// @brief Copy constructor | ||
819 | constexpr InsTime(const InsTime&) = default; | ||
820 | /// @brief Move constructor | ||
821 | constexpr InsTime(InsTime&&) = default; | ||
822 | /// @brief Copy assignment operator | ||
823 | constexpr InsTime& operator=(const InsTime&) = default; | ||
824 | /// @brief Move assignment operator | ||
825 | constexpr InsTime& operator=(InsTime&&) = default; | ||
826 | |||
827 | /* ------------------------ Transformation functions ------------------------ */ | ||
828 | |||
829 | /// @brief Converts this time object into a different format | ||
830 | /// @param timesys Time System in which the time should be given | ||
831 | /// @return InsTime_MJD structure of the this object | ||
832 | 223960 | [[nodiscard]] constexpr InsTime_MJD toMJD(TimeSystem timesys = UTC) const | |
833 | { | ||
834 | 223960 | long double mjdFrac = _mjd.mjd_frac + static_cast<long double>(differenceToUTC(timesys)) / static_cast<long double>(InsTimeUtil::SECONDS_PER_DAY); | |
835 | 223970 | return { _mjd.mjd_day, mjdFrac }; | |
836 | } | ||
837 | |||
838 | /// @brief Converts this time object into a different format | ||
839 | /// @param timesys Time System in which the time should be given | ||
840 | /// @return InsTime_JD structure of the this object | ||
841 | 50098 | [[nodiscard]] constexpr InsTime_JD toJD(TimeSystem timesys = UTC) const | |
842 | { | ||
843 | 50098 | auto jd_day = _mjd.mjd_day + InsTimeUtil::DIFF_MJD_TO_JD_DAYS; | |
844 | 50098 | auto jd_frac = _mjd.mjd_frac + InsTimeUtil::DIFF_MJD_TO_JD_FRAC; | |
845 | |||
846 | 50098 | jd_frac += static_cast<long double>(differenceToUTC(timesys)) / static_cast<long double>(InsTimeUtil::SECONDS_PER_DAY); | |
847 | |||
848 | 50098 | return { jd_day, jd_frac }; | |
849 | } | ||
850 | |||
851 | /// @brief Converts this time object into a different format | ||
852 | /// @param timesys Time System in which the time should be given | ||
853 | /// @return InsTime_GPSweekTow structure of the this object | ||
854 | 122655 | [[nodiscard]] constexpr InsTime_GPSweekTow toGPSweekTow(TimeSystem timesys = GPST) const | |
855 | { | ||
856 | 122655 | InsTime_MJD mjd_leap = _mjd; | |
857 | // Convert from UTC to intended time system | ||
858 |
1/2✓ Branch 1 taken 122655 times.
✗ Branch 2 not taken.
|
122655 | mjd_leap.mjd_frac += static_cast<long double>(differenceToUTC(timesys)) / static_cast<long double>(InsTimeUtil::SECONDS_PER_DAY); |
859 | |||
860 | // Put everything in the time of week, as it gets splitted in InsTime_GPSweekTow constructor | ||
861 | 122655 | auto tow = static_cast<long double>((mjd_leap.mjd_day - InsTimeUtil::DIFF_TO_6_1_1980_MJD)) * InsTimeUtil::SECONDS_PER_DAY | |
862 | 122655 | + mjd_leap.mjd_frac * InsTimeUtil::SECONDS_PER_DAY; | |
863 | |||
864 | 245310 | return { 0, 0, tow }; | |
865 | } | ||
866 | |||
867 | /// @brief Converts this time object into a different format | ||
868 | /// @param timesys Time System in which the time should be given | ||
869 | /// @param digits Amount of digits for the seconds to round to | ||
870 | /// @return InsTime_YMDHMS structure of the this object | ||
871 | 50095 | [[nodiscard]] constexpr InsTime_YMDHMS toYMDHMS(TimeSystem timesys = UTC, int digits = -1) const | |
872 | { | ||
873 | // transform MJD to JD | ||
874 |
1/2✓ Branch 2 taken 50095 times.
✗ Branch 3 not taken.
|
50095 | InsTime_JD jd = toJD(); |
875 | 50095 | jd.jd_frac = jd.jd_frac + 0.5L; | |
876 |
1/2✓ Branch 1 taken 50095 times.
✗ Branch 2 not taken.
|
50095 | jd.jd_frac += static_cast<long double>(differenceToUTC(timesys)) / static_cast<long double>(InsTimeUtil::SECONDS_PER_DAY); |
877 |
2/2✓ Branch 0 taken 29000 times.
✓ Branch 1 taken 21095 times.
|
50095 | if (jd.jd_frac >= 1.0L) |
878 | { | ||
879 | 29000 | jd.jd_day += static_cast<int32_t>(jd.jd_frac); | |
880 | 29000 | jd.jd_frac -= gcem::floor(jd.jd_frac); | |
881 | } | ||
882 | // transform JD to YMDHMS | ||
883 | 50095 | double a = 32044.0 + jd.jd_day; | |
884 | 50095 | double b = gcem::floor((4.0 * a + 3.0) / 146097.0); | |
885 | 50095 | double c = a - gcem::floor((b * 146097.0) / 4.0); | |
886 | |||
887 | 50095 | double d = gcem::floor((4.0 * c + 3.0) / 1461.0); | |
888 | 50095 | double e = c - gcem::floor((1461.0 * d) / 4.0); | |
889 | 50095 | double m = gcem::floor((5.0 * e + 2.0) / 153.0); | |
890 | |||
891 | 50095 | auto day = static_cast<uint16_t>(e - gcem::floor((153.0 * m + 2.0) / 5.0) + 1); | |
892 | 50095 | auto month = static_cast<uint16_t>(m + 3 - 12 * gcem::floor(m / 10.0)); | |
893 | 50095 | auto year = static_cast<uint16_t>(b * 100 + d - 4800.0 + gcem::floor(m / 10.0)); | |
894 | |||
895 | 50095 | long double sec = jd.jd_frac * InsTimeUtil::SECONDS_PER_DAY; | |
896 | |||
897 |
1/2✓ Branch 1 taken 50095 times.
✗ Branch 2 not taken.
|
100190 | return { year, month, day, 0, 0, sec, digits }; |
898 | } | ||
899 | |||
900 | /// @brief Converts this time object into a different format | ||
901 | /// @param timesys Time System in which the time should be given | ||
902 | /// @return InsTime_YDoySod structure of the this object | ||
903 | 4 | [[nodiscard]] constexpr InsTime_YDoySod toYDoySod(TimeSystem timesys = UTC) const | |
904 | { | ||
905 |
1/2✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
|
4 | InsTime_YMDHMS yearMonthDayHMS = toYMDHMS(); |
906 | |||
907 | 4 | auto year = yearMonthDayHMS.year; | |
908 | 4 | long double sod = static_cast<long double>(yearMonthDayHMS.hour * InsTimeUtil::SECONDS_PER_HOUR | |
909 | 4 | + yearMonthDayHMS.min * InsTimeUtil::SECONDS_PER_MINUTE) | |
910 | 4 | + yearMonthDayHMS.sec | |
911 |
1/2✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 | + static_cast<long double>(differenceToUTC(timesys)); |
912 | |||
913 | 4 | int32_t doy = 0; | |
914 |
2/2✓ Branch 0 taken 14 times.
✓ Branch 1 taken 4 times.
|
18 | for (int32_t i = 1; i < yearMonthDayHMS.month; i++) |
915 | { | ||
916 | 14 | doy += InsTimeUtil::daysInMonth(i, year); | |
917 | } | ||
918 | 4 | doy += yearMonthDayHMS.day; | |
919 | |||
920 | 8 | return { year, doy, sod }; | |
921 | } | ||
922 | |||
923 | /// @brief Returns the current time rounded/cutted to a full day (changes time to 0:0:0h UTC of current day) | ||
924 | /// @return The rounded/cutted time object | ||
925 | [[nodiscard]] constexpr InsTime toFullDay() const | ||
926 | { | ||
927 | return InsTime(InsTime_MJD(_mjd.mjd_day, 0.0L)); | ||
928 | } | ||
929 | |||
930 | /// @brief Converts this time object into a UNIX timestamp in [s] | ||
931 | /// @attention Do not pass `long double` to the LOG_... functions, it can loop indefinitely | ||
932 | 4 | [[nodiscard]] constexpr long double toUnixTime() const | |
933 | { | ||
934 | 4 | return static_cast<long double>((_mjd.mjd_day - InsTimeUtil::DIFF_TO_1_1_1970_MJD) * InsTimeUtil::SECONDS_PER_DAY) | |
935 | 4 | + _mjd.mjd_frac * InsTimeUtil::SECONDS_PER_DAY; | |
936 | } | ||
937 | |||
938 | /* ----------------------------- Leap functions ----------------------------- */ | ||
939 | |||
940 | /// @brief Returns the current number of leap seconds (offset GPST to UTC) | ||
941 | /// @return Number of leap seconds | ||
942 | 454067 | [[nodiscard]] constexpr uint16_t leapGps2UTC() const | |
943 | { | ||
944 | 454067 | return leapGps2UTC(_mjd); | |
945 | } | ||
946 | |||
947 | /// @brief Returns the number of leap seconds (offset GPST to UTC) for the provided InsTime object | ||
948 | /// @param[in] insTime Time point | ||
949 | /// @return Number of leap seconds | ||
950 | 7 | static constexpr uint16_t leapGps2UTC(const InsTime& insTime) | |
951 | { | ||
952 | 7 | return leapGps2UTC(insTime._mjd); | |
953 | } | ||
954 | |||
955 | /// @brief Returns the number of leap seconds (offset GPST to UTC) for the provided InsTime_GPSweekTow object | ||
956 | /// @param[in] gpsWeekTow Time point | ||
957 | /// @return Number of leap seconds | ||
958 | 1 | static constexpr uint16_t leapGps2UTC(const InsTime_GPSweekTow& gpsWeekTow) | |
959 | { | ||
960 |
3/6✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 1 times.
✗ Branch 10 not taken.
|
1 | return leapGps2UTC(InsTime(gpsWeekTow).toMJD()); |
961 | } | ||
962 | |||
963 | /// @brief Returns the number of leap seconds (offset GPST to UTC) for the provided InsTime_YDoySod object | ||
964 | /// @param[in] yearDoySod Time point | ||
965 | /// @return Number of leap seconds | ||
966 | 1 | static constexpr uint16_t leapGps2UTC(const InsTime_YDoySod& yearDoySod) | |
967 | { | ||
968 |
3/6✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 1 times.
✗ Branch 10 not taken.
|
1 | return leapGps2UTC(InsTime(yearDoySod).toMJD()); |
969 | } | ||
970 | |||
971 | /// @brief Returns the number of leap seconds (offset GPST to UTC) for the provided InsTime_YMDHMS object | ||
972 | /// @param[in] yearMonthDayHMS Time point | ||
973 | /// @return Number of leap seconds | ||
974 | 1 | static constexpr uint16_t leapGps2UTC(const InsTime_YMDHMS& yearMonthDayHMS) | |
975 | { | ||
976 |
3/6✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 1 times.
✗ Branch 10 not taken.
|
1 | return leapGps2UTC(InsTime(yearMonthDayHMS).toMJD()); |
977 | } | ||
978 | |||
979 | /// @brief Returns the number of leap seconds (offset GPST to UTC) for the provided InsTime_JD object | ||
980 | /// @param[in] jd Time point | ||
981 | /// @return Number of leap seconds | ||
982 | 1 | static constexpr uint16_t leapGps2UTC(const InsTime_JD& jd) | |
983 | { | ||
984 |
3/6✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 1 times.
✗ Branch 10 not taken.
|
1 | return leapGps2UTC(InsTime(jd).toMJD()); |
985 | } | ||
986 | |||
987 | /// @brief Returns the number of leap seconds (offset GPST to UTC) for the provided InsTime_MJD object | ||
988 | /// @param[in] mjd_in Time point | ||
989 | /// @return Number of leap seconds | ||
990 | 454065 | static constexpr uint16_t leapGps2UTC(const InsTime_MJD& mjd_in) | |
991 | { | ||
992 | 454065 | return static_cast<uint16_t>(std::ranges::upper_bound(InsTimeUtil::GPS_LEAP_SEC_MJD, mjd_in.mjd_day) - InsTimeUtil::GPS_LEAP_SEC_MJD.begin() - 1); | |
993 | } | ||
994 | |||
995 | /// @brief Checks if the current time is a leap year | ||
996 | /// @return True if the current time is a leap year, false otherwise | ||
997 | 1 | [[nodiscard]] constexpr bool isLeapYear() const | |
998 | { | ||
999 |
1/2✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | return InsTimeUtil::isLeapYear(toYMDHMS().year); |
1000 | } | ||
1001 | |||
1002 | /* --------------------- Comparison operator overloading -------------------- */ | ||
1003 | |||
1004 | /// @brief Equal comparison operator (takes double precision into account) | ||
1005 | /// @param[in] rhs Right-hand side to compare with | ||
1006 | /// @return Comparison result | ||
1007 | 7149291 | constexpr bool operator==(const InsTime& rhs) const { return _mjd == rhs._mjd; } | |
1008 | /// @brief Inequal comparison operator (takes double precision into account) | ||
1009 | /// @param[in] rhs Right-hand side to compare with | ||
1010 | /// @return Comparison result | ||
1011 | 56 | constexpr bool operator!=(const InsTime& rhs) const { return !(*this == rhs); } | |
1012 | /// @brief Smaller or equal comparison operator (takes double precision into account) | ||
1013 | /// @param[in] rhs Right-hand side to compare with | ||
1014 | /// @return Comparison result | ||
1015 |
4/4✓ Branch 1 taken 10266 times.
✓ Branch 2 taken 24627 times.
✓ Branch 4 taken 10072 times.
✓ Branch 5 taken 194 times.
|
34893 | constexpr bool operator<=(const InsTime& rhs) const { return *this < rhs || *this == rhs; } |
1016 | /// @brief Greater or equal comparison operator (takes double precision into account) | ||
1017 | /// @param[in] rhs Right-hand side to compare with | ||
1018 | /// @return Comparison result | ||
1019 |
4/4✓ Branch 1 taken 67 times.
✓ Branch 2 taken 141 times.
✓ Branch 4 taken 16 times.
✓ Branch 5 taken 51 times.
|
208 | constexpr bool operator>=(const InsTime& rhs) const { return *this > rhs || *this == rhs; } |
1020 | /// @brief Smaller comparison operator (takes double precision into account) | ||
1021 | /// @param[in] rhs Right-hand side to compare with | ||
1022 | /// @return Comparison result | ||
1023 | 1059384 | constexpr bool operator<(const InsTime& rhs) const { return _mjd < rhs._mjd; } | |
1024 | /// @brief Greater comparison operator (takes double precision into account) | ||
1025 | /// @param[in] rhs Right-hand side to compare with | ||
1026 | /// @return Comparison result | ||
1027 | 27568 | constexpr bool operator>(const InsTime& rhs) const { return !(*this <= rhs); } | |
1028 | |||
1029 | /* --------------------- Arithmetic operator overloading -------------------- */ | ||
1030 | |||
1031 | /// @brief Substracts 2 points in time | ||
1032 | /// @param[in] lhs The left hand side time point | ||
1033 | /// @param[in] rhs The right hand side time point | ||
1034 | /// @return Time difference in [seconds] | ||
1035 | 1584867 | constexpr friend std::chrono::duration<long double> operator-(const InsTime& lhs, const InsTime& rhs) | |
1036 | { | ||
1037 | 1584867 | auto diffDays = lhs._mjd.mjd_day - rhs._mjd.mjd_day; | |
1038 | 1584867 | auto diffFrac = lhs._mjd.mjd_frac - rhs._mjd.mjd_frac; | |
1039 | 1584867 | long double diffSec = (diffFrac + static_cast<long double>(diffDays)) * InsTimeUtil::SECONDS_PER_DAY; | |
1040 | 1584867 | return std::chrono::duration<long double>(diffSec); | |
1041 | } | ||
1042 | |||
1043 | /// @brief Adds a duration to this time point | ||
1044 | /// @param[in] duration The duration to add | ||
1045 | /// @return Reference to this object | ||
1046 | 141062 | constexpr InsTime& operator+=(const std::chrono::duration<long double>& duration) | |
1047 | { | ||
1048 |
1/2✓ Branch 1 taken 141066 times.
✗ Branch 2 not taken.
|
141062 | auto duration_mjd_frac = std::chrono::duration<long double, std::ratio<InsTimeUtil::SECONDS_PER_DAY>>(duration).count(); |
1049 | 282127 | this->_mjd = InsTime_MJD(this->_mjd.mjd_day, | |
1050 | 141055 | this->_mjd.mjd_frac + duration_mjd_frac); | |
1051 | 141072 | return *this; | |
1052 | } | ||
1053 | |||
1054 | /// @brief Substracts a duration to this time point | ||
1055 | /// @param[in] duration The duration to substract | ||
1056 | /// @return Reference to this object | ||
1057 | 633035 | constexpr InsTime& operator-=(const std::chrono::duration<long double>& duration) | |
1058 | { | ||
1059 |
1/2✓ Branch 1 taken 633025 times.
✗ Branch 2 not taken.
|
633035 | auto duration_mjd_frac = std::chrono::duration<long double, std::ratio<InsTimeUtil::SECONDS_PER_DAY>>(duration).count(); |
1060 | 1265988 | this->_mjd = InsTime_MJD(this->_mjd.mjd_day, | |
1061 | 632961 | this->_mjd.mjd_frac - duration_mjd_frac); | |
1062 | 633027 | return *this; | |
1063 | } | ||
1064 | |||
1065 | /// @brief Adds a duration to a time point | ||
1066 | /// @param[in] time The left hand side time point | ||
1067 | /// @param[in] duration The right hand side duration | ||
1068 | /// @return Time point with the added duration | ||
1069 | 140101 | constexpr friend InsTime operator+(const InsTime& time, const std::chrono::duration<long double>& duration) | |
1070 | { | ||
1071 |
1/2✓ Branch 1 taken 140106 times.
✗ Branch 2 not taken.
|
140101 | return InsTime(time) += duration; |
1072 | } | ||
1073 | |||
1074 | /// @brief Substracts a duration from a time point | ||
1075 | /// @param[in] time The left hand side time point | ||
1076 | /// @param[in] duration The right hand side duration | ||
1077 | /// @return Time point with the substracted duration | ||
1078 | 144362 | constexpr friend InsTime operator-(const InsTime& time, const std::chrono::duration<long double>& duration) | |
1079 | { | ||
1080 |
1/2✓ Branch 1 taken 144362 times.
✗ Branch 2 not taken.
|
144362 | return InsTime(time) -= duration; |
1081 | } | ||
1082 | |||
1083 | /* ---------------------------- Utility Functions --------------------------- */ | ||
1084 | |||
1085 | /// @brief Converts the object into a readable string | ||
1086 | explicit operator std::string() const; | ||
1087 | |||
1088 | /// @brief Checks if the Time object has a value | ||
1089 | 2580780 | [[nodiscard]] constexpr bool empty() const | |
1090 | { | ||
1091 |
4/4✓ Branch 0 taken 477082 times.
✓ Branch 1 taken 2103698 times.
✓ Branch 2 taken 477068 times.
✓ Branch 3 taken 14 times.
|
2580780 | return _mjd.mjd_day == 0 && _mjd.mjd_frac == 0.0L; |
1092 | } | ||
1093 | |||
1094 | /// @brief Resets the InsTime object | ||
1095 | 220412 | void reset() | |
1096 | { | ||
1097 | 220412 | _mjd.mjd_day = 0; | |
1098 | 220412 | _mjd.mjd_frac = 0.0L; | |
1099 | 220412 | } | |
1100 | |||
1101 | /// @brief Adds the difference [seconds] between toe (OBRIT-0 last element) and toc (ORBIT-0 first element) to the current time | ||
1102 | /// (Changes time, so that it corresponds to the time of GLONASS ORBIT last element) | ||
1103 | /// @param[in] UTC_sec Seconds in UTC time | ||
1104 | void MakeTimeFromGloOrbit(double UTC_sec) | ||
1105 | { | ||
1106 | auto ymdhms = toYMDHMS(); | ||
1107 | // difference between toe (OBRIT-0 last element) and toc (ORBIT-0 first element) in seconds | ||
1108 | long double diff = gcem::fmod(static_cast<long double>(UTC_sec), InsTimeUtil::SECONDS_PER_DAY) | ||
1109 | - (ymdhms.hour * InsTimeUtil::SECONDS_PER_HOUR | ||
1110 | + ymdhms.min * InsTimeUtil::SECONDS_PER_MINUTE | ||
1111 | + ymdhms.sec); | ||
1112 | // std::cout << "orbit diff " << diff << "\n"; | ||
1113 | *this += std::chrono::duration<long double>(diff); | ||
1114 | } | ||
1115 | |||
1116 | /// @brief Returns the time difference in [s] of a time system and UTC | ||
1117 | /// @param[in] timesys Time system to get the difference from UTC | ||
1118 | 935618 | [[nodiscard]] constexpr int differenceToUTC(TimeSystem timesys) const | |
1119 | { | ||
1120 |
7/8✓ Branch 1 taken 392820 times.
✓ Branch 2 taken 17 times.
✓ Branch 3 taken 23230 times.
✓ Branch 4 taken 2220 times.
✓ Branch 5 taken 54 times.
✓ Branch 6 taken 20461 times.
✓ Branch 7 taken 496795 times.
✗ Branch 8 not taken.
|
935618 | switch (TimeSystem_(timesys)) |
1121 | { | ||
1122 | 392820 | case GPST: // = GPS Time (UTC + leap_seconds) | |
1123 | 392820 | return this->leapGps2UTC(); | |
1124 | 17 | case GLNT: // = GLONASS Time (UTC+ 3h) | |
1125 | 17 | return 3 * InsTimeUtil::SECONDS_PER_HOUR; | |
1126 | 23230 | case GST: // = GALILEO Time (~ GPS) (UTC = GST - 18) is synchronized with TAI with a nominal offset below 50 ns | |
1127 | 23230 | return this->leapGps2UTC(); | |
1128 | 2220 | case QZSST: | |
1129 | 2220 | return this->leapGps2UTC(); // TODO citation for synchronization accuracy | |
1130 | 54 | case IRNSST: | |
1131 | 54 | return this->leapGps2UTC(); // TODO citation for synchronization accuracy | |
1132 | 20461 | case BDT: // = BeiDou Time (UTC) is synchronized with UTC within 100 ns< | |
1133 | 20461 | return this->leapGps2UTC() - 14; | |
1134 | 496795 | case UTC: | |
1135 | case TimeSys_None: | ||
1136 | 496795 | return 0; | |
1137 | } | ||
1138 | ✗ | return 0; | |
1139 | } | ||
1140 | |||
1141 | private: | ||
1142 | /// @brief Modified Julien Date of this InsTime object | ||
1143 | InsTime_MJD _mjd; | ||
1144 | }; | ||
1145 | |||
1146 | /// @brief Stream insertion operator overload | ||
1147 | /// @param[in, out] os Output stream object to stream the time into | ||
1148 | /// @param[in] mjd Object to print | ||
1149 | /// @return Returns the output stream object in order to chain stream insertions | ||
1150 | std::ostream& operator<<(std::ostream& os, const InsTime_MJD& mjd); | ||
1151 | /// @brief Stream insertion operator overload | ||
1152 | /// @param[in, out] os Output stream object to stream the time into | ||
1153 | /// @param[in] jd Object to print | ||
1154 | /// @return Returns the output stream object in order to chain stream insertions | ||
1155 | std::ostream& operator<<(std::ostream& os, const InsTime_JD& jd); | ||
1156 | /// @brief Stream insertion operator overload | ||
1157 | /// @param[in, out] os Output stream object to stream the time into | ||
1158 | /// @param[in] gpsWeekTow Object to print | ||
1159 | /// @return Returns the output stream object in order to chain stream insertions | ||
1160 | std::ostream& operator<<(std::ostream& os, const InsTime_GPSweekTow& gpsWeekTow); | ||
1161 | /// @brief Stream insertion operator overload | ||
1162 | /// @param[in, out] os Output stream object to stream the time into | ||
1163 | /// @param[in] ymdhms Object to print | ||
1164 | /// @return Returns the output stream object in order to chain stream insertions | ||
1165 | std::ostream& operator<<(std::ostream& os, const InsTime_YMDHMS& ymdhms); | ||
1166 | /// @brief Stream insertion operator overload | ||
1167 | /// @param[in, out] os Output stream object to stream the time into | ||
1168 | /// @param[in] yDoySod Object to print | ||
1169 | /// @return Returns the output stream object in order to chain stream insertions | ||
1170 | std::ostream& operator<<(std::ostream& os, const InsTime_YDoySod& yDoySod); | ||
1171 | /// @brief Stream insertion operator overload | ||
1172 | /// @param[in, out] os Output stream object to stream the time into | ||
1173 | /// @param[in] insTime Object to print | ||
1174 | /// @return Returns the output stream object in order to chain stream insertions | ||
1175 | std::ostream& operator<<(std::ostream& os, const InsTime& insTime); | ||
1176 | |||
1177 | /// @brief Converts the provided InsTime into a json object | ||
1178 | /// @param[out] j Return Json object | ||
1179 | /// @param[in] insTime Time to convert | ||
1180 | void to_json(json& j, const InsTime& insTime); | ||
1181 | /// @brief Converts the provided json object into an InsTime | ||
1182 | /// @param[in] j Json object with the time values | ||
1183 | /// @param[out] insTime Time to return | ||
1184 | void from_json(const json& j, InsTime& insTime); | ||
1185 | |||
1186 | } // namespace NAV | ||
1187 | |||
1188 | namespace std | ||
1189 | { | ||
1190 | /// @brief Hash function for InsTime (needed for unordered_map) | ||
1191 | template<> | ||
1192 | struct hash<NAV::InsTime> | ||
1193 | { | ||
1194 | /// @brief Hash function for InsTime | ||
1195 | /// @param[in] t Time | ||
1196 | std::size_t operator()(const NAV::InsTime& t) const | ||
1197 | { | ||
1198 | auto hash1 = std::hash<int32_t>{}(t.toMJD().mjd_day); | ||
1199 | auto hash2 = std::hash<long double>{}(t.toMJD().mjd_frac); | ||
1200 | |||
1201 | return hash1 | (hash2 << 32); | ||
1202 | } | ||
1203 | }; | ||
1204 | } // namespace std | ||
1205 | |||
1206 | #ifndef DOXYGEN_IGNORE | ||
1207 | |||
1208 | /// @brief Formatter | ||
1209 | template<> | ||
1210 | struct fmt::formatter<NAV::InsTime_MJD> : fmt::formatter<std::string> | ||
1211 | { | ||
1212 | /// @brief Defines how to format this structs | ||
1213 | /// @param[in] mjd Struct to format | ||
1214 | /// @param[in, out] ctx Format context | ||
1215 | /// @return Output iterator | ||
1216 | template<typename FormatContext> | ||
1217 | ✗ | auto format(const NAV::InsTime_MJD& mjd, FormatContext& ctx) const | |
1218 | { | ||
1219 | ✗ | return fmt::format_to(ctx.out(), "day={}, frac={}", mjd.mjd_day, static_cast<double>(mjd.mjd_frac)); | |
1220 | } | ||
1221 | }; | ||
1222 | /// @brief Formatter | ||
1223 | template<> | ||
1224 | struct fmt::formatter<NAV::InsTime_JD> : fmt::formatter<std::string> | ||
1225 | { | ||
1226 | /// @brief Defines how to format this structs | ||
1227 | /// @param[in] jd Struct to format | ||
1228 | /// @param[in, out] ctx Format context | ||
1229 | /// @return Output iterator | ||
1230 | template<typename FormatContext> | ||
1231 | ✗ | auto format(const NAV::InsTime_JD& jd, FormatContext& ctx) const | |
1232 | { | ||
1233 | ✗ | return fmt::format_to(ctx.out(), "day={}, frac={}", jd.jd_day, static_cast<double>(jd.jd_frac)); | |
1234 | } | ||
1235 | }; | ||
1236 | /// @brief Formatter | ||
1237 | template<> | ||
1238 | struct fmt::formatter<NAV::InsTime_GPSweekTow> : fmt::formatter<std::string> | ||
1239 | { | ||
1240 | /// @brief Defines how to format this structs | ||
1241 | /// @param[in] gpsWeekTow Struct to format | ||
1242 | /// @param[in, out] ctx Format context | ||
1243 | /// @return Output iterator | ||
1244 | template<typename FormatContext> | ||
1245 | 19560 | auto format(const NAV::InsTime_GPSweekTow& gpsWeekTow, FormatContext& ctx) const | |
1246 | { | ||
1247 | 39120 | return fmt::format_to(ctx.out(), "cycle={}, week={}, tow={}", | |
1248 | 39120 | gpsWeekTow.gpsCycle, gpsWeekTow.gpsWeek, static_cast<double>(gpsWeekTow.tow)); | |
1249 | } | ||
1250 | }; | ||
1251 | /// @brief Formatter | ||
1252 | template<> | ||
1253 | struct fmt::formatter<NAV::InsTime_YMDHMS> : fmt::formatter<std::string> | ||
1254 | { | ||
1255 | /// @brief Defines how to format this structs | ||
1256 | /// @param[in] ymdhms Struct to format | ||
1257 | /// @param[in, out] ctx Format context | ||
1258 | /// @return Output iterator | ||
1259 | template<typename FormatContext> | ||
1260 | 47921 | auto format(const NAV::InsTime_YMDHMS& ymdhms, FormatContext& ctx) const | |
1261 | { | ||
1262 | 95842 | return fmt::format_to(ctx.out(), "{}-{}-{} {}:{}:{:.6g}", | |
1263 | 47921 | ymdhms.year, ymdhms.month, ymdhms.day, | |
1264 | 95842 | ymdhms.hour, ymdhms.min, static_cast<double>(ymdhms.sec)); | |
1265 | } | ||
1266 | }; | ||
1267 | /// @brief Formatter | ||
1268 | template<> | ||
1269 | struct fmt::formatter<NAV::InsTime_YDoySod> : fmt::formatter<std::string> | ||
1270 | { | ||
1271 | /// @brief Defines how to format this structs | ||
1272 | /// @param[in] yDoySod Struct to format | ||
1273 | /// @param[in, out] ctx Format context | ||
1274 | /// @return Output iterator | ||
1275 | template<typename FormatContext> | ||
1276 | ✗ | auto format(const NAV::InsTime_YDoySod& yDoySod, FormatContext& ctx) const | |
1277 | { | ||
1278 | ✗ | return fmt::format_to(ctx.out(), "year={}, doy={}, sod={:.6g}", | |
1279 | ✗ | yDoySod.year, yDoySod.doy, static_cast<double>(yDoySod.sod)); | |
1280 | } | ||
1281 | }; | ||
1282 | /// @brief Formatter | ||
1283 | template<> | ||
1284 | struct fmt::formatter<NAV::InsTime> : fmt::formatter<std::string> | ||
1285 | { | ||
1286 | /// @brief Defines how to format this structs | ||
1287 | /// @param[in] insTime Struct to format | ||
1288 | /// @param[in, out] ctx Format context | ||
1289 | /// @return Output iterator | ||
1290 | template<typename FormatContext> | ||
1291 | 12902 | auto format(const NAV::InsTime& insTime, FormatContext& ctx) const | |
1292 | { | ||
1293 |
2/4✓ Branch 2 taken 12902 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 12902 times.
✗ Branch 7 not taken.
|
25804 | return fmt::format_to(ctx.out(), "{} ({})", insTime.toYMDHMS(), insTime.toGPSweekTow()); |
1294 | } | ||
1295 | }; | ||
1296 | |||
1297 | #endif | ||
1298 |