[libc-commits] [libc] [libc] create TimeReader to look at a struct tm (PR #126138)
Nick Desaulniers via libc-commits
libc-commits at lists.llvm.org
Thu Feb 6 15:10:45 PST 2025
================
@@ -94,6 +101,255 @@ LIBC_INLINE struct tm *localtime(const time_t *t_ptr) {
return time_utils::gmtime_internal(t_ptr, &result);
}
+// Returns number of years from (1, year).
+LIBC_INLINE constexpr int64_t get_num_of_leap_years_before(int64_t year) {
+ return (year / 4) - (year / 100) + (year / 400);
+}
+
+// Returns True if year is a leap year.
+LIBC_INLINE constexpr bool is_leap_year(const int64_t year) {
+ return (((year) % 4) == 0 && (((year) % 100) != 0 || ((year) % 400) == 0));
+}
+
+LIBC_INLINE constexpr int get_days_in_year(const int year) {
+ return is_leap_year(year) ? time_constants::DAYS_PER_LEAP_YEAR
+ : time_constants::DAYS_PER_NON_LEAP_YEAR;
+}
+
+// This is a helper class that takes a struct tm and lets you inspect its
+// values. Where relevant, results are bounds checked and returned as optionals.
+// This class does not, however, do data normalization except where necessary.
+// It will faithfully return a date of 9999-99-99, even though that makes no
+// sense.
+class TMReader final {
+ const tm *timeptr;
+
+public:
+ LIBC_INLINE constexpr TMReader(const tm *tmptr) : timeptr(tmptr) { ; }
+
+ // Strings
+ LIBC_INLINE constexpr cpp::optional<cpp::string_view>
+ get_weekday_short_name() const {
+ if (timeptr->tm_wday >= 0 &&
+ timeptr->tm_wday < time_constants::DAYS_PER_WEEK)
+ return time_constants::WEEK_DAY_NAMES[timeptr->tm_wday];
+
+ return cpp::nullopt;
+ }
+
+ LIBC_INLINE constexpr cpp::optional<cpp::string_view>
+ get_weekday_full_name() const {
+ if (timeptr->tm_wday >= 0 &&
+ timeptr->tm_wday < time_constants::DAYS_PER_WEEK)
+ return time_constants::WEEK_DAY_FULL_NAMES[timeptr->tm_wday];
+
+ return cpp::nullopt;
+ }
+
+ LIBC_INLINE constexpr cpp::optional<cpp::string_view>
+ get_month_short_name() const {
+ if (timeptr->tm_mon >= 0 &&
+ timeptr->tm_mon < time_constants::MONTHS_PER_YEAR)
+ return time_constants::MONTH_NAMES[timeptr->tm_mon];
+
+ return cpp::nullopt;
+ }
+
+ LIBC_INLINE constexpr cpp::optional<cpp::string_view>
+ get_month_full_name() const {
+ if (timeptr->tm_mon >= 0 &&
+ timeptr->tm_mon < time_constants::MONTHS_PER_YEAR)
+ return time_constants::MONTH_FULL_NAMES[timeptr->tm_mon];
+
+ return cpp::nullopt;
+ }
+
+ LIBC_INLINE constexpr cpp::string_view get_am_pm() const {
+ if (timeptr->tm_hour < 12)
+ return "AM";
+ return "PM";
+ }
+
+ LIBC_INLINE constexpr cpp::string_view get_timezone_name() const {
+ // TODO: timezone support
+ return "UTC";
+ }
+
+ // Numbers
+ LIBC_INLINE constexpr int get_sec() const { return timeptr->tm_sec; }
+ LIBC_INLINE constexpr int get_min() const { return timeptr->tm_min; }
+ LIBC_INLINE constexpr int get_hour() const { return timeptr->tm_hour; }
+ LIBC_INLINE constexpr int get_mday() const { return timeptr->tm_mday; }
+ LIBC_INLINE constexpr int get_mon() const { return timeptr->tm_mon; }
+ LIBC_INLINE constexpr int get_yday() const { return timeptr->tm_yday; }
+ LIBC_INLINE constexpr int get_wday() const { return timeptr->tm_wday; }
+ LIBC_INLINE constexpr int get_isdst() const { return timeptr->tm_isdst; }
+
+ // returns the year, counting from 1900
+ LIBC_INLINE constexpr int get_year_raw() const { return timeptr->tm_year; }
+ // returns the year, counting from 0
+ LIBC_INLINE constexpr int get_year() const {
+ return timeptr->tm_year + time_constants::TIME_YEAR_BASE;
+ }
+
+ LIBC_INLINE constexpr int is_leap_year() const {
+ return time_utils::is_leap_year(get_year());
+ }
+
+ LIBC_INLINE constexpr int get_iso_wday() const {
+ // ISO uses a week that starts on Monday, but struct tm starts its week on
+ // Sunday. This function normalizes the weekday so that it always returns a
+ // value 0-6
+ const int NORMALIZED_WDAY =
+ timeptr->tm_wday % time_constants::DAYS_PER_WEEK;
+ return (NORMALIZED_WDAY + (time_constants::DAYS_PER_WEEK - 1)) % 7;
+ }
+
+ // returns the week of the current year, with weeks starting on start_day.
+ LIBC_INLINE constexpr int get_week(time_constants::WeekDay start_day) const {
+ // The most recent start_day. The rest of the days into the current week
+ // don't count, so ignore them.
+ // Also add 7 to handle start_day > tm_wday
+ const int start_of_cur_week =
+ timeptr->tm_yday -
+ ((timeptr->tm_wday + time_constants::DAYS_PER_WEEK - start_day) %
+ time_constants::DAYS_PER_WEEK);
+
+ // Add 1 since the first week may start with day 0
+ const int ceil_weeks_since_start =
+ ((start_of_cur_week + 1) + (time_constants::DAYS_PER_WEEK - 1)) /
+ time_constants::DAYS_PER_WEEK;
+ return ceil_weeks_since_start;
+ }
+
+ LIBC_INLINE constexpr int get_iso_week() const {
----------------
nickdesaulniers wrote:
Does adding `using time_constants;` in each of these methods help make the equations slightly more readable?
https://github.com/llvm/llvm-project/pull/126138
More information about the libc-commits
mailing list