Update from y2038
Michael G. Schwern [Sat, 27 Sep 2008 19:43:22 +0000 (15:43 -0400)]
Fix a bug in the code to use the system gmtime, it was using localtime.

Define a Year type to avoid mixing years and ints unintentionally.

Do some explicit casting to prop up compilers that don't understand
X % Y can never be larger than Y.

localtime64.c
localtime64.h

index ac422e8..72bd68f 100644 (file)
@@ -189,16 +189,17 @@ int _check_tm(struct tm *tm)
 /* The exceptional centuries without leap years cause the cycle to
    shift by 16
 */
-int _cycle_offset(Int64 year)
+Year _cycle_offset(Year year)
 {
-    const Int64 start_year = 2000;
-    Int64 year_diff  = year - start_year;
+    const Year start_year = 2000;
+    Year year_diff  = year - start_year;
+    Year exceptions;
 
     if( year > start_year )
         year_diff--;
 
-    Int64 exceptions  = year_diff / 100;
-    exceptions       -= year_diff / 400;
+    exceptions  = year_diff / 100;
+    exceptions -= year_diff / 400;
 
     /*
     fprintf(stderr, "# year: %lld, exceptions: %lld, year_diff: %lld\n",
@@ -225,10 +226,10 @@ int _cycle_offset(Int64 year)
    It doesn't need the same leap year status since we only care about
    January 1st.
 */
-int _safe_year(Int64 year)
+int _safe_year(Year year)
 {
     int safe_year;
-    Int64 year_cycle = year + _cycle_offset(year);
+    Year year_cycle = year + _cycle_offset(year);
 
     /* Change non-leap xx00 years to an equivalent */
     if( _is_exception_century(year) )
@@ -256,6 +257,7 @@ int _safe_year(Int64 year)
     return safe_year;
 }
 
+
 struct tm *gmtime64_r (const Time64_T *in_time, struct tm *p)
 {
     int v_tm_sec, v_tm_min, v_tm_hour, v_tm_mon, v_tm_wday;
@@ -263,12 +265,12 @@ struct tm *gmtime64_r (const Time64_T *in_time, struct tm *p)
     int leap;
     Int64 m;
     Time64_T time = *in_time;
-    Int64 year = 70;
+    Year year = 70;
 
     /* Use the system gmtime() if time_t is small enough */
     if( SHOULD_USE_SYSTEM_GMTIME(*in_time) ) {
         time_t safe_time = *in_time;
-        localtime_r(&safe_time, p);
+        gmtime_r(&safe_time, p);
         assert(_check_tm(p));
         return p;
     }
@@ -282,17 +284,20 @@ struct tm *gmtime64_r (const Time64_T *in_time, struct tm *p)
     p->tm_zone   = "UTC";
 #endif
 
-    v_tm_sec =  time % 60;
+    v_tm_sec =  (int)(time % 60);
     time /= 60;
-    v_tm_min =  time % 60;
+    v_tm_min =  (int)(time % 60);
     time /= 60;
-    v_tm_hour = time % 24;
+    v_tm_hour = (int)(time % 24);
     time /= 24;
     v_tm_tday = time;
+
     WRAP (v_tm_sec, v_tm_min, 60);
     WRAP (v_tm_min, v_tm_hour, 60);
     WRAP (v_tm_hour, v_tm_tday, 24);
-    if ((v_tm_wday = (v_tm_tday + 4) % 7) < 0)
+
+    v_tm_wday = (int)((v_tm_tday + 4) % 7);
+    if (v_tm_wday < 0)
         v_tm_wday += 7;
     m = v_tm_tday;
 
@@ -357,7 +362,7 @@ struct tm *gmtime64_r (const Time64_T *in_time, struct tm *p)
     }
 
     p->tm_mday = (int) m + 1;
-    p->tm_yday = julian_days_by_month[leap][v_tm_mon] + m;
+    p->tm_yday = (int) julian_days_by_month[leap][v_tm_mon] + m;
     p->tm_sec = v_tm_sec, p->tm_min = v_tm_min, p->tm_hour = v_tm_hour,
         p->tm_mon = v_tm_mon, p->tm_wday = v_tm_wday;
 
@@ -371,7 +376,7 @@ struct tm *localtime64_r (const Time64_T *time, struct tm *local_tm)
 {
     time_t safe_time;
     struct tm gm_tm;
-    Int64 orig_year;
+    Year orig_year;
     int month_diff;
 
     /* Use the system localtime() if time_t is small enough */
index 5bae08a..3771977 100644 (file)
@@ -29,7 +29,7 @@
 #define SYSTEM_GMTIME_MAX       GMTIME_MAX
 #define SYSTEM_GMTIME_MIN       GMTIME_MIN
 
-/* The system localtime will be faster and more correct inside its range */
+/* It'll be faster */
 #define USE_SYSTEM_LOCALTIME    1
 #define USE_SYSTEM_GMTIME       1
 
@@ -37,6 +37,7 @@
 /* 64 bit types.  Set as appropriate for your system. */
 typedef Quad_t               Time64_T;
 typedef Quad_t               Int64;
+typedef Int64                Year;
 
 struct tm *gmtime64_r    (const Time64_T *, struct tm *);
 struct tm *localtime64_r (const Time64_T *, struct tm *);