Skip to content

Commit d02f1e1

Browse files
cleanup and address comments
1 parent bedf3a0 commit d02f1e1

File tree

3 files changed

+60
-63
lines changed

3 files changed

+60
-63
lines changed

libc/src/time/time_constants.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ constexpr int SECONDS_PER_MIN = 60;
4646
constexpr int MINUTES_PER_HOUR = 60;
4747
constexpr int HOURS_PER_DAY = 24;
4848
constexpr int DAYS_PER_WEEK = 7;
49+
constexpr int WEEKS_PER_YEAR = 52;
4950
constexpr int MONTHS_PER_YEAR = 12;
5051
constexpr int DAYS_PER_NON_LEAP_YEAR = 365;
5152
constexpr int DAYS_PER_LEAP_YEAR = 366;

libc/src/time/time_utils.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,13 @@
1212
#include "src/__support/macros/config.h"
1313
#include "src/time/time_constants.h"
1414

15+
#include <stdint.h>
16+
1517
namespace LIBC_NAMESPACE_DECL {
1618
namespace time_utils {
1719

1820
// TODO: clean this up in a followup patch
19-
int64_t mktime_internal(const struct tm *tm_out) {
21+
int64_t mktime_internal(const tm *tm_out) {
2022
// Unlike most C Library functions, mktime doesn't just die on bad input.
2123
// TODO(rtenneti); Handle leap seconds.
2224
int64_t tm_year_from_base = tm_out->tm_year + time_constants::TIME_YEAR_BASE;
@@ -134,7 +136,7 @@ static int64_t computeRemainingYears(int64_t daysPerYears,
134136
//
135137
// Compute the number of months from the remaining days. Finally, adjust years
136138
// to be 1900 and months to be from January.
137-
int64_t update_from_seconds(int64_t total_seconds, struct tm *tm) {
139+
int64_t update_from_seconds(int64_t total_seconds, tm *tm) {
138140
// Days in month starting from March in the year 2000.
139141
static const char daysInMonth[] = {31 /* Mar */, 30, 31, 30, 31, 31,
140142
30, 31, 30, 31, 31, 29};

libc/src/time/time_utils.h

Lines changed: 55 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,11 @@ namespace time_utils {
2626

2727
// calculates the seconds from the epoch for tm_in. Does not update the struct,
2828
// you must call update_from_seconds for that.
29-
int64_t mktime_internal(const struct tm *tm_out);
29+
int64_t mktime_internal(const tm *tm_out);
3030

3131
// Update the "tm" structure's year, month, etc. members from seconds.
3232
// "total_seconds" is the number of seconds since January 1st, 1970.
33-
extern int64_t update_from_seconds(int64_t total_seconds, struct tm *tm);
33+
extern int64_t update_from_seconds(int64_t total_seconds, tm *tm);
3434

3535
// TODO(michaelrj): move these functions to use ErrorOr instead of setting
3636
// errno. They always accompany a specific return value so we only need the one
@@ -49,7 +49,7 @@ LIBC_INLINE time_t out_of_range() {
4949

5050
LIBC_INLINE void invalid_value() { libc_errno = EINVAL; }
5151

52-
LIBC_INLINE char *asctime(const struct tm *timeptr, char *buffer,
52+
LIBC_INLINE char *asctime(const tm *timeptr, char *buffer,
5353
size_t bufferLength) {
5454
if (timeptr == nullptr || buffer == nullptr) {
5555
invalid_value();
@@ -83,7 +83,7 @@ LIBC_INLINE char *asctime(const struct tm *timeptr, char *buffer,
8383
return buffer;
8484
}
8585

86-
LIBC_INLINE struct tm *gmtime_internal(const time_t *timer, struct tm *result) {
86+
LIBC_INLINE tm *gmtime_internal(const time_t *timer, tm *result) {
8787
int64_t seconds = *timer;
8888
// Update the tm structure's year, month, day, etc. from seconds.
8989
if (update_from_seconds(seconds, result) < 0) {
@@ -96,8 +96,8 @@ LIBC_INLINE struct tm *gmtime_internal(const time_t *timer, struct tm *result) {
9696

9797
// TODO: localtime is not yet implemented and a temporary solution is to
9898
// use gmtime, https://github.com/llvm/llvm-project/issues/107597
99-
LIBC_INLINE struct tm *localtime(const time_t *t_ptr) {
100-
static struct tm result;
99+
LIBC_INLINE tm *localtime(const time_t *t_ptr) {
100+
static tm result;
101101
return time_utils::gmtime_internal(t_ptr, &result);
102102
}
103103

@@ -124,44 +124,38 @@ LIBC_INLINE constexpr int get_days_in_year(const int year) {
124124
class TMReader final {
125125
const tm *timeptr;
126126

127+
template <size_t N>
128+
LIBC_INLINE constexpr cpp::optional<cpp::string_view>
129+
bounds_check(const cpp::array<cpp::string_view, N> &arr, int index) const {
130+
if (index >= 0 && index < static_cast<int>(arr.size()))
131+
return arr[index];
132+
return cpp::nullopt;
133+
}
134+
127135
public:
128-
LIBC_INLINE constexpr TMReader(const tm *tmptr) : timeptr(tmptr) { ; }
136+
LIBC_INLINE constexpr explicit TMReader(const tm *tmptr) : timeptr(tmptr) {
137+
;
138+
}
129139

130140
// Strings
131141
LIBC_INLINE constexpr cpp::optional<cpp::string_view>
132142
get_weekday_short_name() const {
133-
if (timeptr->tm_wday >= 0 &&
134-
timeptr->tm_wday < time_constants::DAYS_PER_WEEK)
135-
return time_constants::WEEK_DAY_NAMES[timeptr->tm_wday];
136-
137-
return cpp::nullopt;
143+
return bounds_check(time_constants::WEEK_DAY_NAMES, timeptr->tm_wday);
138144
}
139145

140146
LIBC_INLINE constexpr cpp::optional<cpp::string_view>
141147
get_weekday_full_name() const {
142-
if (timeptr->tm_wday >= 0 &&
143-
timeptr->tm_wday < time_constants::DAYS_PER_WEEK)
144-
return time_constants::WEEK_DAY_FULL_NAMES[timeptr->tm_wday];
145-
146-
return cpp::nullopt;
148+
return bounds_check(time_constants::WEEK_DAY_FULL_NAMES, timeptr->tm_wday);
147149
}
148150

149151
LIBC_INLINE constexpr cpp::optional<cpp::string_view>
150152
get_month_short_name() const {
151-
if (timeptr->tm_mon >= 0 &&
152-
timeptr->tm_mon < time_constants::MONTHS_PER_YEAR)
153-
return time_constants::MONTH_NAMES[timeptr->tm_mon];
154-
155-
return cpp::nullopt;
153+
return bounds_check(time_constants::MONTH_NAMES, timeptr->tm_mon);
156154
}
157155

158156
LIBC_INLINE constexpr cpp::optional<cpp::string_view>
159157
get_month_full_name() const {
160-
if (timeptr->tm_mon >= 0 &&
161-
timeptr->tm_mon < time_constants::MONTHS_PER_YEAR)
162-
return time_constants::MONTH_FULL_NAMES[timeptr->tm_mon];
163-
164-
return cpp::nullopt;
158+
return bounds_check(time_constants::MONTH_FULL_NAMES, timeptr->tm_mon);
165159
}
166160

167161
LIBC_INLINE constexpr cpp::string_view get_am_pm() const {
@@ -197,41 +191,49 @@ class TMReader final {
197191
}
198192

199193
LIBC_INLINE constexpr int get_iso_wday() const {
194+
using time_constants::DAYS_PER_WEEK;
195+
using time_constants::MONDAY;
200196
// ISO uses a week that starts on Monday, but struct tm starts its week on
201197
// Sunday. This function normalizes the weekday so that it always returns a
202198
// value 0-6
203-
const int NORMALIZED_WDAY =
204-
timeptr->tm_wday % time_constants::DAYS_PER_WEEK;
205-
return (NORMALIZED_WDAY + (time_constants::DAYS_PER_WEEK - 1)) % 7;
199+
const int NORMALIZED_WDAY = timeptr->tm_wday % DAYS_PER_WEEK;
200+
return (NORMALIZED_WDAY + (DAYS_PER_WEEK - MONDAY)) % DAYS_PER_WEEK;
206201
}
207202

208203
// returns the week of the current year, with weeks starting on start_day.
209204
LIBC_INLINE constexpr int get_week(time_constants::WeekDay start_day) const {
205+
using time_constants::DAYS_PER_WEEK;
210206
// The most recent start_day. The rest of the days into the current week
211207
// don't count, so ignore them.
212208
// Also add 7 to handle start_day > tm_wday
213209
const int start_of_cur_week =
214210
timeptr->tm_yday -
215-
((timeptr->tm_wday + time_constants::DAYS_PER_WEEK - start_day) %
216-
time_constants::DAYS_PER_WEEK);
211+
((timeptr->tm_wday + DAYS_PER_WEEK - start_day) % DAYS_PER_WEEK);
217212

218-
// Add 1 since the first week may start with day 0
213+
// The original formula is ceil((start_of_cur_week + 1) / DAYS_PER_WEEK)
214+
// That becomes (start_of_cur_week + 1 + DAYS_PER_WEEK - 1) / DAYS_PER_WEEK)
215+
// Which simplifies to (start_of_cur_week + DAYS_PER_WEEK) / DAYS_PER_WEEK
219216
const int ceil_weeks_since_start =
220-
((start_of_cur_week + 1) + (time_constants::DAYS_PER_WEEK - 1)) /
221-
time_constants::DAYS_PER_WEEK;
217+
(start_of_cur_week + DAYS_PER_WEEK) / DAYS_PER_WEEK;
218+
222219
return ceil_weeks_since_start;
223220
}
224221

225222
LIBC_INLINE constexpr int get_iso_week() const {
226-
const time_constants::WeekDay start_day = time_constants::MONDAY;
223+
using time_constants::DAYS_PER_WEEK;
224+
using time_constants::ISO_FIRST_DAY_OF_YEAR;
225+
using time_constants::MONDAY;
226+
using time_constants::WeekDay;
227+
using time_constants::WEEKS_PER_YEAR;
228+
229+
constexpr WeekDay START_DAY = MONDAY;
227230

228231
// The most recent start_day. The rest of the days into the current week
229232
// don't count, so ignore them.
230233
// Also add 7 to handle start_day > tm_wday
231234
const int start_of_cur_week =
232235
timeptr->tm_yday -
233-
((timeptr->tm_wday + time_constants::DAYS_PER_WEEK - start_day) %
234-
time_constants::DAYS_PER_WEEK);
236+
((timeptr->tm_wday + DAYS_PER_WEEK - START_DAY) % DAYS_PER_WEEK);
235237

236238
// if the week starts in the previous year, and also if the 4th of this year
237239
// is not in this week.
@@ -243,10 +245,8 @@ class TMReader final {
243245
// in the next year. We know get_year() - 1 must extend into get_year(),
244246
// so here we check if it also extended into get_year() - 2 and add 1 week
245247
// if it does.
246-
return 52 + ((days_into_prev_year % time_constants::DAYS_PER_WEEK) >
247-
time_constants::ISO_FIRST_DAY_OF_YEAR
248-
? 1
249-
: 0);
248+
return WEEKS_PER_YEAR +
249+
((days_into_prev_year % DAYS_PER_WEEK) > ISO_FIRST_DAY_OF_YEAR);
250250
}
251251

252252
// subtract 1 to account for yday being 0 indexed
@@ -261,16 +261,13 @@ class TMReader final {
261261

262262
// else just calculate the current week like normal.
263263
const int ceil_weeks_since_start =
264-
((start_of_cur_week + 1) + (time_constants::DAYS_PER_WEEK - 1)) /
265-
time_constants::DAYS_PER_WEEK;
264+
(start_of_cur_week + DAYS_PER_WEEK) / DAYS_PER_WEEK;
266265

267266
// add 1 if this year's first week starts in the previous year.
268-
return ceil_weeks_since_start +
269-
(((start_of_cur_week + time_constants::DAYS_PER_WEEK) %
270-
time_constants::DAYS_PER_WEEK) >
271-
time_constants::ISO_FIRST_DAY_OF_YEAR
272-
? 1
273-
: 0);
267+
const int WEEK_STARTS_IN_PREV_YEAR =
268+
((start_of_cur_week + time_constants::DAYS_PER_WEEK) %
269+
time_constants::DAYS_PER_WEEK) > time_constants::ISO_FIRST_DAY_OF_YEAR;
270+
return ceil_weeks_since_start + WEEK_STARTS_IN_PREV_YEAR;
274271
}
275272

276273
LIBC_INLINE constexpr int get_iso_year() const {
@@ -303,11 +300,10 @@ class TMReader final {
303300
304301
wday - yday < 7 - 4
305302
*/
306-
return (ISO_WDAY - timeptr->tm_yday <
307-
time_constants::DAYS_PER_WEEK -
308-
time_constants::ISO_FIRST_DAY_OF_YEAR)
309-
? BASE_YEAR
310-
: BASE_YEAR - 1;
303+
const int IS_CUR_YEAR = (ISO_WDAY - timeptr->tm_yday <
304+
time_constants::DAYS_PER_WEEK -
305+
time_constants::ISO_FIRST_DAY_OF_YEAR);
306+
return BASE_YEAR - !IS_CUR_YEAR;
311307
}
312308

313309
// last week
@@ -328,12 +324,10 @@ class TMReader final {
328324
329325
wday + remaining days < 7 - 4
330326
*/
331-
332-
return (ISO_WDAY + DAYS_LEFT_IN_YEAR <
333-
time_constants::DAYS_PER_WEEK -
334-
time_constants::ISO_FIRST_DAY_OF_YEAR)
335-
? BASE_YEAR + 1
336-
: BASE_YEAR;
327+
const int IS_NEXT_YEAR =
328+
(ISO_WDAY + DAYS_LEFT_IN_YEAR <
329+
time_constants::DAYS_PER_WEEK - time_constants::ISO_FIRST_DAY_OF_YEAR);
330+
return BASE_YEAR + IS_NEXT_YEAR;
337331
}
338332

339333
LIBC_INLINE constexpr time_t get_epoch() const {

0 commit comments

Comments
 (0)