[PATCH 1/1] offset: optimized calculation of year from unix timestamp
gary@garygende.com
gary@garygende.com
Thu Aug 7 09:13:50 GMT 2025
---
time/offtime.c | 40 +++++++++++++++++++++++++++-------------
1 file changed, 27 insertions(+), 13 deletions(-)
diff --git a/time/offtime.c b/time/offtime.c
index c94573e931..aae98ccf62 100644
--- a/time/offtime.c
+++ b/time/offtime.c
@@ -20,6 +20,11 @@
#define SECS_PER_HOUR (60 * 60)
#define SECS_PER_DAY (SECS_PER_HOUR * 24)
+#define DAYS_OFFSET (280 * 365 + 89 * 366)
+#define DIVISOR_400 (303 * 365 + 97 * 366)
+#define DIVISOR_100 (76 * 365 + 24 * 366)
+#define DIVISOR_4 (3 * 365 + 366)
+#define DIVISOR_1 365
/* Compute the `struct tm' representation of T,
offset OFFSET seconds east of UTC,
@@ -52,22 +57,31 @@ __offtime (__time64_t t, long int offset, struct tm
*tp)
tp->tm_wday = (4 + days) % 7;
if (tp->tm_wday < 0)
tp->tm_wday += 7;
- y = 1970;
-#define DIV(a, b) ((a) / (b) - ((a) % (b) < 0))
-#define LEAPS_THRU_END_OF(y) (DIV (y, 4) - DIV (y, 100) + DIV (y, 400))
+ #define MIN_YEAR_GROUP_NUM(a,b) (((a)<(b))?(a):(b))
+ /* Start at the begining of a 400 year leapyear cycle */
+ y = 1601;
+ days += DAYS_OFFSET;
- while (days < 0 || days >= (__isleap (y) ? 366 : 365))
- {
- /* Guess a corrected year, assuming 365 days per year. */
- __time64_t yg = y + days / 365 - (days % 365 < 0);
+ y += (days / DIVISOR_400) * 400;
+ days -= (days / DIVISOR_400) * DIVISOR_400;
+
+ /* account for 3x 100 yr cycles being 1 day shorter than a 400 yr
cycle */
+ y += MIN_YEAR_GROUP_NUM(days / DIVISOR_100, 3) * 100;
+ days -= MIN_YEAR_GROUP_NUM(days / DIVISOR_100, 3) * DIVISOR_100;
+
+ y += (days / DIVISOR_4) * 4;
+ days -= (days / DIVISOR_4) * DIVISOR_4;
+
+ y += MIN_YEAR_GROUP_NUM(days / DIVISOR_1, 3);
+ days -= MIN_YEAR_GROUP_NUM(days / DIVISOR_1, 3) * DIVISOR_1;
+
+ if (days < 0) {
+ --y;
+ days += 365;
+ if (__isleap(y)) ++days;
+ }
- /* Adjust DAYS and Y to match the guessed year. */
- days -= ((yg - y) * 365
- + LEAPS_THRU_END_OF (yg - 1)
- - LEAPS_THRU_END_OF (y - 1));
- y = yg;
- }
tp->tm_year = y - 1900;
if (tp->tm_year != y - 1900)
{
--
2.43.0
More information about the Libc-alpha
mailing list