This source file includes following definitions.
- tm_diff
- gmt_offset
- main
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 #include <config.h>
20
21 #include "parse-datetime.h"
22
23 #include <errno.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <unistd.h>
28
29 #include "macros.h"
30
31 #ifdef DEBUG
32 #define LOG(str, now, res) \
33 printf ("string '%s' diff %d %d\n", \
34 str, res.tv_sec - now.tv_sec, res.tv_nsec - now.tv_nsec);
35 #else
36 #define LOG(str, now, res) (void) 0
37 #endif
38
39 static const char *const day_table[] =
40 {
41 "SUNDAY",
42 "MONDAY",
43 "TUESDAY",
44 "WEDNESDAY",
45 "THURSDAY",
46 "FRIDAY",
47 "SATURDAY",
48 NULL
49 };
50
51
52 #if ! HAVE_TM_GMTOFF
53
54
55
56
57
58
59
60
61
62
63 #define SHR(a, b) \
64 (-1 >> 1 == -1 \
65 ? (a) >> (b) \
66 : (a) / (1 << (b)) - ((a) % (1 << (b)) < 0))
67
68 #define TM_YEAR_BASE 1900
69
70
71
72
73
74 static long int
75 tm_diff (struct tm const *a, struct tm const *b)
76 {
77
78
79 int a4 = SHR (a->tm_year, 2) + SHR (TM_YEAR_BASE, 2) - ! (a->tm_year & 3);
80 int b4 = SHR (b->tm_year, 2) + SHR (TM_YEAR_BASE, 2) - ! (b->tm_year & 3);
81 int a100 = a4 / 25 - (a4 % 25 < 0);
82 int b100 = b4 / 25 - (b4 % 25 < 0);
83 int a400 = SHR (a100, 2);
84 int b400 = SHR (b100, 2);
85 int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
86 long int ayear = a->tm_year;
87 long int years = ayear - b->tm_year;
88 long int days = (365 * years + intervening_leap_days
89 + (a->tm_yday - b->tm_yday));
90 return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour))
91 + (a->tm_min - b->tm_min))
92 + (a->tm_sec - b->tm_sec));
93 }
94 #endif
95
96 static long
97 gmt_offset (time_t s)
98 {
99 long gmtoff;
100
101 #if !HAVE_TM_GMTOFF
102 struct tm tm_local = *localtime (&s);
103 struct tm tm_gmt = *gmtime (&s);
104
105 gmtoff = tm_diff (&tm_local, &tm_gmt);
106 #else
107 gmtoff = localtime (&s)->tm_gmtoff;
108 #endif
109
110 return gmtoff;
111 }
112
113 int
114 main (_GL_UNUSED int argc, char **argv)
115 {
116 struct timespec result;
117 struct timespec result2;
118 struct timespec expected;
119 struct timespec now;
120 const char *p;
121 int i;
122 long gmtoff;
123 time_t ref_time = 1304250918;
124
125
126
127
128
129 setenv ("TZ", "EST5EDT,M3.2.0,M11.1.0", 1);
130
131 gmtoff = gmt_offset (ref_time);
132
133
134
135
136 p = "2011-05-01T11:55:18";
137 expected.tv_sec = ref_time - gmtoff;
138 expected.tv_nsec = 0;
139 ASSERT (parse_datetime (&result, p, 0));
140 LOG (p, expected, result);
141 ASSERT (expected.tv_sec == result.tv_sec
142 && expected.tv_nsec == result.tv_nsec);
143
144
145
146 p = "2011-05-01 11:55:18";
147 expected.tv_sec = ref_time - gmtoff;
148 expected.tv_nsec = 0;
149 ASSERT (parse_datetime (&result, p, 0));
150 LOG (p, expected, result);
151 ASSERT (expected.tv_sec == result.tv_sec
152 && expected.tv_nsec == result.tv_nsec);
153
154
155
156
157 p = "2011-05-01T11:55:18Z";
158 expected.tv_sec = ref_time;
159 expected.tv_nsec = 0;
160 ASSERT (parse_datetime (&result, p, 0));
161 LOG (p, expected, result);
162 ASSERT (expected.tv_sec == result.tv_sec
163 && expected.tv_nsec == result.tv_nsec);
164
165
166
167 p = "2011-05-01 11:55:18Z";
168 expected.tv_sec = ref_time;
169 expected.tv_nsec = 0;
170 ASSERT (parse_datetime (&result, p, 0));
171 LOG (p, expected, result);
172 ASSERT (expected.tv_sec == result.tv_sec
173 && expected.tv_nsec == result.tv_nsec);
174
175
176
177
178 p = "2011-05-01T11:55:18-07:00";
179 expected.tv_sec = 1304276118;
180 expected.tv_nsec = 0;
181 ASSERT (parse_datetime (&result, p, 0));
182 LOG (p, expected, result);
183 ASSERT (expected.tv_sec == result.tv_sec
184 && expected.tv_nsec == result.tv_nsec);
185
186
187
188 p = "2011-05-01 11:55:18-07:00";
189 expected.tv_sec = 1304276118;
190 expected.tv_nsec = 0;
191 ASSERT (parse_datetime (&result, p, 0));
192 LOG (p, expected, result);
193 ASSERT (expected.tv_sec == result.tv_sec
194 && expected.tv_nsec == result.tv_nsec);
195
196
197
198
199 p = "2011-05-01T11:55:18-07";
200 expected.tv_sec = 1304276118;
201 expected.tv_nsec = 0;
202 ASSERT (parse_datetime (&result, p, 0));
203 LOG (p, expected, result);
204 ASSERT (expected.tv_sec == result.tv_sec
205 && expected.tv_nsec == result.tv_nsec);
206
207
208
209 p = "2011-05-01 11:55:18-07";
210 expected.tv_sec = 1304276118;
211 expected.tv_nsec = 0;
212 ASSERT (parse_datetime (&result, p, 0));
213 LOG (p, expected, result);
214 ASSERT (expected.tv_sec == result.tv_sec
215 && expected.tv_nsec == result.tv_nsec);
216
217
218 now.tv_sec = 4711;
219 now.tv_nsec = 1267;
220 p = "now";
221 ASSERT (parse_datetime (&result, p, &now));
222 LOG (p, now, result);
223 ASSERT (now.tv_sec == result.tv_sec && now.tv_nsec == result.tv_nsec);
224
225 now.tv_sec = 4711;
226 now.tv_nsec = 1267;
227 p = "tomorrow";
228 ASSERT (parse_datetime (&result, p, &now));
229 LOG (p, now, result);
230 ASSERT (now.tv_sec + 24 * 60 * 60 == result.tv_sec
231 && now.tv_nsec == result.tv_nsec);
232
233 now.tv_sec = 4711;
234 now.tv_nsec = 1267;
235 p = "yesterday";
236 ASSERT (parse_datetime (&result, p, &now));
237 LOG (p, now, result);
238 ASSERT (now.tv_sec - 24 * 60 * 60 == result.tv_sec
239 && now.tv_nsec == result.tv_nsec);
240
241 now.tv_sec = 4711;
242 now.tv_nsec = 1267;
243 p = "4 hours";
244 ASSERT (parse_datetime (&result, p, &now));
245 LOG (p, now, result);
246 ASSERT (now.tv_sec + 4 * 60 * 60 == result.tv_sec
247 && now.tv_nsec == result.tv_nsec);
248
249
250 now.tv_sec = 4711;
251 now.tv_nsec = 1267;
252 p = "UTC+400 +24 hours";
253 ASSERT (parse_datetime (&result, p, &now));
254 LOG (p, now, result);
255 p = "UTC+400 +1 day";
256 ASSERT (parse_datetime (&result2, p, &now));
257 LOG (p, now, result2);
258 ASSERT (result.tv_sec == result2.tv_sec
259 && result.tv_nsec == result2.tv_nsec);
260
261
262 now.tv_sec = 4711;
263 now.tv_nsec = 1267;
264 p = "UTC+14:00";
265 ASSERT (parse_datetime (&result, p, &now));
266 LOG (p, now, result);
267 p = "UTC+14";
268 ASSERT (parse_datetime (&result2, p, &now));
269 LOG (p, now, result2);
270 ASSERT (result.tv_sec == result2.tv_sec
271 && result.tv_nsec == result2.tv_nsec);
272 p = "UTC+1400";
273 ASSERT (parse_datetime (&result2, p, &now));
274 LOG (p, now, result2);
275 ASSERT (result.tv_sec == result2.tv_sec
276 && result.tv_nsec == result2.tv_nsec);
277
278 now.tv_sec = 4711;
279 now.tv_nsec = 1267;
280 p = "UTC-14:00";
281 ASSERT (parse_datetime (&result, p, &now));
282 LOG (p, now, result);
283 p = "UTC-14";
284 ASSERT (parse_datetime (&result2, p, &now));
285 LOG (p, now, result2);
286 ASSERT (result.tv_sec == result2.tv_sec
287 && result.tv_nsec == result2.tv_nsec);
288 p = "UTC-1400";
289 ASSERT (parse_datetime (&result2, p, &now));
290 LOG (p, now, result2);
291 ASSERT (result.tv_sec == result2.tv_sec
292 && result.tv_nsec == result2.tv_nsec);
293
294 now.tv_sec = 4711;
295 now.tv_nsec = 1267;
296 p = "UTC+0:15";
297 ASSERT (parse_datetime (&result, p, &now));
298 LOG (p, now, result);
299 p = "UTC+0015";
300 ASSERT (parse_datetime (&result2, p, &now));
301 LOG (p, now, result2);
302 ASSERT (result.tv_sec == result2.tv_sec
303 && result.tv_nsec == result2.tv_nsec);
304
305 now.tv_sec = 4711;
306 now.tv_nsec = 1267;
307 p = "UTC-1:30";
308 ASSERT (parse_datetime (&result, p, &now));
309 LOG (p, now, result);
310 p = "UTC-130";
311 ASSERT (parse_datetime (&result2, p, &now));
312 LOG (p, now, result2);
313 ASSERT (result.tv_sec == result2.tv_sec
314 && result.tv_nsec == result2.tv_nsec);
315
316
317
318 now.tv_sec = 4711;
319 now.tv_nsec = 1267;
320 p = "UTC+25:00";
321 ASSERT (!parse_datetime (&result, p, &now));
322
323
324 now.tv_sec = 4711;
325 now.tv_nsec = 1267;
326 p = "UTC+4:00 +40 yesterday";
327 ASSERT (!parse_datetime (&result, p, &now));
328 p = "UTC+4:00 next yesterday";
329 ASSERT (!parse_datetime (&result, p, &now));
330 p = "UTC+4:00 tomorrow ago";
331 ASSERT (!parse_datetime (&result, p, &now));
332 p = "UTC+4:00 tomorrow hence";
333 ASSERT (!parse_datetime (&result, p, &now));
334 p = "UTC+4:00 40 now ago";
335 ASSERT (!parse_datetime (&result, p, &now));
336 p = "UTC+4:00 last tomorrow";
337 ASSERT (!parse_datetime (&result, p, &now));
338 p = "UTC+4:00 -4 today";
339 ASSERT (!parse_datetime (&result, p, &now));
340
341
342 now.tv_sec = 4711;
343 now.tv_nsec = 1267;
344 p = "UTC+400 tomorrow";
345 ASSERT (parse_datetime (&result, p, &now));
346 LOG (p, now, result);
347 p = "UTC+400 +1 day";
348 ASSERT (parse_datetime (&result2, p, &now));
349 LOG (p, now, result2);
350 ASSERT (result.tv_sec == result2.tv_sec
351 && result.tv_nsec == result2.tv_nsec);
352 p = "UTC+400 1 day hence";
353 ASSERT (parse_datetime (&result2, p, &now));
354 LOG (p, now, result2);
355 ASSERT (result.tv_sec == result2.tv_sec
356 && result.tv_nsec == result2.tv_nsec);
357 now.tv_sec = 4711;
358 now.tv_nsec = 1267;
359 p = "UTC+400 yesterday";
360 ASSERT (parse_datetime (&result, p, &now));
361 LOG (p, now, result);
362 p = "UTC+400 1 day ago";
363 ASSERT (parse_datetime (&result2, p, &now));
364 LOG (p, now, result2);
365 ASSERT (result.tv_sec == result2.tv_sec
366 && result.tv_nsec == result2.tv_nsec);
367 now.tv_sec = 4711;
368 now.tv_nsec = 1267;
369 p = "UTC+400 now";
370 ASSERT (parse_datetime (&result, p, &now));
371 LOG (p, now, result);
372 p = "UTC+400 +0 minutes";
373 ASSERT (parse_datetime (&result2, p, &now));
374 LOG (p, now, result2);
375 ASSERT (result.tv_sec == result2.tv_sec
376 && result.tv_nsec == result2.tv_nsec);
377
378
379 setenv ("TZ", "UTC0", 1);
380 for (i = 0; day_table[i]; i++)
381 {
382 unsigned int thur2 = 7 * 24 * 3600;
383 char tmp[32];
384 sprintf (tmp, "NEXT %s", day_table[i]);
385 now.tv_sec = thur2 + 4711;
386 now.tv_nsec = 1267;
387 ASSERT (parse_datetime (&result, tmp, &now));
388 LOG (tmp, now, result);
389 ASSERT (result.tv_nsec == 0);
390 ASSERT (result.tv_sec == thur2 + (i == 4 ? 7 : (i + 3) % 7) * 24 * 3600);
391
392 sprintf (tmp, "LAST %s", day_table[i]);
393 now.tv_sec = thur2 + 4711;
394 now.tv_nsec = 1267;
395 ASSERT (parse_datetime (&result, tmp, &now));
396 LOG (tmp, now, result);
397 ASSERT (result.tv_nsec == 0);
398 ASSERT (result.tv_sec == thur2 + ((i + 3) % 7 - 7) * 24 * 3600);
399 }
400
401 p = "THURSDAY UTC+00";
402 now.tv_sec = 0;
403 now.tv_nsec = 0;
404 ASSERT (parse_datetime (&result, p, &now));
405 LOG (p, now, result);
406 ASSERT (result.tv_sec == now.tv_sec
407 && result.tv_nsec == now.tv_nsec);
408
409 p = "FRIDAY UTC+00";
410 now.tv_sec = 0;
411 now.tv_nsec = 0;
412 ASSERT (parse_datetime (&result, p, &now));
413 LOG (p, now, result);
414 ASSERT (result.tv_sec == 24 * 3600
415 && result.tv_nsec == now.tv_nsec);
416
417
418
419 ASSERT ( ! parse_datetime (&result, "\xb0", &now));
420
421
422
423 ASSERT ( ! parse_datetime (&result, "TZ=\"\"\"", &now));
424 ASSERT ( ! parse_datetime (&result, "TZ=\"\" \"", &now));
425
426 ASSERT ( ! parse_datetime (&result, "TZ=\"", &now));
427 ASSERT ( ! parse_datetime (&result, "TZ=\"\\\"", &now));
428 ASSERT ( ! parse_datetime (&result, "TZ=\"\\n", &now));
429 ASSERT ( ! parse_datetime (&result, "TZ=\"\\n\"", &now));
430
431 ASSERT ( parse_datetime (&result, "TZ=\"\"", &now));
432 ASSERT ( parse_datetime (&result, "TZ=\"\" ", &now));
433 ASSERT ( parse_datetime (&result, " TZ=\"\"", &now));
434
435
436 #if !defined __NetBSD__
437 ASSERT ( parse_datetime (&result, "TZ=\"\\\\\"", &now));
438 ASSERT ( parse_datetime (&result, "TZ=\"\\\"\"", &now));
439 #endif
440
441
442 {
443 static char const bufprefix[] = "TZ=\"";
444 long int tzname_max = -1;
445 errno = 0;
446 #ifdef _SC_TZNAME_MAX
447 tzname_max = sysconf (_SC_TZNAME_MAX);
448 #endif
449 enum { tzname_alloc = 2000 };
450 if (tzname_max < 0)
451 tzname_max = errno ? 6 : tzname_alloc;
452 int tzname_len = tzname_alloc < tzname_max ? tzname_alloc : tzname_max;
453 static char const bufsuffix[] = "0\" 1970-01-01 01:02:03.123456789";
454 enum { bufsize = sizeof bufprefix - 1 + tzname_alloc + sizeof bufsuffix };
455 char buf[bufsize];
456 memcpy (buf, bufprefix, sizeof bufprefix - 1);
457 memset (buf + sizeof bufprefix - 1, 'X', tzname_len);
458 strcpy (buf + sizeof bufprefix - 1 + tzname_len, bufsuffix);
459 ASSERT (parse_datetime (&result, buf, &now));
460 LOG (buf, now, result);
461 ASSERT (result.tv_sec == 1 * 60 * 60 + 2 * 60 + 3
462 && result.tv_nsec == 123456789);
463 }
464
465 return 0;
466 }