@@ -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
5050LIBC_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) {
124124class 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+
127135public:
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