]> git.proxmox.com Git - wasi-libc.git/blob - libc-bottom-half/cloudlibc/src/common/time.h
WASI libc prototype implementation.
[wasi-libc.git] / libc-bottom-half / cloudlibc / src / common / time.h
1 // Copyright (c) 2015-2016 Nuxi, https://nuxi.nl/
2 //
3 // SPDX-License-Identifier: BSD-2-Clause
4
5 #ifndef COMMON_TIME_H
6 #define COMMON_TIME_H
7
8 #include <common/limits.h>
9 #include <common/overflow.h>
10
11 #include <sys/time.h>
12
13 #include <wasi/core.h>
14 #include <stdbool.h>
15 #include <time.h>
16
17 #define NSEC_PER_SEC 1000000000
18
19 // Timezone agnostic conversion routines.
20 int __localtime_utc(time_t, struct tm *);
21 void __mktime_utc(const struct tm *, struct timespec *);
22
23 static inline bool is_leap(time_t year) {
24 year %= 400;
25 if (year < 0)
26 year += 400;
27 return ((year % 4) == 0 && (year % 100) != 0) || year == 100;
28 }
29
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,
34 };
35 static const char common[12] = {
36 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
37 };
38 return is_leap(year) ? leap : common;
39 }
40
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,
45 };
46 static const short common[13] = {
47 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365,
48 };
49 return is_leap(year) ? leap : common;
50 }
51
52 static inline short get_ydays(time_t year) {
53 return is_leap(year) ? 366 : 365;
54 }
55
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)
60 return false;
61
62 // Timestamps before the Epoch are not supported.
63 if (timespec->tv_sec < 0)
64 return false;
65
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);
69 }
70
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)
75 return false;
76
77 if (timespec->tv_sec < 0) {
78 // Timestamps before the Epoch are not supported.
79 *timestamp = 0;
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);
84 }
85 return true;
86 }
87
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};
93 }
94
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};
99 }
100
101 #endif