|
10 | 10 | * http://howardhinnant.github.io/date_algorithms.html#days_from_civil
|
11 | 11 | */
|
12 | 12 |
|
13 |
| -#include <zephyr/types.h> |
14 | 13 | #include <errno.h>
|
15 |
| -#include <stddef.h> |
16 | 14 | #include <stdbool.h>
|
| 15 | +#include <stddef.h> |
| 16 | +#include <stdint.h> |
| 17 | +#include <time.h> |
| 18 | + |
| 19 | +#include <zephyr/sys/__assert.h> |
| 20 | +#include <zephyr/sys/clock.h> |
17 | 21 | #include <zephyr/sys/timeutil.h>
|
18 | 22 |
|
19 | 23 | /** Convert a civil (proleptic Gregorian) date to days relative to
|
@@ -188,3 +192,49 @@ int32_t timeutil_sync_skew_to_ppb(float skew)
|
188 | 192 |
|
189 | 193 | return (ppb64 == ppb32) ? ppb32 : INT32_MIN;
|
190 | 194 | }
|
| 195 | + |
| 196 | +bool timespec_normalize(struct timespec *ts) |
| 197 | +{ |
| 198 | + __ASSERT_NO_MSG(ts != NULL); |
| 199 | + |
| 200 | + long sec; |
| 201 | + |
| 202 | + if (ts->tv_nsec >= (long)NSEC_PER_SEC) { |
| 203 | + sec = ts->tv_nsec / (long)NSEC_PER_SEC; |
| 204 | + } else if (ts->tv_nsec < 0) { |
| 205 | + sec = DIV_ROUND_UP((unsigned long)-ts->tv_nsec, NSEC_PER_SEC); |
| 206 | + } else { |
| 207 | + sec = 0; |
| 208 | + } |
| 209 | + |
| 210 | + if ((ts->tv_nsec < 0) && (ts->tv_sec < 0) && (ts->tv_sec - SYS_TIME_T_MIN < sec)) { |
| 211 | + /* |
| 212 | + * When `tv_nsec` is negative and `tv_sec` is already most negative, |
| 213 | + * further subtraction would cause integer overflow. |
| 214 | + */ |
| 215 | + return false; |
| 216 | + } |
| 217 | + |
| 218 | + if ((ts->tv_nsec >= (long)NSEC_PER_SEC) && (ts->tv_sec > 0) && |
| 219 | + (SYS_TIME_T_MAX - ts->tv_sec < sec)) { |
| 220 | + /* |
| 221 | + * When `tv_nsec` is >= `NSEC_PER_SEC` and `tv_sec` is already most |
| 222 | + * positive, further addition would cause integer overflow. |
| 223 | + */ |
| 224 | + return false; |
| 225 | + } |
| 226 | + |
| 227 | + if (ts->tv_nsec >= (long)NSEC_PER_SEC) { |
| 228 | + ts->tv_sec += sec; |
| 229 | + ts->tv_nsec -= sec * (long)NSEC_PER_SEC; |
| 230 | + } else if (ts->tv_nsec < 0) { |
| 231 | + ts->tv_sec -= sec; |
| 232 | + ts->tv_nsec += sec * (long)NSEC_PER_SEC; |
| 233 | + } else { |
| 234 | + /* no change: SonarQube was complaining */ |
| 235 | + } |
| 236 | + |
| 237 | + __ASSERT_NO_MSG(timespec_is_valid(ts)); |
| 238 | + |
| 239 | + return true; |
| 240 | +} |
0 commit comments