1 /* $NetBSD: t_parsedate.c,v 1.31 2020/10/19 15:06:49 kre Exp $ */ 2 /*- 3 * Copyright (c) 2010, 2015 The NetBSD Foundation, Inc. 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in 14 * the documentation and/or other materials provided with the 15 * distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 20 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 21 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 23 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 25 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 27 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31 #include <sys/cdefs.h> 32 __RCSID("$NetBSD: t_parsedate.c,v 1.31 2020/10/19 15:06:49 kre Exp $"); 33 34 #include <atf-c.h> 35 #include <errno.h> 36 #include <stdio.h> 37 #include <stdlib.h> 38 #include <time.h> 39 #include <util.h> 40 41 /* 42 * ANY is used as a placeholder for values that do not need to be 43 * checked. The actual value is arbitrary. We don't use -1 44 * because some tests might want to use -1 as a literal value. 45 */ 46 #define ANY -30215 47 48 /* parsecheck -- 49 * call parsedate(), then call time_to_tm() on the result, 50 * and check that year/month/day/hour/minute/second are as expected. 51 * 52 * time_to_tm should usually be localtime_r or gmtime_r. 53 * 54 * Don't check values specified as ANY. 55 */ 56 static void 57 parsecheck(const char *datestr, const time_t *reftime, const int *zoff, 58 struct tm * time_to_tm(const time_t *, struct tm *), 59 int year, int month, int day, int hour, int minute, int second) 60 { 61 time_t t; 62 struct tm tm; 63 char argstr[128]; 64 65 /* 66 * printable version of the args. 67 * 68 * Note that printf("%.*d", 0, 0)) prints nothing at all, 69 * while printf("%.*d", 1, val) prints the value as usual. 70 */ 71 snprintf(argstr, sizeof(argstr), "%s%s%s, %s%.*jd, %s%.*d", 72 /* NULL or \"<datestr>\" */ 73 (datestr ? "\"" : ""), 74 (datestr ? datestr : "NULL"), 75 (datestr ? "\"" : ""), 76 /* NULL or *reftime */ 77 (reftime ? "" : "NULL"), 78 (reftime ? 1 : 0), 79 (reftime ? (intmax_t)*reftime : (intmax_t)0), 80 /* NULL or *zoff */ 81 (zoff ? "" : "NULL"), 82 (zoff ? 1 : 0), 83 (zoff ? *zoff : 0)); 84 85 ATF_CHECK_MSG((t = parsedate(datestr, reftime, zoff)) != -1, 86 "parsedate(%s) returned -1\n", argstr); 87 if (t == -1) 88 return; 89 90 ATF_CHECK(time_to_tm(&t, &tm) != NULL); 91 if (year != ANY) 92 ATF_CHECK_MSG(tm.tm_year + 1900 == year, 93 "parsedate(%s) expected year %d got %d (+1900)\n", 94 argstr, year, (int)tm.tm_year); 95 if (month != ANY) 96 ATF_CHECK_MSG(tm.tm_mon + 1 == month, 97 "parsedate(%s) expected month %d got %d (+1)\n", 98 argstr, month, (int)tm.tm_mon); 99 if (day != ANY) 100 ATF_CHECK_MSG(tm.tm_mday == day, 101 "parsedate(%s) expected day %d got %d\n", 102 argstr, day, (int)tm.tm_mday); 103 if (hour != ANY) 104 ATF_CHECK_MSG(tm.tm_hour == hour, 105 "parsedate(%s) expected hour %d got %d\n", 106 argstr, hour, (int)tm.tm_hour); 107 if (minute != ANY) 108 ATF_CHECK_MSG(tm.tm_min == minute, 109 "parsedate(%s) expected minute %d got %d\n", 110 argstr, minute, (int)tm.tm_min); 111 if (second != ANY) 112 ATF_CHECK_MSG(tm.tm_sec == second, 113 "parsedate(%s) expected second %d got %d\n", 114 argstr, second, (int)tm.tm_sec); 115 } 116 117 ATF_TC(dates); 118 119 ATF_TC_HEAD(dates, tc) 120 { 121 atf_tc_set_md_var(tc, "descr", "Test unambiguous dates" 122 " (PR lib/44255)"); 123 } 124 125 ATF_TC_BODY(dates, tc) 126 { 127 128 parsecheck("9/10/68", NULL, NULL, localtime_r, 129 2068, 9, 10, 0, 0, 0); /* year < 69: add 2000 */ 130 parsecheck("9/10/69", NULL, NULL, localtime_r, 131 1969, 9, 10, 0, 0, 0); /* 69 <= year < 100: add 1900 */ 132 parsecheck("68-09-10", NULL, NULL, localtime_r, 133 68, 9, 10, 0, 0, 0); /* ISO8601 year remains unchanged */ 134 parsecheck("70-09-10", NULL, NULL, localtime_r, 135 70, 9, 10, 0, 0, 0); /* ISO8601 year remains unchanged */ 136 parsecheck("2006-11-17", NULL, NULL, localtime_r, 137 2006, 11, 17, 0, 0, 0); 138 parsecheck("10/1/2000", NULL, NULL, localtime_r, 139 2000, 10, 1, 0, 0, 0); /* month/day/year */ 140 parsecheck("20 Jun 1994", NULL, NULL, localtime_r, 141 1994, 6, 20, 0, 0, 0); 142 parsecheck("97 September 2", NULL, NULL, localtime_r, 143 1997, 9, 2, 0, 0, 0); 144 parsecheck("23jun2001", NULL, NULL, localtime_r, 145 2001, 6, 23, 0, 0, 0); 146 parsecheck("1-sep-06", NULL, NULL, localtime_r, 147 2006, 9, 1, 0, 0, 0); 148 parsecheck("1/11", NULL, NULL, localtime_r, 149 ANY, 1, 11, 0, 0, 0); /* month/day */ 150 parsecheck("1500-01-02", NULL, NULL, localtime_r, 151 1500, 1, 2, 0, 0, 0); 152 parsecheck("9999-12-21", NULL, NULL, localtime_r, 153 9999, 12, 21, 0, 0, 0); 154 parsecheck("2015.12.07.08.07.35", NULL, NULL, localtime_r, 155 2015, 12, 7, 8, 7, 35); 156 } 157 158 ATF_TC(times); 159 160 ATF_TC_HEAD(times, tc) 161 { 162 atf_tc_set_md_var(tc, "descr", "Test times" 163 " (PR lib/44255)"); 164 } 165 166 ATF_TC_BODY(times, tc) 167 { 168 169 parsecheck("10:01", NULL, NULL, localtime_r, 170 ANY, ANY, ANY, 10, 1, 0); 171 parsecheck("10:12pm", NULL, NULL, localtime_r, 172 ANY, ANY, ANY, 22, 12, 0); 173 parsecheck("12:11:01.000012", NULL, NULL, localtime_r, 174 ANY, ANY, ANY, 12, 11, 1); 175 parsecheck("12:21-0500", NULL, NULL, gmtime_r, 176 ANY, ANY, ANY, 12+5, 21, 0); 177 /* numeric zones not permitted with am/pm ... */ 178 parsecheck("7 a.m. ICT", NULL, NULL, gmtime_r, 179 ANY, ANY, ANY, 7-7, 0, 0); 180 parsecheck("midnight", NULL, NULL, localtime_r, 181 ANY, ANY, ANY, 0, 0, 0); 182 parsecheck("mn", NULL, NULL, localtime_r, 183 ANY, ANY, ANY, 0, 0, 0); 184 parsecheck("noon", NULL, NULL, localtime_r, 185 ANY, ANY, ANY, 12, 0, 0); 186 187 /* 188 * The following tests used to trigger the bug from PR lib/52101 189 * but that is fixed now. 190 * 191 atf_tc_expect_fail("PR lib/52101"); 192 */ 193 194 parsecheck("12:30 am", NULL, NULL, localtime_r, 195 ANY, ANY, ANY, 0, 30, 0); 196 parsecheck("12:30 pm", NULL, NULL, localtime_r, 197 ANY, ANY, ANY, 12, 30, 0); 198 199 /* 200 * Technically, these are invalid, noon and midnight 201 * are neither am, nor pm, but this is what people expect... 202 */ 203 parsecheck("12:00:00 am", NULL, NULL, localtime_r, 204 ANY, ANY, ANY, 0, 0, 0); 205 parsecheck("12:00:00 pm", NULL, NULL, localtime_r, 206 ANY, ANY, ANY, 12, 0, 0); 207 parsecheck("12am", NULL, NULL, localtime_r, 208 ANY, ANY, ANY, 0, 0, 0); 209 parsecheck("12pm", NULL, NULL, localtime_r, 210 ANY, ANY, ANY, 12, 0, 0); 211 212 /* end 52101 bug tests */ 213 214 parsecheck("12 noon", NULL, NULL, localtime_r, 215 ANY, ANY, ANY, 12, 0, 0); 216 parsecheck("12 midnight", NULL, NULL, localtime_r, 217 ANY, ANY, ANY, 0, 0, 0); 218 parsecheck("12 midday", NULL, NULL, localtime_r, /* unlikely! */ 219 ANY, ANY, ANY, 12, 0, 0); 220 parsecheck("12 mn", NULL, NULL, localtime_r, 221 ANY, ANY, ANY, 0, 0, 0); 222 223 parsecheck("12:00 noon", NULL, NULL, localtime_r, 224 ANY, ANY, ANY, 12, 0, 0); 225 parsecheck("12:00 midnight", NULL, NULL, localtime_r, 226 ANY, ANY, ANY, 0, 0, 0); 227 parsecheck("12:00:00 noon", NULL, NULL, localtime_r, 228 ANY, ANY, ANY, 12, 0, 0); 229 parsecheck("12:00:00 midnight", NULL, NULL, localtime_r, 230 ANY, ANY, ANY, 0, 0, 0); 231 } 232 233 ATF_TC(dsttimes); 234 235 ATF_TC_HEAD(dsttimes, tc) 236 { 237 atf_tc_set_md_var(tc, "descr", "Test DST transition times" 238 " (PR lib/47916)"); 239 } 240 241 ATF_TC_BODY(dsttimes, tc) 242 { 243 struct tm tm; 244 time_t t; 245 int tzoff; 246 247 putenv(__UNCONST("TZ=EST")); 248 tzset(); 249 parsecheck("12:0", NULL, NULL, localtime_r, 250 ANY, ANY, ANY, 12, 0, 0); 251 252 putenv(__UNCONST("TZ=Asia/Tokyo")); 253 tzset(); 254 parsecheck("12:0", NULL, NULL, localtime_r, 255 ANY, ANY, ANY, 12, 0, 0); 256 257 /* 258 * When the effective local time is Tue Jul 9 13:21:53 BST 2013, 259 * check mktime("14:00") 260 */ 261 putenv(__UNCONST("TZ=Europe/London")); 262 tzset(); 263 tm = (struct tm){ 264 .tm_year = 2013-1900, .tm_mon = 7-1, .tm_mday = 9, 265 .tm_hour = 13, .tm_min = 21, .tm_sec = 53, 266 .tm_isdst = 0 }; 267 t = mktime(&tm); 268 ATF_CHECK(t != (time_t)-1); 269 parsecheck("14:00", &t, NULL, localtime_r, 270 2013, 7, 9, 14, 0, 0); 271 tzoff = -60; /* British Summer Time */ 272 parsecheck("14:00", &t, &tzoff, localtime_r, 273 2013, 7, 9, 14, 0, 0); 274 } 275 276 ATF_TC(relative); 277 278 ATF_TC_HEAD(relative, tc) 279 { 280 atf_tc_set_md_var(tc, "descr", "Test relative items" 281 " (PR lib/44255)"); 282 } 283 284 ATF_TC_BODY(relative, tc) 285 { 286 struct tm tm; 287 time_t now; 288 289 #define REL_CHECK(s, now, tm) do { \ 290 time_t p, q; \ 291 char nb[30], pb[30], qb[30]; \ 292 p = parsedate(s, &now, NULL); \ 293 q = mktime(&tm); \ 294 ATF_CHECK_EQ_MSG(p, q, \ 295 "From %jd (%24.24s) using \"%s\", obtained %jd (%24.24s); expected %jd (%24.24s)", \ 296 (uintmax_t)now, ctime_r(&now, nb), \ 297 s, (uintmax_t)p, ctime_r(&p, pb), (uintmax_t)q, \ 298 ctime_r(&q, qb)); \ 299 } while (/*CONSTCOND*/0) 300 301 #define isleap(yr) (((yr) & 3) == 0 && (((yr) % 100) != 0 || \ 302 ((1900+(yr)) % 400) == 0)) 303 304 ATF_CHECK(parsedate("-1 month", NULL, NULL) != -1); 305 ATF_CHECK(parsedate("last friday", NULL, NULL) != -1); 306 ATF_CHECK(parsedate("one week ago", NULL, NULL) != -1); 307 ATF_CHECK(parsedate("this thursday", NULL, NULL) != -1); 308 ATF_CHECK(parsedate("next sunday", NULL, NULL) != -1); 309 ATF_CHECK(parsedate("+2 years", NULL, NULL) != -1); 310 311 /* 312 * Test relative to a number of fixed dates. Avoid the 313 * edges of the time_t range to avert under- or overflow 314 * of the relative date, and use a prime step for maximum 315 * coverage of different times of day/week/month/year. 316 */ 317 for (now = 0x00FFFFFF; now < 0xFF000000; now += 3777779) { 318 ATF_CHECK(localtime_r(&now, &tm) != NULL); 319 tm.tm_mday--; 320 /* "yesterday" leaves time untouched */ 321 tm.tm_isdst = -1; 322 REL_CHECK("yesterday", now, tm); 323 324 ATF_CHECK(localtime_r(&now, &tm) != NULL); 325 tm.tm_mday++; 326 /* as does "tomorrow" */ 327 tm.tm_isdst = -1; 328 REL_CHECK("tomorrow", now, tm); 329 330 ATF_CHECK(localtime_r(&now, &tm) != NULL); 331 if (tm.tm_wday > 4) 332 tm.tm_mday += 7; 333 tm.tm_mday += 4 - tm.tm_wday; 334 /* if a day name is mentioned, it means midnight (by default) */ 335 tm.tm_sec = tm.tm_min = tm.tm_hour = 0; 336 tm.tm_isdst = -1; 337 REL_CHECK("this thursday", now, tm); 338 339 ATF_CHECK(localtime_r(&now, &tm) != NULL); 340 tm.tm_mday += 14 - (tm.tm_wday ? tm.tm_wday : 7); 341 tm.tm_sec = tm.tm_min = tm.tm_hour = 0; 342 tm.tm_isdst = -1; 343 REL_CHECK("next sunday", now, tm); 344 345 ATF_CHECK(localtime_r(&now, &tm) != NULL); 346 if (tm.tm_wday <= 5) 347 tm.tm_mday -= 7; 348 tm.tm_mday += 5 - tm.tm_wday; 349 tm.tm_sec = tm.tm_min = 0; 350 tm.tm_hour = 16; 351 tm.tm_isdst = -1; 352 REL_CHECK("last friday 4 p.m.", now, tm); 353 354 ATF_CHECK(localtime_r(&now, &tm) != NULL); 355 tm.tm_mday += 14; 356 if (tm.tm_wday > 3) 357 tm.tm_mday += 7; 358 tm.tm_mday += 3 - tm.tm_wday; 359 tm.tm_sec = tm.tm_min = 0; 360 tm.tm_hour = 3; 361 tm.tm_isdst = -1; 362 REL_CHECK("we fortnight 3 a.m.", now, tm); 363 364 ATF_CHECK(localtime_r(&now, &tm) != NULL); 365 tm.tm_min -= 5; 366 tm.tm_isdst = -1; 367 REL_CHECK("5 minutes ago", now, tm); 368 369 ATF_CHECK(localtime_r(&now, &tm) != NULL); 370 tm.tm_hour++; 371 tm.tm_min += 37; 372 tm.tm_isdst = -1; 373 REL_CHECK("97 minutes", now, tm); 374 375 ATF_CHECK(localtime_r(&now, &tm) != NULL); 376 tm.tm_mon++; 377 if (tm.tm_mon == 1 && 378 tm.tm_mday > 28 + isleap(tm.tm_year)) 379 tm.tm_mday = 28 + isleap(tm.tm_year); 380 else if ((tm.tm_mon == 3 || tm.tm_mon == 5 || 381 tm.tm_mon == 8 || tm.tm_mon == 10) && tm.tm_mday == 31) 382 tm.tm_mday = 30; 383 tm.tm_isdst = -1; 384 REL_CHECK("month", now, tm); 385 386 ATF_CHECK(localtime_r(&now, &tm) != NULL); 387 tm.tm_mon += 2; /* "next" means add 2 ... */ 388 if (tm.tm_mon == 13 && 389 tm.tm_mday > 28 + isleap(tm.tm_year + 1)) 390 tm.tm_mday = 28 + isleap(tm.tm_year + 1); 391 else if (tm.tm_mon == 8 && tm.tm_mday == 31) 392 tm.tm_mday = 30; 393 tm.tm_isdst = -1; 394 REL_CHECK("next month", now, tm); 395 396 ATF_CHECK(localtime_r(&now, &tm) != NULL); 397 tm.tm_mon--; 398 if (tm.tm_mon == 1 && 399 tm.tm_mday > 28 + isleap(tm.tm_year)) 400 tm.tm_mday = 28 + isleap(tm.tm_year); 401 else if ((tm.tm_mon == 3 || tm.tm_mon == 5 || 402 tm.tm_mon == 8 || tm.tm_mon == 10) && tm.tm_mday == 31) 403 tm.tm_mday = 30; 404 tm.tm_isdst = -1; 405 REL_CHECK("last month", now, tm); 406 407 ATF_CHECK(localtime_r(&now, &tm) != NULL); 408 tm.tm_mon += 6; 409 if (tm.tm_mon == 13 && 410 tm.tm_mday > 28 + isleap(tm.tm_year + 1)) 411 tm.tm_mday = 28 + isleap(tm.tm_year + 1); 412 else if ((tm.tm_mon == 15 || tm.tm_mon == 17 || 413 tm.tm_mon == 8 || tm.tm_mon == 10) && tm.tm_mday == 31) 414 tm.tm_mday = 30; 415 tm.tm_mday += 2; 416 tm.tm_isdst = -1; 417 REL_CHECK("+6 months 2 days", now, tm); 418 419 ATF_CHECK(localtime_r(&now, &tm) != NULL); 420 tm.tm_mon -= 9; 421 if (tm.tm_mon == 1 && tm.tm_mday > 28 + isleap(tm.tm_year)) 422 tm.tm_mday = 28 + isleap(tm.tm_year); 423 else if ((tm.tm_mon == -9 || tm.tm_mon == -7 || 424 tm.tm_mon == -2) && tm.tm_mday == 31) 425 tm.tm_mday = 30; 426 tm.tm_isdst = -1; 427 REL_CHECK("9 months ago", now, tm); 428 429 ATF_CHECK(localtime_r(&now, &tm) != NULL); 430 if (tm.tm_wday <= 2) 431 tm.tm_mday -= 7; 432 tm.tm_mday += 2 - tm.tm_wday; 433 tm.tm_isdst = -1; 434 tm.tm_hour = tm.tm_min = tm.tm_sec = 0; 435 REL_CHECK("1 week ago Tu", now, tm); 436 437 ATF_CHECK(localtime_r(&now, &tm) != NULL); 438 tm.tm_isdst = -1; 439 tm.tm_mday++; 440 tm.tm_hour = tm.tm_min = tm.tm_sec = 0; 441 REL_CHECK("midnight tomorrow", now, tm); 442 443 ATF_CHECK(localtime_r(&now, &tm) != NULL); 444 tm.tm_isdst = -1; 445 tm.tm_mday++; 446 tm.tm_hour = tm.tm_min = tm.tm_sec = 0; 447 REL_CHECK("tomorrow midnight", now, tm); 448 449 ATF_CHECK(localtime_r(&now, &tm) != NULL); 450 tm.tm_isdst = -1; 451 tm.tm_mday++; 452 tm.tm_hour = 12; 453 tm.tm_min = tm.tm_sec = 0; 454 REL_CHECK("noon tomorrow", now, tm); 455 456 ATF_CHECK(localtime_r(&now, &tm) != NULL); 457 if (tm.tm_wday > 2) 458 tm.tm_mday += 7; 459 tm.tm_mday += 2 - tm.tm_wday; 460 tm.tm_sec = tm.tm_min = tm.tm_hour = 0; 461 tm.tm_isdst = -1; 462 REL_CHECK("midnight Tuesday", now, tm); 463 464 ATF_CHECK(localtime_r(&now, &tm) != NULL); 465 if (tm.tm_wday > 2 + 1) 466 tm.tm_mday += 7; 467 tm.tm_mday += 2 - tm.tm_wday; 468 tm.tm_mday++; /* xxx midnight --> the next day */ 469 tm.tm_sec = tm.tm_min = tm.tm_hour = 0; 470 tm.tm_isdst = -1; 471 REL_CHECK("Tuesday midnight", now, tm); 472 } 473 } 474 475 ATF_TC(atsecs); 476 477 ATF_TC_HEAD(atsecs, tc) 478 { 479 atf_tc_set_md_var(tc, "descr", "Test seconds past the epoch"); 480 } 481 482 ATF_TC_BODY(atsecs, tc) 483 { 484 int tzoff; 485 486 /* "@0" -> (time_t)0, regardless of timezone */ 487 ATF_CHECK(parsedate("@0", NULL, NULL) == (time_t)0); 488 putenv(__UNCONST("TZ=Europe/Berlin")); 489 tzset(); 490 ATF_CHECK(parsedate("@0", NULL, NULL) == (time_t)0); 491 putenv(__UNCONST("TZ=America/New_York")); 492 tzset(); 493 ATF_CHECK(parsedate("@0", NULL, NULL) == (time_t)0); 494 tzoff = 0; 495 ATF_CHECK(parsedate("@0", NULL, &tzoff) == (time_t)0); 496 tzoff = 3600; 497 ATF_CHECK(parsedate("@0", NULL, &tzoff) == (time_t)0); 498 tzoff = -3600; 499 ATF_CHECK(parsedate("@0", NULL, &tzoff) == (time_t)0); 500 501 /* -1 or other negative numbers are not errors */ 502 errno = 0; 503 ATF_CHECK(parsedate("@-1", NULL, &tzoff) == (time_t)-1 && errno == 0); 504 ATF_CHECK(parsedate("@-2", NULL, &tzoff) == (time_t)-2 && errno == 0); 505 506 /* junk is an error */ 507 errno = 0; 508 ATF_CHECK(parsedate("@junk", NULL, NULL) == (time_t)-1 && errno != 0); 509 } 510 511 ATF_TC(zones); 512 513 ATF_TC_HEAD(zones, tc) 514 { 515 atf_tc_set_md_var(tc, "descr", "Test parsing dates with zones"); 516 } 517 518 ATF_TC_BODY(zones, tc) 519 { 520 parsecheck("2015-12-06 16:11:48 UTC", NULL, NULL, gmtime_r, 521 2015, 12, 6, 16, 11, 48); 522 parsecheck("2015-12-06 16:11:48 UT", NULL, NULL, gmtime_r, 523 2015, 12, 6, 16, 11, 48); 524 parsecheck("2015-12-06 16:11:48 GMT", NULL, NULL, gmtime_r, 525 2015, 12, 6, 16, 11, 48); 526 parsecheck("2015-12-06 16:11:48 +0000", NULL, NULL, gmtime_r, 527 2015, 12, 6, 16, 11, 48); 528 529 parsecheck("2015-12-06 16:11:48 -0500", NULL, NULL, gmtime_r, 530 2015, 12, 6, 21, 11, 48); 531 parsecheck("2015-12-06 16:11:48 EST", NULL, NULL, gmtime_r, 532 2015, 12, 6, 21, 11, 48); 533 parsecheck("2015-12-06 16:11:48 EDT", NULL, NULL, gmtime_r, 534 2015, 12, 6, 20, 11, 48); 535 parsecheck("2015-12-06 16:11:48 +0500", NULL, NULL, gmtime_r, 536 2015, 12, 6, 11, 11, 48); 537 538 parsecheck("2015-12-06 16:11:48 +1000", NULL, NULL, gmtime_r, 539 2015, 12, 6, 6, 11, 48); 540 parsecheck("2015-12-06 16:11:48 AEST", NULL, NULL, gmtime_r, 541 2015, 12, 6, 6, 11, 48); 542 parsecheck("2015-12-06 16:11:48 -1000", NULL, NULL, gmtime_r, 543 2015, 12, 7, 2, 11, 48); 544 parsecheck("2015-12-06 16:11:48 HST", NULL, NULL, gmtime_r, 545 2015, 12, 7, 2, 11, 48); 546 547 parsecheck("2015-12-06 16:11:48 AWST", NULL, NULL, gmtime_r, 548 2015, 12, 6, 8, 11, 48); 549 parsecheck("2015-12-06 16:11:48 NZDT", NULL, NULL, gmtime_r, 550 2015, 12, 6, 3, 11, 48); 551 552 parsecheck("Sun, 6 Dec 2015 09:43:16 -0500", NULL, NULL, gmtime_r, 553 2015, 12, 6, 14, 43, 16); 554 parsecheck("Mon Dec 7 03:13:31 ICT 2015", NULL, NULL, gmtime_r, 555 2015, 12, 6, 20, 13, 31); 556 /* the day name is ignored when a day of month (etc) is given... */ 557 parsecheck("Sat Dec 7 03:13:31 ICT 2015", NULL, NULL, gmtime_r, 558 2015, 12, 6, 20, 13, 31); 559 560 561 parsecheck("2015-12-06 12:00:00 IDLW", NULL, NULL, gmtime_r, 562 2015, 12, 7, 0, 0, 0); 563 parsecheck("2015-12-06 12:00:00 IDLE", NULL, NULL, gmtime_r, 564 2015, 12, 6, 0, 0, 0); 565 566 parsecheck("2015-12-06 21:17:33 NFT", NULL, NULL, gmtime_r, 567 2015, 12, 7, 0, 47, 33); 568 parsecheck("2015-12-06 21:17:33 ACST", NULL, NULL, gmtime_r, 569 2015, 12, 6, 11, 47, 33); 570 parsecheck("2015-12-06 21:17:33 +0717", NULL, NULL, gmtime_r, 571 2015, 12, 6, 14, 0, 33); 572 573 parsecheck("2015-12-06 21:21:21 Z", NULL, NULL, gmtime_r, 574 2015, 12, 6, 21, 21, 21); 575 parsecheck("2015-12-06 21:21:21 A", NULL, NULL, gmtime_r, 576 2015, 12, 6, 22, 21, 21); 577 parsecheck("2015-12-06 21:21:21 G", NULL, NULL, gmtime_r, 578 2015, 12, 7, 4, 21, 21); 579 parsecheck("2015-12-06 21:21:21 M", NULL, NULL, gmtime_r, 580 2015, 12, 7, 9, 21, 21); 581 parsecheck("2015-12-06 21:21:21 N", NULL, NULL, gmtime_r, 582 2015, 12, 6, 20, 21, 21); 583 parsecheck("2015-12-06 21:21:21 T", NULL, NULL, gmtime_r, 584 2015, 12, 6, 14, 21, 21); 585 parsecheck("2015-12-06 21:21:21 Y", NULL, NULL, gmtime_r, 586 2015, 12, 6, 9, 21, 21); 587 588 } 589 590 ATF_TC(gibberish); 591 592 ATF_TC_HEAD(gibberish, tc) 593 { 594 atf_tc_set_md_var(tc, "descr", "Test (not) parsing nonsense"); 595 } 596 597 ATF_TC_BODY(gibberish, tc) 598 { 599 errno = 0; 600 ATF_CHECK(parsedate("invalid nonsense", NULL, NULL) == (time_t)-1 601 && errno != 0); 602 errno = 0; 603 ATF_CHECK(parsedate("12th day of Christmas", NULL, NULL) == (time_t)-1 604 && errno != 0); 605 errno = 0; 606 ATF_CHECK(parsedate("2015-31-07 15:00", NULL, NULL) == (time_t)-1 607 && errno != 0); 608 errno = 0; 609 ATF_CHECK(parsedate("2015-02-29 10:01", NULL, NULL) == (time_t)-1 610 && errno != 0); 611 errno = 0; 612 ATF_CHECK(parsedate("2015-12-06 24:01", NULL, NULL) == (time_t)-1 613 && errno != 0); 614 errno = 0; 615 ATF_CHECK(parsedate("2015-12-06 14:61", NULL, NULL) == (time_t)-1 616 && errno != 0); 617 } 618 619 ATF_TP_ADD_TCS(tp) 620 { 621 ATF_TP_ADD_TC(tp, dates); 622 ATF_TP_ADD_TC(tp, times); 623 ATF_TP_ADD_TC(tp, dsttimes); 624 ATF_TP_ADD_TC(tp, relative); 625 ATF_TP_ADD_TC(tp, atsecs); 626 ATF_TP_ADD_TC(tp, zones); 627 ATF_TP_ADD_TC(tp, gibberish); 628 629 return atf_no_error(); 630 } 631 632