-
Notifications
You must be signed in to change notification settings - Fork 10.7k
/
time_utils.h
145 lines (123 loc) · 4.75 KB
/
time_utils.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
//===-- Collection of utils for mktime and friends --------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_LIBC_SRC_TIME_TIME_UTILS_H
#define LLVM_LIBC_SRC_TIME_TIME_UTILS_H
#include <stddef.h> // For size_t.
#include "src/__support/common.h"
#include "src/errno/libc_errno.h"
#include "src/time/mktime.h"
#include <stdint.h>
namespace __llvm_libc {
namespace time_utils {
enum Month : int {
JANUARY,
FEBRUARY,
MARCH,
APRIL,
MAY,
JUNE,
JULY,
AUGUST,
SEPTEMBER,
OCTOBER,
NOVEMBER,
DECEMBER
};
struct TimeConstants {
static constexpr int SECONDS_PER_MIN = 60;
static constexpr int SECONDS_PER_HOUR = 3600;
static constexpr int SECONDS_PER_DAY = 86400;
static constexpr int MINUTES_PER_HOUR = 60;
static constexpr int DAYS_PER_WEEK = 7;
static constexpr int MONTHS_PER_YEAR = 12;
static constexpr int DAYS_PER_NON_LEAP_YEAR = 365;
static constexpr int DAYS_PER_LEAP_YEAR = 366;
static constexpr int TIME_YEAR_BASE = 1900;
static constexpr int EPOCH_YEAR = 1970;
static constexpr int EPOCH_WEEK_DAY = 4;
static constexpr int NUMBER_OF_SECONDS_IN_LEAP_YEAR =
(DAYS_PER_NON_LEAP_YEAR + 1) * SECONDS_PER_DAY;
// For asctime the behavior is undefined if struct tm's tm_wday or tm_mon are
// not within the normal ranges as defined in <time.h>, or if struct tm's
// tm_year exceeds {INT_MAX}-1990, or if the below asctime_internal algorithm
// would attempt to generate more than 26 bytes of output (including the
// terminating null).
static constexpr int ASCTIME_BUFFER_SIZE = 256;
static constexpr int ASCTIME_MAX_BYTES = 26;
/* 2000-03-01 (mod 400 year, immediately after feb29 */
static constexpr int64_t SECONDS_UNTIL2000_MARCH_FIRST =
(946684800LL + SECONDS_PER_DAY * (31 + 29));
static constexpr int WEEK_DAY_OF2000_MARCH_FIRST = 3;
static constexpr int DAYS_PER400_YEARS =
(DAYS_PER_NON_LEAP_YEAR * 400 + (400 / 4) - 3);
static constexpr int DAYS_PER100_YEARS =
(DAYS_PER_NON_LEAP_YEAR * 100 + (100 / 4) - 1);
static constexpr int DAYS_PER4_YEARS = (DAYS_PER_NON_LEAP_YEAR * 4 + 1);
// The latest time that can be represented in this form is 03:14:07 UTC on
// Tuesday, 19 January 2038 (corresponding to 2,147,483,647 seconds since the
// start of the epoch). This means that systems using a 32-bit time_t type are
// susceptible to the Year 2038 problem.
static constexpr int END_OF32_BIT_EPOCH_YEAR = 2038;
static constexpr time_t OUT_OF_RANGE_RETURN_VALUE = -1;
};
// Update the "tm" structure's year, month, etc. members from seconds.
// "total_seconds" is the number of seconds since January 1st, 1970.
extern int64_t update_from_seconds(int64_t total_seconds, struct tm *tm);
// POSIX.1-2017 requires this.
LIBC_INLINE time_t out_of_range() {
libc_errno = EOVERFLOW;
return static_cast<time_t>(-1);
}
LIBC_INLINE void invalid_value() { libc_errno = EINVAL; }
LIBC_INLINE char *asctime(const struct tm *timeptr, char *buffer,
size_t bufferLength) {
if (timeptr == nullptr || buffer == nullptr) {
invalid_value();
return nullptr;
}
if (timeptr->tm_wday < 0 ||
timeptr->tm_wday > (TimeConstants::DAYS_PER_WEEK - 1)) {
invalid_value();
return nullptr;
}
if (timeptr->tm_mon < 0 ||
timeptr->tm_mon > (TimeConstants::MONTHS_PER_YEAR - 1)) {
invalid_value();
return nullptr;
}
// TODO(rtenneti): i18n the following strings.
static const char *week_days_name[TimeConstants::DAYS_PER_WEEK] = {
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
static const char *months_name[TimeConstants::MONTHS_PER_YEAR] = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
int written_size = __builtin_snprintf(
buffer, bufferLength, "%.3s %.3s%3d %.2d:%.2d:%.2d %d\n",
week_days_name[timeptr->tm_wday], months_name[timeptr->tm_mon],
timeptr->tm_mday, timeptr->tm_hour, timeptr->tm_min, timeptr->tm_sec,
TimeConstants::TIME_YEAR_BASE + timeptr->tm_year);
if (written_size < 0)
return nullptr;
if (static_cast<size_t>(written_size) >= bufferLength) {
out_of_range();
return nullptr;
}
return buffer;
}
LIBC_INLINE struct tm *gmtime_internal(const time_t *timer, struct tm *result) {
int64_t seconds = *timer;
// Update the tm structure's year, month, day, etc. from seconds.
if (update_from_seconds(seconds, result) < 0) {
out_of_range();
return nullptr;
}
return result;
}
} // namespace time_utils
} // namespace __llvm_libc
#endif // LLVM_LIBC_SRC_TIME_TIME_UTILS_H