diff --git a/core/os/time.cpp b/core/os/time.cpp index 90aeb75911..e930d9aef0 100644 --- a/core/os/time.cpp +++ b/core/os/time.cpp @@ -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; \