usleep tests: Avoid failure due to known Cygwin 3.5.3 bug.
[gnulib.git] / tests / test-nstrftime.h
blobb822f3acd17123526bb841f1ff2e91487f980362
1 /* Test of nstrftime-like functions.
2 Copyright (C) 2011-2024 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <https://www.gnu.org/licenses/>. */
17 /* Written by Jim Meyering and Bruno Haible. */
19 #define FUNC_NAME STRINGIFY(FUNC)
20 #define STRINGIFY(x) #x
22 /* Support for settings like TZ='<+00>0' was added in IEEE Std 1003.1-2001. */
23 #define TZ_ANGLE_BRACKETS_SHOULD_WORK (200112 <= _POSIX_VERSION)
25 /* A wrapper around FUNC that checks the return value. */
26 static size_t
27 FUNC_CHECKED (char *restrict s, size_t maxsize,
28 char const *format,
29 struct tm const *tp, timezone_t tz, int ns)
31 size_t ret = FUNC (s, maxsize, format, tp, tz, ns);
32 if (ret > 0)
34 ASSERT (ret < maxsize);
35 ASSERT (strlen (s) == ret);
37 return ret;
40 /* -------------------------------------------------------------------------- */
42 struct posixtm_test
44 time_t in;
45 int in_ns;
46 char const *fmt;
47 char const *exp;
50 static struct posixtm_test const T[] =
52 { 1300000000, 0, "%F", "2011-03-13" },
53 { 0, 10, "%T.%N", "00:00:00.000000010" },
54 { 56, 123456789, "%T.%12N", "00:00:56.123456789000" },
55 { 0, 123000000, "%T.%_6N", "00:00:00.123 " },
56 { 0, 0, NULL, NULL }
59 static int
60 posixtm_test (void)
62 int fail = 0;
63 unsigned int i;
65 for (i = 0; T[i].fmt; i++)
67 char buf[1000];
68 time_t t = T[i].in;
69 struct tm *tm = gmtime (&t);
70 size_t n;
72 ASSERT (tm);
74 n = FUNC_CHECKED (buf, sizeof buf, T[i].fmt, tm, 0, T[i].in_ns);
75 if (n == 0)
77 fail = 1;
78 printf ("%s failed with format %s\n", FUNC_NAME, T[i].fmt);
79 fflush (stdout);
82 if (! STREQ (buf, T[i].exp))
84 fail = 1;
85 printf ("%s: result mismatch: got %s, expected %s\n",
86 T[i].fmt, buf, T[i].exp);
87 fflush (stdout);
91 return fail;
94 /* -------------------------------------------------------------------------- */
96 struct tzalloc_test
98 timezone_t tz;
99 char const *setting;
102 static struct tzalloc_test TZ[] =
104 #define Pacific 0
105 #if defined _WIN32 && !defined __CYGWIN__
106 { 0, "PST8PDT" },
107 #else
108 { 0, "PST8PDT,M3.2.0,M11.1.0" },
109 #endif
111 #define Arizona 1
112 { 0, "MST7" },
114 #define UTC 2
115 { 0, 0 },
117 #define CentEur 3
118 #if defined _WIN32 && !defined __CYGWIN__
119 { 0, "CET-1CEST" },
120 #else
121 { 0, "CET-1CEST,M3.5.0,M10.5.0/3" },
122 #endif
124 #define Japan 4
125 { 0, "JST-9" },
127 #define NZ 5
128 #if defined _WIN32 && !defined __CYGWIN__
129 { 0, "NST-13NDT" },
130 #else
131 { 0, "NZST-12NZDT,M9.5.0,M4.1.0/3" },
132 #endif
134 #define Unknown 6
135 { 0, "<-00>0" },
137 { 0 }
140 struct localtime_rz_test
142 /* Input parameters. */
143 struct tzalloc_test *tza;
144 time_t t;
146 /* Expected result. */
147 char const *exp;
149 /* Determines if an incorrectly unset tm_isdst
150 results in failure or just a warning. */
151 int ahistorical;
154 static struct localtime_rz_test LT[] =
156 #if !(defined __DragonFly__ || defined __NetBSD__ || defined __ANDROID__)
157 { TZ+Pacific, 0, "1969-12-31 16:00:00 -0800 (PST)", 0 },
158 #endif
159 { TZ+Arizona, 0, "1969-12-31 17:00:00 -0700 (MST)", 0 },
160 { TZ+UTC , 0, "1970-01-01 00:00:00 +0000 (UTC)", 0 },
161 #if !(defined __DragonFly__ || defined __NetBSD__ || defined __ANDROID__)
162 { TZ+CentEur, 0, "1970-01-01 01:00:00 +0100 (CET)", 0 },
163 #endif
164 { TZ+Japan , 0, "1970-01-01 09:00:00 +0900 (JST)", 0 },
165 #if !defined __FreeBSD__
166 { TZ+NZ , 0, "1970-01-01 13:00:00 +1300 (NZDT)", 1 },
167 #endif
168 { TZ+Pacific, 500000001, "1985-11-04 16:53:21 -0800 (PST)", 0 },
169 { TZ+Arizona, 500000001, "1985-11-04 17:53:21 -0700 (MST)", 0 },
170 { TZ+UTC , 500000001, "1985-11-05 00:53:21 +0000 (UTC)", 0 },
171 { TZ+CentEur, 500000001, "1985-11-05 01:53:21 +0100 (CET)", 1 },
172 { TZ+Japan , 500000001, "1985-11-05 09:53:21 +0900 (JST)", 0 },
173 { TZ+NZ , 500000001, "1985-11-05 13:53:21 +1300 (NZDT)", 0 },
174 #if !(defined _WIN32 && !defined __CYGWIN__)
175 { TZ+Pacific, 1000000002, "2001-09-08 18:46:42 -0700 (PDT)", 0 },
176 #endif
177 { TZ+Arizona, 1000000002, "2001-09-08 18:46:42 -0700 (MST)", 0 },
178 { TZ+UTC , 1000000002, "2001-09-09 01:46:42 +0000 (UTC)", 0 },
179 #if !(defined _WIN32 && !defined __CYGWIN__)
180 { TZ+CentEur, 1000000002, "2001-09-09 03:46:42 +0200 (CEST)", 0 },
181 #endif
182 { TZ+Japan , 1000000002, "2001-09-09 10:46:42 +0900 (JST)", 0 },
183 #if !(defined _WIN32 && !defined __CYGWIN__)
184 { TZ+NZ , 1000000002, "2001-09-09 13:46:42 +1200 (NZST)", 0 },
185 #endif
186 #if TZ_ANGLE_BRACKETS_SHOULD_WORK && !defined __FreeBSD__
187 { TZ+Unknown, 0, "1970-01-01 00:00:00 -0000 (-00)", 0 },
188 { TZ+Unknown, 500000001, "1985-11-05 00:53:21 -0000 (-00)", 0 },
189 { TZ+Unknown, 1000000002, "2001-09-09 01:46:42 -0000 (-00)", 0 },
190 #endif
191 { 0 }
194 static int
195 tzalloc_test (void)
197 int fail = 0;
198 int i;
200 for (i = 0; LT[i].tza; i++)
202 struct tzalloc_test *tza = LT[i].tza;
203 long lt = LT[i].t;
204 timezone_t tz = tza->tz;
205 char const *setting;
206 static char const format[] = "%Y-%m-%d %H:%M:%S %z (%Z)";
207 char buf[1000];
208 struct tm tm;
209 size_t n;
211 if (!tz && tza->setting)
213 tz = tzalloc (tza->setting);
214 if (!tz)
216 fail = 1;
217 printf ("%s: tzalloc: %s\n", TZ[i].setting, strerror (errno));
218 fflush (stdout);
219 continue;
221 tza->tz = tz;
224 setting = tza->setting ? tza->setting : "UTC0";
226 if (!localtime_rz (tz, &LT[i].t, &tm))
228 fail = 1;
229 printf ("%s: %ld: localtime_rz: %s\n", setting, lt,
230 strerror (errno));
231 fflush (stdout);
232 continue;
235 n = FUNC_CHECKED (buf, sizeof buf, format, &tm, tz, 0);
236 if (n == 0)
238 fail = 1;
239 printf ("%s: %ld: %s failed\n", setting, lt, FUNC_NAME);
240 fflush (stdout);
241 continue;
244 if (! (STREQ (buf, LT[i].exp)
245 || (!tz && n == strlen (LT[i].exp)
246 && memcmp (buf, LT[i].exp, n - sizeof "(GMT)" + 1) == 0
247 && STREQ (buf + n - sizeof "(GMT)" + 1, "(GMT)"))
248 #if defined _WIN32 && !defined __CYGWIN__
249 /* On native Windows, the time zone is printed differently. */
250 || strncmp (buf, LT[i].exp, 20) == 0
251 #endif
254 /* Don't fail for unhandled dst in ahistorical entries,
255 as gnulib doesn't currently fix that issue, seen on Darwin 14. */
256 if (!LT[i].ahistorical || tm.tm_isdst)
257 fail = 1;
258 printf ("%s: expected \"%s\", got \"%s\"\n",
259 setting, LT[i].exp, buf);
260 fflush (stdout);
264 return fail;
267 /* -------------------------------------------------------------------------- */
269 static int
270 quarter_test (void)
272 int fail = 0;
273 size_t mon;
275 /* Check %q. */
276 for (mon = 1; mon <= 12; mon++)
278 char out[2];
279 char exp[2] = {0,};
280 struct tm qtm = { .tm_mon = mon - 1 };
281 char fmt[3] = {'%','q','\0'};
283 size_t r = FUNC_CHECKED (out, sizeof (out), fmt, &qtm, 0, 0);
284 if (r == 0)
286 printf ("%s(\"%%q\") failed\n", FUNC_NAME);
287 fflush (stdout);
288 fail = 1;
289 break;
292 exp[0] = mon < 4 ? '1' : mon < 7 ? '2' : mon < 10 ? '3' : '4';
293 if (strcmp (out, exp) != 0)
295 printf ("%s %%q: expected \"%s\", got \"%s\"\n", FUNC_NAME, exp, out);
296 fflush (stdout);
297 fail = 1;
298 break;
302 return fail;
305 /* -------------------------------------------------------------------------- */
307 static int
308 errno_test (void)
310 int fail = 0;
311 struct tm tm = { .tm_year = 2020 - 1900, .tm_mday = 1 };
312 char buf[INT_BUFSIZE_BOUND (time_t)];
313 size_t n;
314 int bigyear = LLONG_MAX - 1900 < INT_MAX ? LLONG_MAX - 1900 : INT_MAX;
316 errno = 0;
317 n = FUNC_CHECKED (buf, 0, "%m", &tm, 0, 0);
318 if (! (n == 0 && errno == ERANGE))
320 fail = 1;
321 printf ("%s failed to set errno = ERANGE\n", FUNC_NAME);
322 fflush (stdout);
325 errno = 0;
326 n = FUNC_CHECKED (buf, sizeof buf, "", &tm, 0, 0);
327 if (! (n == 0 && errno == 0))
329 fail = 1;
330 printf ("%s failed to leave errno alone\n", FUNC_NAME);
331 fflush (stdout);
335 tm.tm_year = bigyear;
336 errno = 0;
337 n = FUNC_CHECKED (buf, sizeof buf, "%s", &tm, 0, 0);
338 if (n == 0)
340 if (errno != EOVERFLOW)
342 fail = 1;
343 printf ("%s failed to set errno = EOVERFLOW\n", FUNC_NAME);
344 fflush (stdout);
347 if (mktime_z (0, &tm) != (time_t) -1)
349 fail = 1;
350 printf ("%s %%s failed but mktime_z worked for tm_year=%d\n",
351 FUNC_NAME, bigyear);
352 fflush (stdout);
355 else
357 long long int text_seconds = atoll (buf);
358 if (text_seconds <= (LLONG_MAX - 1 < TYPE_MAXIMUM (time_t)
359 ? LLONG_MAX - 1 : TYPE_MAXIMUM (time_t)))
361 time_t bigtime = text_seconds;
362 struct tm *tmp = gmtime (&bigtime);
363 if (!tmp)
365 fail = 1;
366 printf ("gmtime failed on %s result\n", FUNC_NAME);
367 fflush (stdout);
369 else
371 char buf1[sizeof buf];
372 size_t n1 = FUNC_CHECKED (buf1, sizeof buf1, "%s", tmp, 0, 0);
373 buf1[n1] = '\0';
374 if (! STREQ (buf, buf1))
376 fail = 1;
377 printf ("%s %%s first returned '%s', then '%s'\n",
378 FUNC_NAME, buf, buf1);
379 fflush (stdout);
385 return fail;
388 /* -------------------------------------------------------------------------- */
390 /* Test various format directives. */
392 typedef enum { english, french } language_t;
394 static int
395 locales_test (language_t language)
397 int fail = 0;
399 time_t t = 1509000003;
400 struct tm *tm = gmtime (&t);
401 int ns = 123456789;
402 char buf[100];
403 size_t n;
405 n = FUNC_CHECKED (buf, sizeof buf, "%+4Y-%m-%d %H:%M:%S.%N", tm, 0, ns);
406 ASSERT (n > 0);
407 printf ("Format as ISO 8601: %s\n", buf);
408 fflush (stdout);
409 ASSERT (STREQ (buf, "2017-10-26 06:40:03.123456789"));
411 /* Exercise various POSIX format directives. */
413 n = FUNC_CHECKED (buf, sizeof buf, "%a", tm, 0, ns);
414 ASSERT (n > 0);
415 printf ("%%a directive: %s\n", buf);
416 fflush (stdout);
417 switch (language)
419 case english:
420 ASSERT (STREQ (buf, "Thu"));
421 break;
422 case french:
423 ASSERT (STREQ (buf, "jeu.") /* glibc, FreeBSD, NetBSD, Solaris, Cygwin */
424 || STREQ (buf, "Jeu") /* macOS, older FreeBSD */);
425 break;
428 n = FUNC_CHECKED (buf, sizeof buf, "%A", tm, 0, ns);
429 ASSERT (n > 0);
430 printf ("%%A directive: %s\n", buf);
431 fflush (stdout);
432 switch (language)
434 case english:
435 ASSERT (STREQ (buf, "Thursday"));
436 break;
437 case french:
438 ASSERT (STREQ (buf, "jeudi") /* glibc, FreeBSD, NetBSD, Solaris, Cygwin */
439 || STREQ (buf, "Jeudi") /* macOS, older FreeBSD */);
440 break;
443 n = FUNC_CHECKED (buf, sizeof buf, "%b", tm, 0, ns);
444 ASSERT (n > 0);
445 printf ("%%b directive: %s\n", buf);
446 fflush (stdout);
447 switch (language)
449 case english:
450 ASSERT (STREQ (buf, "Oct"));
451 break;
452 case french:
453 ASSERT (STREQ (buf, "oct.") /* glibc, FreeBSD, NetBSD, Solaris, Cygwin */
454 || STREQ (buf, "oct") /* macOS, older FreeBSD */);
455 break;
458 n = FUNC_CHECKED (buf, sizeof buf, "%B", tm, 0, ns);
459 ASSERT (n > 0);
460 printf ("%%B directive: %s\n", buf);
461 fflush (stdout);
462 switch (language)
464 case english:
465 ASSERT (STREQ (buf, "October"));
466 break;
467 case french:
468 ASSERT (STREQ (buf, "octobre"));
469 break;
472 n = FUNC_CHECKED (buf, sizeof buf, "%c", tm, 0, ns);
473 ASSERT (n > 0);
474 printf ("%%c directive: %s\n", buf);
475 fflush (stdout);
476 switch (language)
478 case english:
479 ASSERT (STREQ (buf, "Thu Oct 26 06:40:03 2017"));
480 break;
481 case french:
482 ASSERT (STREQ (buf, "jeu. 26 oct. 2017 06:40:03") /* glibc, Cygwin */
483 || STREQ (buf, "jeu. 26 oct. 06:40:03 2017") /* FreeBSD */
484 || STREQ (buf, "Jeu 26 oct 06:40:03 2017") /* macOS, older FreeBSD */
485 || STREQ (buf, "26 octobre 2017 06:40:03") /* NetBSD */
486 || STREQ (buf, "26 octobre 2017 à 06:40:03") /* Solaris (UTF-8) */
487 || STREQ (buf, "26 octobre 2017 \340 06:40:03") /* Solaris (ISO-8859-1) */);
488 break;
491 n = FUNC_CHECKED (buf, sizeof buf, "%C", tm, 0, ns);
492 ASSERT (n > 0);
493 printf ("%%C directive: %s\n", buf);
494 fflush (stdout);
495 ASSERT (STREQ (buf, "20"));
497 n = FUNC_CHECKED (buf, sizeof buf, "%d", tm, 0, ns);
498 ASSERT (n > 0);
499 printf ("%%d directive: %s\n", buf);
500 fflush (stdout);
501 ASSERT (STREQ (buf, "26"));
503 n = FUNC_CHECKED (buf, sizeof buf, "%D", tm, 0, ns);
504 ASSERT (n > 0);
505 printf ("%%D directive: %s\n", buf);
506 fflush (stdout);
507 ASSERT (STREQ (buf, "10/26/17"));
509 n = FUNC_CHECKED (buf, sizeof buf, "%e", tm, 0, ns);
510 ASSERT (n > 0);
511 printf ("%%e directive: %s\n", buf);
512 fflush (stdout);
513 ASSERT (STREQ (buf, "26"));
515 n = FUNC_CHECKED (buf, sizeof buf, "%F", tm, 0, ns);
516 ASSERT (n > 0);
517 printf ("%%F directive: %s\n", buf);
518 fflush (stdout);
519 ASSERT (STREQ (buf, "2017-10-26"));
521 n = FUNC_CHECKED (buf, sizeof buf, "%g", tm, 0, ns);
522 ASSERT (n > 0);
523 printf ("%%g directive: %s\n", buf);
524 fflush (stdout);
525 ASSERT (STREQ (buf, "17"));
527 n = FUNC_CHECKED (buf, sizeof buf, "%G", tm, 0, ns);
528 ASSERT (n > 0);
529 printf ("%%G directive: %s\n", buf);
530 fflush (stdout);
531 ASSERT (STREQ (buf, "2017"));
533 n = FUNC_CHECKED (buf, sizeof buf, "%h", tm, 0, ns);
534 ASSERT (n > 0);
535 printf ("%%h directive: %s\n", buf);
536 fflush (stdout);
537 switch (language)
539 case english:
540 ASSERT (STREQ (buf, "Oct"));
541 break;
542 case french:
543 ASSERT (STREQ (buf, "oct.") /* glibc, FreeBSD, NetBSD, Solaris, Cygwin */
544 || STREQ (buf, "oct") /* macOS, older FreeBSD */);
545 break;
548 n = FUNC_CHECKED (buf, sizeof buf, "%H", tm, 0, ns);
549 ASSERT (n > 0);
550 printf ("%%H directive: %s\n", buf);
551 fflush (stdout);
552 ASSERT (STREQ (buf, "06"));
554 n = FUNC_CHECKED (buf, sizeof buf, "%I", tm, 0, ns);
555 ASSERT (n > 0);
556 printf ("%%I directive: %s\n", buf);
557 fflush (stdout);
558 ASSERT (STREQ (buf, "06"));
560 n = FUNC_CHECKED (buf, sizeof buf, "%j", tm, 0, ns);
561 ASSERT (n > 0);
562 printf ("%%j directive: %s\n", buf);
563 fflush (stdout);
564 ASSERT (STREQ (buf, "299"));
566 n = FUNC_CHECKED (buf, sizeof buf, "%m", tm, 0, ns);
567 ASSERT (n > 0);
568 printf ("%%m directive: %s\n", buf);
569 fflush (stdout);
570 ASSERT (STREQ (buf, "10"));
572 n = FUNC_CHECKED (buf, sizeof buf, "%M", tm, 0, ns);
573 ASSERT (n > 0);
574 printf ("%%M directive: %s\n", buf);
575 fflush (stdout);
576 ASSERT (STREQ (buf, "40"));
578 n = FUNC_CHECKED (buf, sizeof buf, "%n", tm, 0, ns);
579 ASSERT (n > 0);
580 printf ("%%n directive: %s\n", buf);
581 fflush (stdout);
582 ASSERT (STREQ (buf, "\n"));
584 n = FUNC_CHECKED (buf, sizeof buf, "%p", tm, 0, ns);
585 switch (language)
587 case english:
588 ASSERT (n > 0);
589 printf ("%%p directive: %s\n", buf);
590 fflush (stdout);
591 ASSERT (STREQ (buf, "AM"));
592 break;
593 case french:
594 ASSERT (n == 0);
595 break;
598 n = FUNC_CHECKED (buf, sizeof buf, "%r", tm, 0, ns);
599 ASSERT (n > 0);
600 printf ("%%r directive: %s\n", buf);
601 fflush (stdout);
602 switch (language)
604 case english:
605 ASSERT (STREQ (buf, "06:40:03 AM"));
606 break;
607 case french:
608 ASSERT (STREQ (buf, "06:40:03 ") /* glibc */
609 || STREQ (buf, "06:40:03") /* NetBSD, Cygwin */
610 || STREQ (buf, " 6:40:03") /* Solaris */);
611 break;
614 n = FUNC_CHECKED (buf, sizeof buf, "%R", tm, 0, ns);
615 ASSERT (n > 0);
616 printf ("%%R directive: %s\n", buf);
617 fflush (stdout);
618 ASSERT (STREQ (buf, "06:40"));
620 n = FUNC_CHECKED (buf, sizeof buf, "%S", tm, 0, ns);
621 ASSERT (n > 0);
622 printf ("%%S directive: %s\n", buf);
623 fflush (stdout);
624 ASSERT (STREQ (buf, "03"));
626 n = FUNC_CHECKED (buf, sizeof buf, "%t", tm, 0, ns);
627 ASSERT (n > 0);
628 printf ("%%t directive: %s\n", buf);
629 fflush (stdout);
630 ASSERT (STREQ (buf, "\t"));
632 n = FUNC_CHECKED (buf, sizeof buf, "%T", tm, 0, ns);
633 ASSERT (n > 0);
634 printf ("%%T directive: %s\n", buf);
635 fflush (stdout);
636 ASSERT (STREQ (buf, "06:40:03"));
638 n = FUNC_CHECKED (buf, sizeof buf, "%u", tm, 0, ns);
639 ASSERT (n > 0);
640 printf ("%%u directive: %s\n", buf);
641 fflush (stdout);
642 ASSERT (STREQ (buf, "4"));
644 n = FUNC_CHECKED (buf, sizeof buf, "%U", tm, 0, ns);
645 ASSERT (n > 0);
646 printf ("%%U directive: %s\n", buf);
647 fflush (stdout);
648 ASSERT (STREQ (buf, "43"));
650 n = FUNC_CHECKED (buf, sizeof buf, "%V", tm, 0, ns);
651 ASSERT (n > 0);
652 printf ("%%V directive: %s\n", buf);
653 fflush (stdout);
654 ASSERT (STREQ (buf, "43"));
656 n = FUNC_CHECKED (buf, sizeof buf, "%w", tm, 0, ns);
657 ASSERT (n > 0);
658 printf ("%%w directive: %s\n", buf);
659 fflush (stdout);
660 ASSERT (STREQ (buf, "4"));
662 n = FUNC_CHECKED (buf, sizeof buf, "%W", tm, 0, ns);
663 ASSERT (n > 0);
664 printf ("%%W directive: %s\n", buf);
665 fflush (stdout);
666 ASSERT (STREQ (buf, "43"));
668 n = FUNC_CHECKED (buf, sizeof buf, "%x", tm, 0, ns);
669 ASSERT (n > 0);
670 printf ("%%x directive: %s\n", buf);
671 fflush (stdout);
672 switch (language)
674 case english:
675 ASSERT (STREQ (buf, "10/26/17"));
676 break;
677 case french:
678 ASSERT (STREQ (buf, "26/10/2017") /* glibc, NetBSD, Solaris, Cygwin */
679 || STREQ (buf, "26.10.2017") /* FreeBSD, macOS */);
680 break;
683 n = FUNC_CHECKED (buf, sizeof buf, "%X", tm, 0, ns);
684 ASSERT (n > 0);
685 printf ("%%X directive: %s\n", buf);
686 fflush (stdout);
687 ASSERT (STREQ (buf, "06:40:03"));
689 n = FUNC_CHECKED (buf, sizeof buf, "%y", tm, 0, ns);
690 ASSERT (n > 0);
691 printf ("%%y directive: %s\n", buf);
692 fflush (stdout);
693 ASSERT (STREQ (buf, "17"));
695 n = FUNC_CHECKED (buf, sizeof buf, "%Y", tm, 0, ns);
696 ASSERT (n > 0);
697 printf ("%%Y directive: %s\n", buf);
698 fflush (stdout);
699 ASSERT (STREQ (buf, "2017"));
701 n = FUNC_CHECKED (buf, sizeof buf, "%z", tm, 0, ns);
702 ASSERT (n > 0);
703 printf ("%%z directive: %s\n", buf);
704 fflush (stdout);
705 ASSERT (STREQ (buf, "+0000"));
707 n = FUNC_CHECKED (buf, sizeof buf, "%Z", tm, 0, ns);
708 ASSERT (n > 0);
709 printf ("%%Z directive: %s\n", buf);
710 fflush (stdout);
711 ASSERT (STREQ (buf, "GMT") /* glibc, NetBSD, OpenBSD, AIX, Solaris, Cygwin, Android */
712 || STREQ (buf, "UTC") /* musl, macOS, FreeBSD */);
714 n = FUNC_CHECKED (buf, sizeof buf, "%%", tm, 0, ns);
715 ASSERT (n > 0);
716 printf ("%%%% directive: %s\n", buf);
717 fflush (stdout);
718 ASSERT (STREQ (buf, "%"));
720 /* Exercise various GNU extensions from glibc. */
722 n = FUNC_CHECKED (buf, sizeof buf, "%k", tm, 0, ns);
723 ASSERT (n > 0);
724 printf ("%%k directive: %s\n", buf);
725 fflush (stdout);
726 ASSERT (STREQ (buf, " 6"));
728 n = FUNC_CHECKED (buf, sizeof buf, "%l", tm, 0, ns);
729 ASSERT (n > 0);
730 printf ("%%l directive: %s\n", buf);
731 fflush (stdout);
732 ASSERT (STREQ (buf, " 6"));
734 n = FUNC_CHECKED (buf, sizeof buf, "%P", tm, 0, ns);
735 switch (language)
737 case english:
738 ASSERT (n > 0);
739 printf ("%%P directive: %s\n", buf);
740 fflush (stdout);
741 ASSERT (STREQ (buf, "am"));
742 break;
743 case french:
744 ASSERT (n == 0);
745 break;
748 n = FUNC_CHECKED (buf, sizeof buf, "%s", tm, 0, ns);
749 ASSERT (n > 0);
750 printf ("%%s directive: %s\n", buf);
751 fflush (stdout);
752 ASSERT (STREQ (buf, "1509000003"));
754 /* Exercise various GNU extensions from gnulib. */
756 n = FUNC_CHECKED (buf, sizeof buf, "%N", tm, 0, ns);
757 ASSERT (n > 0);
758 printf ("%%N directive: %s\n", buf);
759 fflush (stdout);
760 ASSERT (STREQ (buf, "123456789"));
762 return fail;
765 /* -------------------------------------------------------------------------- */
768 Local Variables:
769 indent-tabs-mode: nil
770 End: