[PATCH v2 2/4] time: shorten year determination loop

Jan Beulich posted 4 patches 1 month ago
[PATCH v2 2/4] time: shorten year determination loop
Posted by Jan Beulich 1 month ago
For dates very far into the future (the MC146818 RTC's century byte can go
up to the 99th century), the present year-wise loop would become somewhat
inefficient (taking perhaps several thousand iterations). Prefix that loop
with a 400-year granular calculation (somewhat like the earlier loop does
for dates in the past).

Signed-off-by: Jan Beulich <jbeulich@suse.com>
---
v2: New.

--- a/xen/common/time.c
+++ b/xen/common/time.c
@@ -27,6 +27,8 @@
 #define __isleap(year) \
   ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
 
+#define DAYS_IN_400_YEARS (365 * 303 + 366 * 97)
+
 /* How many days are in each month.  */
 static const unsigned short int __mon_lengths[2][12] = {
     /* Normal years.  */
@@ -57,7 +59,7 @@ struct tm gmtime(unsigned long t)
     while ( t & (1UL<<39) )
     {
         y -= 400;
-        t += ((unsigned long)(365 * 303 + 366 * 97)) * SECS_PER_DAY;
+        t += (unsigned long)DAYS_IN_400_YEARS * SECS_PER_DAY;
     }
     t &= (1UL << 40) - 1;
 #endif
@@ -71,6 +73,11 @@ struct tm gmtime(unsigned long t)
     tbuf.tm_sec = rem % 60;
     /* January 1, 1970 was a Thursday.  */
     tbuf.tm_wday = (4 + days) % 7;
+    if ( days >= DAYS_IN_400_YEARS )
+    {
+        y += (days / DAYS_IN_400_YEARS) * 400;
+        days %= DAYS_IN_400_YEARS;
+    }
     while ( days >= (rem = __isleap(y) ? 366 : 365) )
     {
         ++y;