xref: /aosp_15_r20/external/llvm-libc/src/time/time_utils.h (revision 71db0c75aadcf003ffe3238005f61d7618a3fead)
1*71db0c75SAndroid Build Coastguard Worker //===-- Collection of utils for mktime and friends --------------*- C++ -*-===//
2*71db0c75SAndroid Build Coastguard Worker //
3*71db0c75SAndroid Build Coastguard Worker // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*71db0c75SAndroid Build Coastguard Worker // See https://llvm.org/LICENSE.txt for license information.
5*71db0c75SAndroid Build Coastguard Worker // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*71db0c75SAndroid Build Coastguard Worker //
7*71db0c75SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
8*71db0c75SAndroid Build Coastguard Worker 
9*71db0c75SAndroid Build Coastguard Worker #ifndef LLVM_LIBC_SRC_TIME_TIME_UTILS_H
10*71db0c75SAndroid Build Coastguard Worker #define LLVM_LIBC_SRC_TIME_TIME_UTILS_H
11*71db0c75SAndroid Build Coastguard Worker 
12*71db0c75SAndroid Build Coastguard Worker #include <stddef.h> // For size_t.
13*71db0c75SAndroid Build Coastguard Worker 
14*71db0c75SAndroid Build Coastguard Worker #include "src/__support/common.h"
15*71db0c75SAndroid Build Coastguard Worker #include "src/__support/macros/config.h"
16*71db0c75SAndroid Build Coastguard Worker #include "src/errno/libc_errno.h"
17*71db0c75SAndroid Build Coastguard Worker #include "src/time/mktime.h"
18*71db0c75SAndroid Build Coastguard Worker 
19*71db0c75SAndroid Build Coastguard Worker #include <stdint.h>
20*71db0c75SAndroid Build Coastguard Worker 
21*71db0c75SAndroid Build Coastguard Worker namespace LIBC_NAMESPACE_DECL {
22*71db0c75SAndroid Build Coastguard Worker namespace time_utils {
23*71db0c75SAndroid Build Coastguard Worker 
24*71db0c75SAndroid Build Coastguard Worker enum Month : int {
25*71db0c75SAndroid Build Coastguard Worker   JANUARY,
26*71db0c75SAndroid Build Coastguard Worker   FEBRUARY,
27*71db0c75SAndroid Build Coastguard Worker   MARCH,
28*71db0c75SAndroid Build Coastguard Worker   APRIL,
29*71db0c75SAndroid Build Coastguard Worker   MAY,
30*71db0c75SAndroid Build Coastguard Worker   JUNE,
31*71db0c75SAndroid Build Coastguard Worker   JULY,
32*71db0c75SAndroid Build Coastguard Worker   AUGUST,
33*71db0c75SAndroid Build Coastguard Worker   SEPTEMBER,
34*71db0c75SAndroid Build Coastguard Worker   OCTOBER,
35*71db0c75SAndroid Build Coastguard Worker   NOVEMBER,
36*71db0c75SAndroid Build Coastguard Worker   DECEMBER
37*71db0c75SAndroid Build Coastguard Worker };
38*71db0c75SAndroid Build Coastguard Worker 
39*71db0c75SAndroid Build Coastguard Worker struct TimeConstants {
40*71db0c75SAndroid Build Coastguard Worker   static constexpr int SECONDS_PER_MIN = 60;
41*71db0c75SAndroid Build Coastguard Worker   static constexpr int MINUTES_PER_HOUR = 60;
42*71db0c75SAndroid Build Coastguard Worker   static constexpr int HOURS_PER_DAY = 24;
43*71db0c75SAndroid Build Coastguard Worker   static constexpr int DAYS_PER_WEEK = 7;
44*71db0c75SAndroid Build Coastguard Worker   static constexpr int MONTHS_PER_YEAR = 12;
45*71db0c75SAndroid Build Coastguard Worker   static constexpr int DAYS_PER_NON_LEAP_YEAR = 365;
46*71db0c75SAndroid Build Coastguard Worker   static constexpr int DAYS_PER_LEAP_YEAR = 366;
47*71db0c75SAndroid Build Coastguard Worker 
48*71db0c75SAndroid Build Coastguard Worker   static constexpr int SECONDS_PER_HOUR = SECONDS_PER_MIN * MINUTES_PER_HOUR;
49*71db0c75SAndroid Build Coastguard Worker   static constexpr int SECONDS_PER_DAY = SECONDS_PER_HOUR * HOURS_PER_DAY;
50*71db0c75SAndroid Build Coastguard Worker   static constexpr int NUMBER_OF_SECONDS_IN_LEAP_YEAR =
51*71db0c75SAndroid Build Coastguard Worker       DAYS_PER_LEAP_YEAR * SECONDS_PER_DAY;
52*71db0c75SAndroid Build Coastguard Worker 
53*71db0c75SAndroid Build Coastguard Worker   static constexpr int TIME_YEAR_BASE = 1900;
54*71db0c75SAndroid Build Coastguard Worker   static constexpr int EPOCH_YEAR = 1970;
55*71db0c75SAndroid Build Coastguard Worker   static constexpr int EPOCH_WEEK_DAY = 4;
56*71db0c75SAndroid Build Coastguard Worker 
57*71db0c75SAndroid Build Coastguard Worker   // For asctime the behavior is undefined if struct tm's tm_wday or tm_mon are
58*71db0c75SAndroid Build Coastguard Worker   // not within the normal ranges as defined in <time.h>, or if struct tm's
59*71db0c75SAndroid Build Coastguard Worker   // tm_year exceeds {INT_MAX}-1990, or if the below asctime_internal algorithm
60*71db0c75SAndroid Build Coastguard Worker   // would attempt to generate more than 26 bytes of output (including the
61*71db0c75SAndroid Build Coastguard Worker   // terminating null).
62*71db0c75SAndroid Build Coastguard Worker   static constexpr int ASCTIME_BUFFER_SIZE = 256;
63*71db0c75SAndroid Build Coastguard Worker   static constexpr int ASCTIME_MAX_BYTES = 26;
64*71db0c75SAndroid Build Coastguard Worker 
65*71db0c75SAndroid Build Coastguard Worker   /* 2000-03-01 (mod 400 year, immediately after feb29 */
66*71db0c75SAndroid Build Coastguard Worker   static constexpr int64_t SECONDS_UNTIL2000_MARCH_FIRST =
67*71db0c75SAndroid Build Coastguard Worker       (946684800LL + SECONDS_PER_DAY * (31 + 29));
68*71db0c75SAndroid Build Coastguard Worker   static constexpr int WEEK_DAY_OF2000_MARCH_FIRST = 3;
69*71db0c75SAndroid Build Coastguard Worker 
70*71db0c75SAndroid Build Coastguard Worker   static constexpr int DAYS_PER400_YEARS =
71*71db0c75SAndroid Build Coastguard Worker       (DAYS_PER_NON_LEAP_YEAR * 400) + (400 / 4) - 3;
72*71db0c75SAndroid Build Coastguard Worker   static constexpr int DAYS_PER100_YEARS =
73*71db0c75SAndroid Build Coastguard Worker       (DAYS_PER_NON_LEAP_YEAR * 100) + (100 / 4) - 1;
74*71db0c75SAndroid Build Coastguard Worker   static constexpr int DAYS_PER4_YEARS = (DAYS_PER_NON_LEAP_YEAR * 4) + 1;
75*71db0c75SAndroid Build Coastguard Worker 
76*71db0c75SAndroid Build Coastguard Worker   // The latest time that can be represented in this form is 03:14:07 UTC on
77*71db0c75SAndroid Build Coastguard Worker   // Tuesday, 19 January 2038 (corresponding to 2,147,483,647 seconds since the
78*71db0c75SAndroid Build Coastguard Worker   // start of the epoch). This means that systems using a 32-bit time_t type are
79*71db0c75SAndroid Build Coastguard Worker   // susceptible to the Year 2038 problem.
80*71db0c75SAndroid Build Coastguard Worker   static constexpr int END_OF32_BIT_EPOCH_YEAR = 2038;
81*71db0c75SAndroid Build Coastguard Worker 
82*71db0c75SAndroid Build Coastguard Worker   static constexpr time_t OUT_OF_RANGE_RETURN_VALUE = -1;
83*71db0c75SAndroid Build Coastguard Worker };
84*71db0c75SAndroid Build Coastguard Worker 
85*71db0c75SAndroid Build Coastguard Worker // Update the "tm" structure's year, month, etc. members from seconds.
86*71db0c75SAndroid Build Coastguard Worker // "total_seconds" is the number of seconds since January 1st, 1970.
87*71db0c75SAndroid Build Coastguard Worker extern int64_t update_from_seconds(int64_t total_seconds, struct tm *tm);
88*71db0c75SAndroid Build Coastguard Worker 
89*71db0c75SAndroid Build Coastguard Worker // TODO(michaelrj): move these functions to use ErrorOr instead of setting
90*71db0c75SAndroid Build Coastguard Worker // errno. They always accompany a specific return value so we only need the one
91*71db0c75SAndroid Build Coastguard Worker // variable.
92*71db0c75SAndroid Build Coastguard Worker 
93*71db0c75SAndroid Build Coastguard Worker // POSIX.1-2017 requires this.
out_of_range()94*71db0c75SAndroid Build Coastguard Worker LIBC_INLINE time_t out_of_range() {
95*71db0c75SAndroid Build Coastguard Worker #ifdef EOVERFLOW
96*71db0c75SAndroid Build Coastguard Worker   // For non-POSIX uses of the standard C time functions, where EOVERFLOW is
97*71db0c75SAndroid Build Coastguard Worker   // not defined, it's OK not to set errno at all. The plain C standard doesn't
98*71db0c75SAndroid Build Coastguard Worker   // require it.
99*71db0c75SAndroid Build Coastguard Worker   libc_errno = EOVERFLOW;
100*71db0c75SAndroid Build Coastguard Worker #endif
101*71db0c75SAndroid Build Coastguard Worker   return TimeConstants::OUT_OF_RANGE_RETURN_VALUE;
102*71db0c75SAndroid Build Coastguard Worker }
103*71db0c75SAndroid Build Coastguard Worker 
invalid_value()104*71db0c75SAndroid Build Coastguard Worker LIBC_INLINE void invalid_value() { libc_errno = EINVAL; }
105*71db0c75SAndroid Build Coastguard Worker 
asctime(const struct tm * timeptr,char * buffer,size_t bufferLength)106*71db0c75SAndroid Build Coastguard Worker LIBC_INLINE char *asctime(const struct tm *timeptr, char *buffer,
107*71db0c75SAndroid Build Coastguard Worker                           size_t bufferLength) {
108*71db0c75SAndroid Build Coastguard Worker   if (timeptr == nullptr || buffer == nullptr) {
109*71db0c75SAndroid Build Coastguard Worker     invalid_value();
110*71db0c75SAndroid Build Coastguard Worker     return nullptr;
111*71db0c75SAndroid Build Coastguard Worker   }
112*71db0c75SAndroid Build Coastguard Worker   if (timeptr->tm_wday < 0 ||
113*71db0c75SAndroid Build Coastguard Worker       timeptr->tm_wday > (TimeConstants::DAYS_PER_WEEK - 1)) {
114*71db0c75SAndroid Build Coastguard Worker     invalid_value();
115*71db0c75SAndroid Build Coastguard Worker     return nullptr;
116*71db0c75SAndroid Build Coastguard Worker   }
117*71db0c75SAndroid Build Coastguard Worker   if (timeptr->tm_mon < 0 ||
118*71db0c75SAndroid Build Coastguard Worker       timeptr->tm_mon > (TimeConstants::MONTHS_PER_YEAR - 1)) {
119*71db0c75SAndroid Build Coastguard Worker     invalid_value();
120*71db0c75SAndroid Build Coastguard Worker     return nullptr;
121*71db0c75SAndroid Build Coastguard Worker   }
122*71db0c75SAndroid Build Coastguard Worker 
123*71db0c75SAndroid Build Coastguard Worker   // TODO(rtenneti): i18n the following strings.
124*71db0c75SAndroid Build Coastguard Worker   static const char *week_days_name[TimeConstants::DAYS_PER_WEEK] = {
125*71db0c75SAndroid Build Coastguard Worker       "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
126*71db0c75SAndroid Build Coastguard Worker 
127*71db0c75SAndroid Build Coastguard Worker   static const char *months_name[TimeConstants::MONTHS_PER_YEAR] = {
128*71db0c75SAndroid Build Coastguard Worker       "Jan", "Feb", "Mar", "Apr", "May", "Jun",
129*71db0c75SAndroid Build Coastguard Worker       "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
130*71db0c75SAndroid Build Coastguard Worker 
131*71db0c75SAndroid Build Coastguard Worker   // TODO(michaelr): look into removing this call to __builtin_snprintf that may
132*71db0c75SAndroid Build Coastguard Worker   // be emitted as a call to snprintf. Alternatively, look into using our
133*71db0c75SAndroid Build Coastguard Worker   // internal printf machinery.
134*71db0c75SAndroid Build Coastguard Worker   int written_size = __builtin_snprintf(
135*71db0c75SAndroid Build Coastguard Worker       buffer, bufferLength, "%.3s %.3s%3d %.2d:%.2d:%.2d %d\n",
136*71db0c75SAndroid Build Coastguard Worker       week_days_name[timeptr->tm_wday], months_name[timeptr->tm_mon],
137*71db0c75SAndroid Build Coastguard Worker       timeptr->tm_mday, timeptr->tm_hour, timeptr->tm_min, timeptr->tm_sec,
138*71db0c75SAndroid Build Coastguard Worker       TimeConstants::TIME_YEAR_BASE + timeptr->tm_year);
139*71db0c75SAndroid Build Coastguard Worker   if (written_size < 0)
140*71db0c75SAndroid Build Coastguard Worker     return nullptr;
141*71db0c75SAndroid Build Coastguard Worker   if (static_cast<size_t>(written_size) >= bufferLength) {
142*71db0c75SAndroid Build Coastguard Worker     out_of_range();
143*71db0c75SAndroid Build Coastguard Worker     return nullptr;
144*71db0c75SAndroid Build Coastguard Worker   }
145*71db0c75SAndroid Build Coastguard Worker   return buffer;
146*71db0c75SAndroid Build Coastguard Worker }
147*71db0c75SAndroid Build Coastguard Worker 
gmtime_internal(const time_t * timer,struct tm * result)148*71db0c75SAndroid Build Coastguard Worker LIBC_INLINE struct tm *gmtime_internal(const time_t *timer, struct tm *result) {
149*71db0c75SAndroid Build Coastguard Worker   int64_t seconds = *timer;
150*71db0c75SAndroid Build Coastguard Worker   // Update the tm structure's year, month, day, etc. from seconds.
151*71db0c75SAndroid Build Coastguard Worker   if (update_from_seconds(seconds, result) < 0) {
152*71db0c75SAndroid Build Coastguard Worker     out_of_range();
153*71db0c75SAndroid Build Coastguard Worker     return nullptr;
154*71db0c75SAndroid Build Coastguard Worker   }
155*71db0c75SAndroid Build Coastguard Worker 
156*71db0c75SAndroid Build Coastguard Worker   return result;
157*71db0c75SAndroid Build Coastguard Worker }
158*71db0c75SAndroid Build Coastguard Worker 
159*71db0c75SAndroid Build Coastguard Worker // TODO: localtime is not yet implemented and a temporary solution is to
160*71db0c75SAndroid Build Coastguard Worker //       use gmtime, https://github.com/llvm/llvm-project/issues/107597
localtime(const time_t * t_ptr)161*71db0c75SAndroid Build Coastguard Worker LIBC_INLINE struct tm *localtime(const time_t *t_ptr) {
162*71db0c75SAndroid Build Coastguard Worker   static struct tm result;
163*71db0c75SAndroid Build Coastguard Worker   return time_utils::gmtime_internal(t_ptr, &result);
164*71db0c75SAndroid Build Coastguard Worker }
165*71db0c75SAndroid Build Coastguard Worker 
166*71db0c75SAndroid Build Coastguard Worker } // namespace time_utils
167*71db0c75SAndroid Build Coastguard Worker } // namespace LIBC_NAMESPACE_DECL
168*71db0c75SAndroid Build Coastguard Worker 
169*71db0c75SAndroid Build Coastguard Worker #endif // LLVM_LIBC_SRC_TIME_TIME_UTILS_H
170