Merge pull request #106759 from aaronp64/time_year_calc

Update `time.cpp` year/unix time conversions to be constant time
This commit is contained in:
Thaddeus Crews
2025-05-26 11:24:22 -05:00

View File

@@ -37,6 +37,33 @@
#define IS_LEAP_YEAR(year) (!((year) % 4) && (((year) % 100) || !((year) % 400)))
#define YEAR_SIZE(year) (IS_LEAP_YEAR(year) ? 366 : 365)
static constexpr int64_t total_leap_days(int64_t p_year) {
if (p_year > 0) {
--p_year;
return 1 + (p_year / 4 - p_year / 100 + p_year / 400);
}
return p_year / 4 - p_year / 100 + p_year / 400;
}
static constexpr int64_t year_to_days(int64_t p_year) {
return p_year * 365 + total_leap_days(p_year);
}
static constexpr int64_t days_to_year(int64_t p_days) {
int64_t year = 400 * p_days / year_to_days(400);
if (year < 0) {
--year;
}
if (year_to_days(year) > p_days) {
--year;
}
if (year_to_days(year + 1) <= p_days) {
++year;
}
return year;
}
#define YEAR_KEY "year"
#define MONTH_KEY "month"
#define DAY_KEY "day"
@@ -72,16 +99,10 @@ static const uint8_t MONTH_DAYS_TABLE[2][12] = {
int64_t day_number = Math::floor(p_unix_time_val / (double)SECONDS_PER_DAY); \
{ \
int64_t day_number_copy = day_number; \
year = UNIX_EPOCH_YEAR_AD; \
day_number_copy += year_to_days(UNIX_EPOCH_YEAR_AD); \
year = days_to_year(day_number_copy); \
day_number_copy -= year_to_days(year); \
uint8_t month_zero_index = 0; \
while (day_number_copy >= YEAR_SIZE(year)) { \
day_number_copy -= YEAR_SIZE(year); \
year++; \
} \
while (day_number_copy < 0) { \
year--; \
day_number_copy += YEAR_SIZE(year); \
} \
/* After the above, day_number now represents the day of the year (0-index). */ \
while (day_number_copy >= MONTH_DAYS_TABLE[IS_LEAP_YEAR(year)][month_zero_index]) { \
day_number_copy -= MONTH_DAYS_TABLE[IS_LEAP_YEAR(year)][month_zero_index]; \
@@ -116,15 +137,8 @@ static const uint8_t MONTH_DAYS_TABLE[2][12] = {
day_number += MONTH_DAYS_TABLE[IS_LEAP_YEAR(year)][i]; \
} \
/* Add the days in the years to day_number. */ \
if (year >= UNIX_EPOCH_YEAR_AD) { \
for (int64_t iyear = UNIX_EPOCH_YEAR_AD; iyear < year; iyear++) { \
day_number += YEAR_SIZE(iyear); \
} \
} else { \
for (int64_t iyear = UNIX_EPOCH_YEAR_AD - 1; iyear >= year; iyear--) { \
day_number -= YEAR_SIZE(iyear); \
} \
}
day_number += year_to_days(year); \
day_number -= year_to_days(UNIX_EPOCH_YEAR_AD);
#define PARSE_ISO8601_STRING(ret) \
int64_t year = UNIX_EPOCH_YEAR_AD; \