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 }