]> git.proxmox.com Git - wasi-libc.git/blame - libc-bottom-half/cloudlibc/src/common/time.h
Update README and add CI-tests for minimal supported LLVM-version (10) (#302)
[wasi-libc.git] / libc-bottom-half / cloudlibc / src / common / time.h
CommitLineData
320054e8
DG
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
446cb3f1 13#include <wasi/api.h>
320054e8
DG
14#include <stdbool.h>
15#include <time.h>
16
17#define NSEC_PER_SEC 1000000000
18
19// Timezone agnostic conversion routines.
20int __localtime_utc(time_t, struct tm *);
21void __mktime_utc(const struct tm *, struct timespec *);
22
23static 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.
31static 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.
42static 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
52static inline short get_ydays(time_t year) {
53 return is_leap(year) ? 366 : 365;
54}
55
56static 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
71static 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
88static 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
95static 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