1 // Copyright (c) 2015-2016 Nuxi, https://nuxi.nl/
3 // SPDX-License-Identifier: BSD-2-Clause
8 #include <common/limits.h>
9 #include <common/overflow.h>
13 #include <wasi/core.h>
17 #define NSEC_PER_SEC 1000000000
19 // Timezone agnostic conversion routines.
20 int __localtime_utc(time_t, struct tm
*);
21 void __mktime_utc(const struct tm
*, struct timespec
*);
23 static inline bool is_leap(time_t year
) {
27 return ((year
% 4) == 0 && (year
% 100) != 0) || year
== 100;
30 // Gets the length of the months in a year.
31 static inline const char *get_months(time_t year
) {
32 static const char leap
[12] = {
33 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
35 static const char common
[12] = {
36 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
38 return is_leap(year
) ? leap
: common
;
41 // Gets the cumulative length of the months in a year.
42 static inline const short *get_months_cumulative(time_t year
) {
43 static const short leap
[13] = {
44 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366,
46 static const short common
[13] = {
47 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365,
49 return is_leap(year
) ? leap
: common
;
52 static inline short get_ydays(time_t year
) {
53 return is_leap(year
) ? 366 : 365;
56 static inline bool timespec_to_timestamp_exact(
57 const struct timespec
*timespec
, __wasi_timestamp_t
*timestamp
) {
58 // Invalid nanoseconds field.
59 if (timespec
->tv_nsec
< 0 || timespec
->tv_nsec
>= NSEC_PER_SEC
)
62 // Timestamps before the Epoch are not supported.
63 if (timespec
->tv_sec
< 0)
66 // Make sure our timestamp does not overflow.
67 return !mul_overflow(timespec
->tv_sec
, NSEC_PER_SEC
, timestamp
) &&
68 !add_overflow(*timestamp
, timespec
->tv_nsec
, timestamp
);
71 static inline bool timespec_to_timestamp_clamp(
72 const struct timespec
*timespec
, __wasi_timestamp_t
*timestamp
) {
73 // Invalid nanoseconds field.
74 if (timespec
->tv_nsec
< 0 || timespec
->tv_nsec
>= NSEC_PER_SEC
)
77 if (timespec
->tv_sec
< 0) {
78 // Timestamps before the Epoch are not supported.
80 } else if (mul_overflow(timespec
->tv_sec
, NSEC_PER_SEC
, timestamp
) ||
81 add_overflow(*timestamp
, timespec
->tv_nsec
, timestamp
)) {
82 // Make sure our timestamp does not overflow.
83 *timestamp
= NUMERIC_MAX(__wasi_timestamp_t
);
88 static inline struct timespec
timestamp_to_timespec(
89 __wasi_timestamp_t timestamp
) {
90 // Decompose timestamp into seconds and nanoseconds.
91 return (struct timespec
){.tv_sec
= timestamp
/ NSEC_PER_SEC
,
92 .tv_nsec
= timestamp
% NSEC_PER_SEC
};
95 static inline struct timeval
timestamp_to_timeval(
96 __wasi_timestamp_t timestamp
) {
97 struct timespec ts
= timestamp_to_timespec(timestamp
);
98 return (struct timeval
){.tv_sec
= ts
.tv_sec
, ts
.tv_nsec
/ 1000};