sfeed_time_libc.c - sfeed_tests - sfeed tests and RSS and Atom files
 (HTM) git clone git://git.codemadness.org/sfeed_tests
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
       sfeed_time_libc.c (3196B)
       ---
            1 /*
            2 Test datetounix against timegm() libc implementation.
            3 
            4 Extract datetounix() function from sfeed.c:
            5 
            6 echo 'static long long'
            7 awk '/^datetounix/ { d=1; } d && /^}$/ { exit(0); } d' < sfeed.c
            8 echo '}'
            9 */
           10 
           11 #include <err.h>
           12 #include <stdio.h>
           13 #include <stdlib.h>
           14 #include <string.h>
           15 #include <time.h>
           16 
           17 static long long
           18 datetounix(long long year, int mon, int day, int hour, int min, int sec)
           19 {
           20         /* seconds in a month in a regular (non-leap) year */
           21         static const long secs_through_month[] = {
           22                 0, 31 * 86400, 59 * 86400, 90 * 86400,
           23                 120 * 86400, 151 * 86400, 181 * 86400, 212 * 86400,
           24                 243 * 86400, 273 * 86400, 304 * 86400, 334 * 86400 };
           25         int is_leap = 0, cycles, centuries = 0, leaps = 0, rem;
           26         long long t;
           27 
           28         /* optimization: handle common range year 1902 up to and including 2038 */
           29         if (year - 2ULL <= 136) {
           30                 /* amount of leap days relative to 1970: every 4 years */
           31                 leaps = (year - 68) >> 2;
           32                 if (!((year - 68) & 3)) {
           33                         leaps--;
           34                         is_leap = 1;
           35                 } else {
           36                         is_leap = 0;
           37                 }
           38                 t = 31536000 * (year - 70) + (86400 * leaps); /* 365 * 86400 = 31536000 */
           39         } else {
           40                 /* general leap year calculation:
           41                    leap years occur mostly every 4 years but every 100 years
           42                    a leap year is skipped unless the year is divisible by 400 */
           43                 cycles = (year - 100) / 400;
           44                 rem = (year - 100) % 400;
           45                 if (rem < 0) {
           46                         cycles--;
           47                         rem += 400;
           48                 }
           49                 if (!rem) {
           50                         is_leap = 1;
           51                 } else {
           52                         if (rem >= 300) {
           53                                 centuries = 3;
           54                                 rem -= 300;
           55                         } else if (rem >= 200) {
           56                                 centuries = 2;
           57                                 rem -= 200;
           58                         } else if (rem >= 100) {
           59                                 centuries = 1;
           60                                 rem -= 100;
           61                         }
           62                         if (rem) {
           63                                 leaps = rem / 4U;
           64                                 rem %= 4U;
           65                                 is_leap = !rem;
           66                         }
           67                 }
           68                 leaps += (97 * cycles) + (24 * centuries) - is_leap;
           69 
           70                 /* adjust 8 leap days from 1970 up to and including 2000:
           71                    ((30 * 365) + 8) * 86400 = 946771200 */
           72                 t = ((year - 100) * 31536000LL) + (leaps * 86400LL) + 946771200LL;
           73         }
           74         t += secs_through_month[mon];
           75         if (is_leap && mon >= 2)
           76                 t += 86400;
           77         t += 86400LL * (day - 1);
           78         t += 3600LL * hour;
           79         t += 60LL * min;
           80         t += sec;
           81 
           82         return t;
           83 }
           84 
           85 void
           86 testtm(struct tm *tm)
           87 {
           88         time_t t1, t2; /* assume time_t is signed 64-bit */
           89         long long ll;
           90 
           91         t1 = timegm(tm);
           92         if (t1 == (time_t)-1) {
           93                 errx(1, "timegm failed for %d, %d, %d, %d, %d, %d\n",
           94                         tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
           95         }
           96 
           97         ll = datetounix(tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
           98         t2 = (time_t)ll;
           99 
          100         if (t1 != t2) {
          101                 printf("result: %lld != %lld\n", (long long)t1, (long long)t2);
          102                 printf("for: %d, %d, %d, %d, %d, %d\n",
          103                         tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
          104                 exit(1);
          105         }
          106 }
          107 
          108 int
          109 main(void)
          110 {
          111         struct tm tm;
          112         int y, mon, d;
          113         long long counter = 0;
          114 
          115         for (y = -2069; y < 2069; y++) {
          116                 for (mon = 0; mon < 12; mon++) {
          117                         for (d = 1; d <= 31; d++) {
          118 /*                                printf("DEBUG: comparing %d %d %d\n", y, mon, d);*/
          119 
          120                                 memset(&tm, 0, sizeof(tm));
          121                                 tm.tm_year = y - 1900;
          122                                 tm.tm_mon = mon - 1;
          123                                 tm.tm_mday = d;
          124                                 tm.tm_hour = 0;
          125                                 tm.tm_min = 0;
          126                                 tm.tm_sec = 0;
          127                                 tm.tm_isdst = -1;
          128 
          129                                 testtm(&tm);
          130                                 counter++;
          131                         }
          132                 }
          133         }
          134         printf("%lld dates compared, all OK\n", counter);
          135 
          136         return 0;
          137 }