sfeed_time_libc.c - sfeed_tests - sfeed tests and RSS and Atom files | |
git clone git://git.codemadness.org/sfeed_tests | |
Log | |
Files | |
Refs | |
README | |
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 includi… | |
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 * 8… | |
39 } else { | |
40 /* general leap year calculation: | |
41 leap years occur mostly every 4 years but every 100 y… | |
42 a leap year is skipped unless the year is divisible b… | |
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) + 94… | |
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_hou… | |
95 } | |
96 | |
97 ll = datetounix(tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hou… | |
98 t2 = (time_t)ll; | |
99 | |
100 if (t1 != t2) { | |
101 printf("result: %lld != %lld\n", (long long)t1, (long lo… | |
102 printf("for: %d, %d, %d, %d, %d, %d\n", | |
103 tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hou… | |
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", … | |
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 } |