Ne.app NeANT
The Ne.app NeANT User module of the NeANT distribution.
22.locale.time.put.cpp
Go to the documentation of this file.
1
29#include <ios> // for basic_ios
30#include <locale> // for locale, time_put
31
32#include <climits> // for INT_MAX, INT_MIN, TZNAME_MAX
33#include <cstdio> // for fprintf(), ...
34#include <cstdlib> // for mbstowcs(), wcstombs()
35#include <cstring> // for memset(), memcpy(), strlen(), strcat()
36#include <ctime> // for tm, tzset()
37#include <cwchar> // for wcsftime(), wcslen()
38#include <cassert> // for assert()
39
40#include <rw_driver.h> // for rw_test(), ...
41#include <rw_environ.h> // for rw_putenv()
42#include <rw_file.h> // for pcs_write(), ...
43#include <rw_locale.h> // for rw_localedef(), ...
44#include <rw_printf.h> // for rw_snprintf()
45#include <rw_valcmp.h> // for rw_strncmp()
46
47
48#if _RWSTD_PATH_SEP == '/'
49# define SLASH "/"
50#else
51# define SLASH "\\"
52#endif
53
54
55// the root of the locale directory (RWSTD_LOCALE_ROOT)
56// set in main() instead of here to avoid Solaris 7 putenv() bug (PR #30017)
57const char* locale_root;
58
59#if defined (_RWSTD_NO_TZSET) && !defined (_RWSTD_NO_TZSET_IN_LIBC)
60# undef _RWSTD_NO_TZSET
61extern "C" _RWSTD_DLLIMPORT void tzset () _LIBC_THROWS();
62#endif // _RWSTD_NO_TZSET && !_RWSTD_NO_TZSET_IN_LIBC
63
64inline void set_TZ (const char* str)
65{
66 rw_putenv (str);
67
68#ifndef _RWSTD_NO_TZSET
69 tzset ();
70#endif
71}
72
73
75const char* narrow (char *dst, const char *src)
76{
77 if (src == dst || !src || !dst)
78 return src;
79
80 std::memcpy (dst, src, std::strlen (src) + 1);
81 return dst;
82}
83
84
85const char* widen (char *dst, const char *src)
86{
87 if (src == dst || !src || !dst)
88 return src;
89
90 std::memcpy (dst, src, std::strlen (src) + 1);
91 return dst;
92}
93
94
95const char* narrow (char *dst, const wchar_t *src)
96{
97 static char buf [4096];
98
99 if (!src)
100 return 0;
101
102 if (!dst)
103 dst = buf;
104
105 RW_ASSERT (std::wcslen (src) < sizeof buf);
106
107 const std::size_t len = std::wcstombs (dst, src, sizeof buf / sizeof *buf);
108
109 if (std::size_t (-1) == len)
110 *dst = 0;
111
112 return dst;
113}
114
115
116const wchar_t* widen (wchar_t *dst, const char *src)
117{
118 static wchar_t buf [4096];
119
120 if (!src)
121 return 0;
122
123 if (!dst)
124 dst = buf;
125
126 RW_ASSERT (std::strlen (src) < sizeof buf /sizeof *buf);
127
128 const std::size_t len = std::mbstowcs (dst, src, sizeof buf / sizeof *buf);
129
130 if (std::size_t (-1) == len)
131 *dst = 0;
132
133 return dst;
134}
135
136
137std::size_t rw_strftime (char *buf, std::size_t bufsize,
138 const char *pat, const std::tm *tmb)
139{
140 static const std::tm tmp = std::tm ();
141
142 if (!tmb)
143 tmb = &tmp;
144
145#if defined (_MSC_VER) || defined (__MINGW32__)
146
147 // ms crt aborts if you use out of range values in debug
148 if (tmb->tm_hour < 0 || 24 <= tmb->tm_hour)
149 return 0;
150
151 if (tmb->tm_min < 0 || 60 <= tmb->tm_min)
152 return 0;
153
154 if (tmb->tm_sec < 0 || 60 <= tmb->tm_sec)
155 return 0;
156
157 // create a new pattern buffer that is windows strftime compatible...
158 char patbuf [512];
159 char *fpat = patbuf;
160
161 // assumes tm_year is relative to 1900
162 const int year = (tmb->tm_year + 1900);
163 const int century = (tmb->tm_year + 1900) / 100;
164
165 while (*pat) {
166
167 if (*pat == '%') {
168
169 // ensure we are not within 16 chars of the end of the
170 // local pattern buffer to avoid overflow
171 assert ((fpat + 16) < (patbuf + 512));
172
173 pat += 1; // step past %
174 switch (*pat)
175 {
176 case '\0':
177 // fails miserably if the last char is %
178 *fpat++ = '%'; *fpat++ = '%';
179 break;
180 case 'C':
181 // %C is replaced by the century number (the year divided by
182 // 100 and truncated to an integer) as a decimal number.
183 *fpat++ = '0' + (century / 10) % 10;
184 *fpat++ = '0' + (century % 10);
185 pat += 1;
186 break;
187 case 'D':
188 // %D same as %m/%d/%y.
189 *fpat++ = '%'; *fpat++ = 'm'; *fpat++ = '/';
190 *fpat++ = '%'; *fpat++ = 'd'; *fpat++ = '/';
191 *fpat++ = '%'; *fpat++ = 'y'; pat += 1;
192 break;
193 case 'e':
194 // %e is replaced by the day of the month as a decimal
195 // number [1,31]; a single digit is preceded by a space.
196 if (tmb->tm_mday < 10)
197 *fpat++ = ' ';
198 else
199 *fpat++ = '0' + (tmb->tm_mday / 10) % 10;
200 *fpat++ = '0' + (tmb->tm_mday % 10);
201 pat += 1;
202 break;
203 case 'F':
204 // %F Equivalent to %Y - %m - %d (the ISO 8601:2000 standard
205 // date format). [ tm_year, tm_mon, tm_mday]
206 *fpat++ = '%'; *fpat++ = 'Y';
207 *fpat++ = ' '; *fpat++ = '-'; *fpat++ = ' ';
208 *fpat++ = '%'; *fpat++ = 'm';
209 *fpat++ = ' '; *fpat++ = '-'; *fpat++ = ' ';
210 *fpat++ = '%'; *fpat++ = 'd'; pat += 1;
211 break;
212 case 'g':
213 // %g Replaced by the last 2 digits of the week-based year
214 // as a decimal number [00,99]. [ tm_year, tm_wday, tm_yday]
215 return 0;
216 case 'G':
217 // %G Replaced by the week-based year as a decimal number
218 // (for example, 1977). [ tm_year, tm_wday, tm_yday]
219 return 0;
220 case 'h':
221 // %h same as %b.
222 *fpat++ = '%'; *fpat++ = 'b'; pat += 1;
223 break;
224 case 'n':
225 // %n is replaced by a newline character.
226 *fpat++ = '\n'; pat += 1;
227 break;
228 case 'r':
229 // %r is replaced by the time in a.m. and p.m. notation; in
230 // the POSIX locale this is equivalent to %I:%M:%S %p.
231 *fpat++ = '%'; *fpat++ = 'I'; *fpat++ = ':';
232 *fpat++ = '%'; *fpat++ = 'M'; *fpat++ = ':';
233 *fpat++ = '%'; *fpat++ = 'S'; *fpat++ = ' ';
234 *fpat++ = '%'; *fpat++ = 'p'; pat += 1;
235 break;
236 case 'R':
237 // %R is replaced by the time in 24 hour notation (%H:%M).
238 *fpat++ = '%'; *fpat++ = 'H'; *fpat++ = ':';
239 *fpat++ = '%'; *fpat++ = 'M'; pat += 1;
240 break;
241 case 't':
242 // %t is replaced by a tab character.
243 *fpat++ = '\t'; pat += 1;
244 break;
245 case 'T':
246 // %T is replaced by the time (%H:%M:%S).
247 *fpat++ = '%'; *fpat++ = 'H'; *fpat++ = ':';
248 *fpat++ = '%'; *fpat++ = 'M'; *fpat++ = ':';
249 *fpat++ = '%'; *fpat++ = 'S'; pat += 1;
250 break;
251 case 'u':
252 // %u is replaced by the weekday as a decimal number [1,7],
253 // with 1 representing Monday.
254 *fpat++ = '0' + (tmb->tm_wday + 1);
255 pat += 1;
256 break;
257 case 'V':
258 // %V is replaced by the week number of the year (Monday as
259 // the first day of the week) as a decimal number [01,53].
260 // If the week containing 1 January has four or more days
261 // in the new year, then it is considered week 1. Otherwise,
262 // it is the last week of the previous year, and the next
263 // week is week 1.
264 return 0;
265 default:
266 // copy percent and format
267 *fpat++ = '%';
268 *fpat++ = *pat++;
269 break;
270 }
271
272 *fpat = 0; // null terminate
273 }
274 else {
275 *fpat++ = *pat++;
276 }
277 }
278
279 // copy the null
280 *fpat = *pat;
281
282 const std::size_t n = std::strftime (buf, bufsize, patbuf, tmb);
283
284#else // !_MSC_VER && !__MINGW32__
285
286 const std::size_t n = std::strftime (buf, bufsize, pat, tmb);
287
288#endif // _MSC_VER || __MINGW32__
289
290 RW_ASSERT (n < bufsize);
291
292 return n;
293}
294
295
296std::size_t rw_strftime (wchar_t *wbuf, std::size_t bufsize,
297 const wchar_t *wpat, const std::tm *tmb)
298{
299 static const std::tm tmp = std::tm ();
300
301#if !defined (_RWSTD_NO_WCSFTIME_WCHAR_T_FMAT) \
302 && !defined (_MSC_VER) && !defined (__MINGW32__)
303
304 std::size_t n = std::wcsftime (wbuf, bufsize, wpat, tmb ? tmb : &tmp);
305
306#else // _RWSTD_NO_WCSFTIME || _MSC_VER || __MINGW32__
307
308 char pat [1024];
309 char buf [1024];
310
311 narrow (pat, wpat);
312 std::size_t n = rw_strftime (buf, bufsize, pat, tmb ? tmb : &tmp);
313 widen (wbuf, buf);
314
315#endif // _RWSTD_NO_WCSFTIME, _MSC_VER, __MINGW32__
316
317 RW_ASSERT (n < bufsize);
318
319 return n;
320}
321
322
325template <class charT>
326struct Ios: std::basic_ios<charT>
327{
328 Ios () {
329 this->init (0);
330 }
331};
332
333
334template <class charT>
335struct Buffer: std::basic_streambuf<charT>
336{
337 Buffer (charT *beg, charT *end) {
338 this->setp (beg, end);
339 }
340 void pubsetp (charT *beg, charT *end) {
341 this->setp (beg, end);
342 }
343};
344
345
347template <class charT>
348void do_test (int lineno, // line number containing tests
349 charT, // character type of test
350 const char *tname, // character type name
351 const std::tm *tmb, // may be 0 (extension)
352 const char *pat, // format pattern string
353 int flags, // ios_base flags
354 int width, // ios_base width
355 char fill, // fill character
356 const char *str) // expected result or strftime() format
357{
358 Ios<charT> ios;
359
360 const std::time_put<charT> &tp =
361 std::use_facet<std::time_put<charT> >(ios.getloc ());
362
363 ios.flags (std::ios_base::fmtflags (flags));
364 ios.width (std::streamsize (width));
365
366 charT buf [1024] = { 0 };
367
368 charT result [sizeof buf / sizeof *buf];
369
370 // convert narrow pattern string a (possibly) wide representation
371 charT wpatbuf [256];
372 const charT* const wpat = widen (wpatbuf, pat);
373
374 // `str' may be 0 if testing uspecified behavior (i.e.,
375 // just that the input doesn't cause undefined behavior
376 // such as a crash, but the actual result is unspecified)
377 if (str && '%' == str [0] && tmb) {
378
379 // if expected result string starts with a '%', use it as a format
380 // string to strftime() to obtain the actual result string
381
382 charT wfmtstr [256];
383 widen (wfmtstr, str);
384 std::size_t n = rw_strftime (result, sizeof result / sizeof *result,
385 wfmtstr, tmb);
386
387 RW_ASSERT (n < sizeof result);
388
389 result [n] = charT ();
390
391 if (0 == n || !std::memcmp (result, str, n)) {
392 // unable to convert pattern using strftime, bail out
393 rw_warn (0, 0, __LINE__, "strftime failed");
394 return;
395 }
396 }
397 else if (str)
398 widen (result, str);
399
400
401 const char* const patend =
402 pat + std::char_traits<char>::length (pat);
403
404 // construct a streambuf-derived object to use for formatting
405 Buffer<charT> sb (buf, buf + sizeof buf / sizeof *buf);
406
407 std::ostreambuf_iterator<charT> it (&sb);
408
409 // convert the narrow fill character to the generic charT
410 // being careful to avoid (potential) sign extension
411 typedef unsigned char UChar;
412 const charT wfill = charT (UChar (fill));
413
414 if (patend - pat == 2 && '%' == pat [0]) {
415
416 // format character, no modifier
417 *tp.put (it, ios, wfill, tmb, char (wpat [1])) = charT ();
418
419 const bool success = 0 == rw_strncmp (buf, result);
420
421 rw_assert (!str || success , __FILE__, lineno,
422 "line %d. time_put<%s>::do_put (%{t}, ..., %#c) "
423 "%{?}with TZ=\"%{$TZ}\" %{;}==>"
424 " %{*Ac}, expected %{*Ac}%{?} (strftime format %#s)%{;}, "
425 "flags = %{If}",
426 __LINE__, tname, tmb, pat [1],
427 'Z' == pat [1] || 'z' == pat [1],
428 int (sizeof *buf), buf, int (sizeof *result), result,
429 str && '%' == str [0], str, flags);
430 }
431 else if (patend - pat == 3 && '%' == pat [0]) {
432
433 // format character preceded by a format modifier
434 *tp.put (it, ios, wfill, tmb, char (wpat [2]), char (wpat [1])) =
435 charT ();
436
437 const bool success = 0 == rw_strncmp (buf, result);
438
439 rw_assert (!str || success , __FILE__, lineno,
440 "line %d. time_put<%s>::do_put (%{t}, ..., %#c, %#c) ==>"
441 " %{*Ac}, expected %{*Ac}%{?} (strftime format %#s)%{;}, "
442 "flags = %{If}",
443 __LINE__, tname, tmb, pat [1], pat [2],
444 int (sizeof *buf), buf, int (sizeof *result), result,
445 str && '%' == str [0], str, flags);
446 }
447
448 sb.pubsetp (buf, buf + sizeof buf / sizeof *buf);
449
450 // format string
451 *tp.put (it, ios, wfill, tmb, wpat, wpat + (patend - pat)) = charT ();
452
453 const bool success = 0 == rw_strncmp (buf, result);
454
455 rw_assert (!str || success , __FILE__, lineno,
456 "line %d. time_put<%s>::do_put (%{t}, ..., %#s) "
457 "%{?}with TZ=\"%{$TZ}\" %{;}==>"
458 " %{*Ac}, expected %{*Ac}%{?} (strftime format %#s)%{;}, "
459 "flags = %{If}",
460 __LINE__, tname, tmb, pat,
461 std::strstr (pat, "%Z") || std::strstr (pat, "%z"),
462 int (sizeof *buf), buf, int (sizeof *result), result,
463 str && '%' == str [0], str, flags);
464}
465
466
468struct time_data
469{
470 const char* abday [7]; // %a abbreviated day name
471 const char* day [7]; // %A full day name
472 const char* abmon [12]; // %b abbreviated month name
473 const char* mon [12]; // %B full month name
474 const char* am_pm [2]; // %p AM/PM designator
475 const char* d_t_fmt; // %c date and time
476 const char* d_fmt; // %x date
477 const char* t_fmt; // %X time
478 const char* t_fmt_ampm; // %r time with the AM/PM designaror
479 const char* era_d_t_fmt; // %Ec alternative date and time
480 const char* era_d_fmt; // %EX alternative date
481 const char* era_t_fmt; // %Ex alternative time
482 const char** alt_digits; // alternative numeric symbols
483
484 struct era_data {
485 int offset;
486 int start_day; // [1..31]
487 int start_mon; // [0..11]
488 int start_year;
489 int end_day; // [1..31]
490 int end_mon; // [0..11]
491 int end_year; // INT_MIN, [0..9999], INT_MAX
492 const char *name;
493 const char *format;
494 };
495
496 const era_data* era;
497};
498
499
500const char* make_LC_TIME (const time_data *td)
501{
502 static char locnamebuf [1024];
503
504 // assume `td' points to the same data as the first time
505 // the function was called and reuse the same database
506 if (*locnamebuf)
507 return locnamebuf;
508
509 // create a temporary locale definition file
510 char srcfname [1024];
511 if (rw_snprintf (srcfname, sizeof srcfname, "%s%c%s",
512 locale_root, _RWSTD_PATH_SEP, "LC_TIME.src") < 0)
513 return 0;
514
515 std::FILE *fout = std::fopen (srcfname, "w");
516 if (0 == fout)
517 return 0;
518
519 std::fprintf (fout, "LC_TIME\n");
520
521 unsigned i;
522
523 std::fprintf (fout, "abday ");
524
525 for (i = 0; i != sizeof td->abday / sizeof *td->abday; ++i) {
526 std::fprintf (fout, "\"");
527 pcs_write (fout, td->abday [i]);
528 std::fprintf (fout, "\"%c", i < 6 ? ';' : '\n');
529 }
530
531 std::fprintf (fout, "day ");
532
533 for (i = 0; i != sizeof td->day / sizeof *td->day; ++i) {
534 std::fprintf (fout, "\"");
535 pcs_write (fout, td->day [i]);
536 std::fprintf (fout, "\"%c", i < 6 ? ';' : '\n');
537 }
538
539 std::fprintf (fout, "abmon ");
540
541 for (i = 0; i != sizeof td->abmon / sizeof *td->abmon; ++i) {
542 std::fprintf (fout, "\"");
543 pcs_write (fout, td->abmon [i]);
544 std::fprintf (fout, "\"%c", i < 11 ? ';' : '\n');
545 }
546
547 std::fprintf (fout, "mon ");
548
549 for (i = 0; i != sizeof td->mon / sizeof *td->mon; ++i) {
550 std::fprintf (fout, "\"");
551 pcs_write (fout, td->mon [i]);
552 std::fprintf (fout, "\"%c", i < 11 ? ';' : '\n');
553 }
554
555 std::fprintf (fout, "am_pm ");
556
557 for (i = 0; i != sizeof td->am_pm / sizeof *td->am_pm; ++i) {
558 std::fprintf (fout, "\"");
559 pcs_write (fout, td->am_pm [i]);
560 std::fprintf (fout, "\"%c", i < 1 ? ';' : '\n');
561 }
562
563 // write out d_t_fmt, d_fmt, t_fmt, etc.
564 // preface each line with a comment giving
565 // the specification in a human-readable format
566 std::fprintf (fout, "\n# d_t_fmt \"%s\"\nd_t_fmt \"",
567 td->d_t_fmt);
568 pcs_write (fout, td->d_t_fmt);
569
570 std::fprintf (fout, "\"\n\n# d_fmt \"%s\"\nd_fmt \"",
571 td->d_fmt);
572 pcs_write (fout, td->d_fmt);
573
574 std::fprintf (fout, "\"\n\n# t_fmt \"%s\"\nt_fmt \"",
575 td->t_fmt);
576 pcs_write (fout, td->t_fmt);
577
578 std::fprintf (fout, "\"\n\n# t_fmt_ampm \"%s\"\nt_fmt_ampm \"",
579 td->t_fmt_ampm);
580 pcs_write (fout, td->t_fmt_ampm);
581
582 std::fprintf (fout, "\"\n\n# era_d_t_fmt \"%s\"\nera_d_t_fmt \"",
583 td->era_d_t_fmt);
584 pcs_write (fout, td->era_d_t_fmt);
585
586 std::fprintf (fout, "\"\n\n# era_d_fmt \"%s\"\nera_d_fmt \"",
587 td->era_d_fmt);
588 pcs_write (fout, td->era_d_fmt);
589
590 std::fprintf (fout, "\"\n\n# era_t_fmt \"%s\"\nera_t_fmt \"",
591 td->era_t_fmt);
592 pcs_write (fout, td->era_t_fmt);
593
594 std::fprintf (fout, "\"\nalt_digits ");
595
596 for (i = 0; td->alt_digits [i]; ++i) {
597 std::fprintf (fout, "\"");
598 pcs_write (fout, td->alt_digits [i]);
599 std::fprintf (fout, "\"%c", td->alt_digits [i + 1] ? ';' : '\n');
600 }
601
602 std::fprintf (fout, "\n\nera ");
603
604 for (i = 0; INT_MIN != td->era [i].offset; ++i) {
605
606 char segment [256];
607
608 std::sprintf (segment, "%c:%d:%04d/%02d/%02d:",
609 td->era [i].offset < 0 ? '-' : '+',
610 td->era [i].offset < 0 ? -td->era [i].offset
611 : td->era [i].offset,
612 td->era [i].start_year + 1900,
613 td->era [i].start_mon + 1,
614 td->era [i].start_day);
615
616 const char *end_date = 0;
617
618 if (INT_MIN == td->era [i].end_year)
619 end_date = "-*"; // beginning of time
620 else if (INT_MAX == td->era [i].end_year)
621 end_date = "+*"; // end of time
622
623 if (end_date) {
624 std::sprintf (segment + std::strlen (segment), "%s:%s:%s",
625 end_date, td->era [i].name, td->era [i].format);
626 }
627 else {
628 std::sprintf (segment + std::strlen (segment),
629 "%04d/%02d/%02d:%s:%s",
630 td->era [i].end_year + 1900,
631 td->era [i].end_mon + 1,
632 td->era [i].end_day,
633 td->era [i].name,
634 td->era [i].format);
635 }
636
637 std::fprintf (fout, "\"");
638 pcs_write (fout, segment);
639 std::fprintf (fout, "\"%c",
640 INT_MIN == td->era [i + 1].offset ? '\n' : ';');
641 }
642
643 std::fprintf (fout, "\nEND LC_TIME\n");
644
645 std::fclose (fout);
646
647 // create a temporary character map file
648 char cmfname [1024];
649 if (rw_snprintf (cmfname, sizeof cmfname, "%s%c%s",
650 locale_root, _RWSTD_PATH_SEP, "LC_TIME.cm") < 0)
651 return 0;
652
653 fout = std::fopen (cmfname, "w");
654 if (0 == fout)
655 return 0;
656
657 pcs_write (fout, 0);
658
659 std::fclose (fout);
660
661 const char* const locname =
662 rw_localedef ("", srcfname, cmfname, "test-locale");
663
664 // avoid copying into buffer if it's not big enough: this
665 // this affect the efficiency of the function but not its
666 // behavior
667 if (locname && std::strlen (locname) < sizeof locnamebuf)
668 std::strcpy (locnamebuf, locname);
669
670 // remove temporary files
671 std::remove (cmfname);
672 std::remove (srcfname);
673
674 return locname;
675}
676
677
679const std::tm* mktm (int sec = 0, // [0,60]
680 int min = 0, // [0,59]
681 int hour = 0, // [0,23]
682 int mday = 1, // [1,31]
683 int mon = 0, // [0,11]
684 int year = 0, // Gregorian year - 1900
685 int wday = 0, // [0,6]; 0 = Sunday
686 int yday = 0, // [0,365]
687 int isdst = 0, // < 0, 0, > 0
688 long gmtoff = 0, // offset from GMT in seconds,
689 const char *zone = 0) // timezone name
690{
691 static std::tm tmp = std::tm ();
692
693 if (sec < 0) {
694 // get the current local time
695 std::time_t t = std::time (0);
696 std::tm *tmb = std::localtime (&t);
697 return tmb ? tmb : &tmp;
698 }
699 else if (INT_MAX == sec) {
700 // return 0 to exercise extensions
701 return 0;
702 }
703
704 // use arguments to initialize struct
705 tmp.tm_sec = sec;
706 tmp.tm_min = min;
707 tmp.tm_hour = hour;
708 tmp.tm_mday = mday;
709 tmp.tm_mon = mon;
710 tmp.tm_year = year;
711 tmp.tm_wday = wday;
712 tmp.tm_yday = yday;
713 tmp.tm_isdst = isdst;
714
715#if defined (__linux__) && defined (_RWSTD_NO_PURE_C_HEADERS)
716
717 // support for glibc extension:
718
719 // GNU glibc uses gmtoff and zone instead of timezone and
720 // tzname when computing/formatting time zone information
721 //
722 // http://www.gnu.org/manual/glibc-2.2.3/html_node/libc_425.html#SEC434
723
724# ifndef __USE_BSD
725
726 tmp.__tm_gmtoff = gmtoff;
727 tmp.__tm_zone = zone;
728
729# else // if defined (__USE_BSD)
730
731 tmp.tm_gmtoff = gmtoff;
732 tmp.tm_zone = zone;
733
734# endif // __USE_BSD
735
736#else
737
738 _RWSTD_UNUSED (gmtoff);
739 _RWSTD_UNUSED (zone);
740
741#endif // __linux__ && _RWSTD_NO_PURE_C_HEADERS
742
743 return &tmp;
744}
745
746
747#define T __LINE__, charT (), tname, mktm
748#define TEST do_test
749
750
751template <class charT>
752void test_POSIX (charT, const char *tname)
753{
754 rw_info (0, 0, 0, "std::time_put<%s>, std::locale (\"C\")", tname);
755
756 // exercise the formatting of struct tm in "C" locale
757
758 // %a: the locale's abbreviated weekday name. [tm_wday]
759 rw_info (0, 0, __LINE__, "%%a: the locale's abbreviated weekday name");
760 TEST (T (0, 0, 0, 1, 0, 0, 0), "%a", 0, 0, ' ', "%a");
761 TEST (T (0, 0, 0, 1, 0, 0, 0), "%a", 0, 0, ' ', "Sun");
762 TEST (T (0, 0, 0, 1, 0, 0, 1), "%a", 0, 0, ' ', "Mon");
763 TEST (T (0, 0, 0, 1, 0, 0, 2), "%a", 0, 0, ' ', "Tue");
764 TEST (T (0, 0, 0, 1, 0, 0, 3), "%a", 0, 0, ' ', "Wed");
765 TEST (T (0, 0, 0, 1, 0, 0, 4), "%a", 0, 0, ' ', "Thu");
766 TEST (T (0, 0, 0, 1, 0, 0, 5), "%a", 0, 0, ' ', "Fri");
767 TEST (T (0, 0, 0, 1, 0, 0, 6), "%a", 0, 0, ' ', "Sat");
768 TEST (T (0, 0, 0, 1, 0, 0, 0), "%aday", 0, 0, ' ', "Sunday");
769 TEST (T (0, 0, 0, 1, 0, 0, 0), "Sun", 0, 0, ' ', "%a");
770 TEST (T (-1 /* now */), "%a", 0, 0, ' ', "%a");
771 TEST (T (-1), "%a %a", 0, 0, ' ', "%a %a");
772 TEST (T (0, 0, 0, 1, 0, 0, -1), "%a", 0, 0, ' ', 0 /* unspecified */);
773
774 // %A: the locale's full weekday name. [tm_wday]
775 rw_info (0, 0, __LINE__, "%%A: the locale's full weekday name");
776 TEST (T (0, 0, 0, 1, 0, 0, 0), "%A", 0, 0, ' ', "%A");
777 TEST (T (0, 0, 0, 1, 0, 0, 0), "%A", 0, 0, ' ', "Sunday");
778 TEST (T (0, 0, 0, 1, 0, 0, 1), "%A", 0, 0, ' ', "Monday");
779 TEST (T (0, 0, 0, 1, 0, 0, 2), "%A", 0, 0, ' ', "Tuesday");
780 TEST (T (0, 0, 0, 1, 0, 0, 3), "%A", 0, 0, ' ', "Wednesday");
781 TEST (T (0, 0, 0, 1, 0, 0, 4), "%A", 0, 0, ' ', "Thursday");
782 TEST (T (0, 0, 0, 1, 0, 0, 5), "%A", 0, 0, ' ', "Friday");
783 TEST (T (0, 0, 0, 1, 0, 0, 6), "%A", 0, 0, ' ', "Saturday");
784 TEST (T (0, 0, 0, 1, 0, 0, 0), "Sunday", 0, 0, ' ', "%A");
785 TEST (T (-1 /* now */), "%A", 0, 0, ' ', "%A");
786 TEST (T (-1), "%A %a", 0, 0, ' ', "%A %a");
787 TEST (T (-1), "%a %A", 0, 0, ' ', "%a %A");
788 TEST (T (0, 0, 0, 1, 0, 0, -1), "%A", 0, 0, ' ', 0 /* unspecified */);
789
790 // %b: the locale's abbreviated month name. [tm_mon]
791 rw_info (0, 0, __LINE__, "%%b: the locale's abbreviated month name");
792 TEST (T (0, 0, 0, 1, 0), "%b", 0, 0, ' ', "%b");
793 TEST (T (0, 0, 0, 1, 0), "%b", 0, 0, ' ', "Jan");
794 TEST (T (0, 0, 0, 1, 1), "%b", 0, 0, ' ', "Feb");
795 TEST (T (0, 0, 0, 1, 2), "%b", 0, 0, ' ', "Mar");
796 TEST (T (0, 0, 0, 1, 3), "%b", 0, 0, ' ', "Apr");
797 TEST (T (0, 0, 0, 1, 4), "%b", 0, 0, ' ', "May");
798 TEST (T (0, 0, 0, 1, 5), "%b", 0, 0, ' ', "Jun");
799 TEST (T (0, 0, 0, 1, 6), "%b", 0, 0, ' ', "Jul");
800 TEST (T (0, 0, 0, 1, 7), "%b", 0, 0, ' ', "Aug");
801 TEST (T (0, 0, 0, 1, 8), "%b", 0, 0, ' ', "Sep");
802 TEST (T (0, 0, 0, 1, 9), "%b", 0, 0, ' ', "Oct");
803 TEST (T (0, 0, 0, 1, 10), "%b", 0, 0, ' ', "Nov");
804 TEST (T (0, 0, 0, 1, 11), "%b", 0, 0, ' ', "Dec");
805 TEST (T (0, 0, 0, 1, 0), " %buary", 0, 0, ' ', " January");
806 TEST (T (0, 0, 0, 1, 0), "Jan", 0, 0, ' ', "%b");
807 TEST (T (-1 /* now */), "%b", 0, 0, ' ', "%b");
808 TEST (T (-1), "%b %b", 0, 0, ' ', "%b %b");
809 TEST (T (0, 0, 0, 1, -1), "%b", 0, 0, ' ', 0 /* unspecified */);
810
811 // %B: the locale's full month name. [tm_mon]
812 rw_info (0, 0, __LINE__, "%%B: the locale's full month name");
813 TEST (T (0, 0, 0, 1, 0), "%B", 0, 0, ' ', "%B");
814 TEST (T (0, 0, 0, 1, 0), "%B", 0, 0, ' ', "January");
815 TEST (T (0, 0, 0, 1, 1), "%B", 0, 0, ' ', "February");
816 TEST (T (0, 0, 0, 1, 2), "%B", 0, 0, ' ', "March");
817 TEST (T (0, 0, 0, 1, 3), "%B", 0, 0, ' ', "April");
818 TEST (T (0, 0, 0, 1, 4), "%B", 0, 0, ' ', "May");
819 TEST (T (0, 0, 0, 1, 5), "%B", 0, 0, ' ', "June");
820 TEST (T (0, 0, 0, 1, 6), "%B", 0, 0, ' ', "July");
821 TEST (T (0, 0, 0, 1, 7), "%B", 0, 0, ' ', "August");
822 TEST (T (0, 0, 0, 1, 8), "%B", 0, 0, ' ', "September");
823 TEST (T (0, 0, 0, 1, 9), "%B", 0, 0, ' ', "October");
824 TEST (T (0, 0, 0, 1, 10), "%B", 0, 0, ' ', "November");
825 TEST (T (0, 0, 0, 1, 11), "%B", 0, 0, ' ', "December");
826 TEST (T (), "January", 0, 0, ' ', "%B");
827 TEST (T (-1 /* now */), "%B", 0, 0, ' ', "%B");
828 TEST (T (-1), "%B %b", 0, 0, ' ', "%B %b");
829 TEST (T (-1), "%A %B", 0, 0, ' ', "%A %B");
830 TEST (T (-1), "%A %B ", 0, 0, ' ', "%A %B ");
831 TEST (T (0, 0, 0, 1, -1), "%B", 0, 0, ' ', 0 /* unspecified */);
832
833 // %c: the locale's appropriate date and time representation.
834 // [all specified in 7.23.1 of C99]; equivalent format
835 // specified by POSIX
836 rw_info (0, 0, __LINE__,
837 "%%c: the locale's appropriate date and time representation");
838
839 // avoid comparing against the result of strftime() which
840 // may not conform to the latest POSIX (IEEE Std 1003.1-2001)
841 // (e.g., SunOS 5.7)
842 TEST (T (), "%c", 0, 0, ' ', "%a %b %e %T %Y");
843 TEST (T (), "%c %", 0, 0, ' ', "%a %b %e %T %Y %");
844 TEST (T (), "%c", 0, 0, ' ', "%a %b %e %H:%M:%S %Y");
845 TEST (T (), "%c", 0, 0, ' ', "Sun Jan 1 00:00:00 1900");
846 TEST (T (-1), "%c", 0, 0, ' ', "%a %b %e %T %Y");
847 TEST (T (0, -1), "%c", 0, 0, ' ', 0 /* unspecified */);
848
849 TEST (T ( 1, 2, 3, 4, 5, 6, 0), "%c", 0, 0, ' ',
850 "Sun Jun 4 03:02:01 1906"); // incorrect weekday
851 TEST (T ( 2, 3, 4, 5, 6, 7, 0), "%c", 0, 0, ' ',
852 "Sun Jul 5 04:03:02 1907"); // all fields correct
853 TEST (T (25, 7, 13, 30, 0, 103, 4), "%c", 0, 0, ' ',
854 "Thu Jan 30 13:07:25 2003"); // all fields correct
855
856 // extension: passing (std::tm*)0 to std::time_put<>::put()
857 // and 'c' as the format specifier produces the formatting
858 // pattern corresponding to the locale date and date format
859 TEST (T (INT_MAX), "%c", 0, 0, ' ', "%a %b %e %H:%M:%S %Y");
860
861 // %C: the year divided by 100 and truncated to an integer,
862 // as a decimal number (00-99). [tm_year]
863 rw_info (0, 0, __LINE__,
864 "%%C: the year divided by 100 and truncated to an integer");
865
866 // avoid comparing against the result of strftime() which
867 // may not conform to the latest POSIX (IEEE Std 1003.1-2001)
868 // (e.g., SunOS 5.7)
869 TEST (T (0, 0, 0, 1, 0, 0), "19", 0, 0, ' ', "19");
870 TEST (T (0, 0, 0, 1, 0, 1), "%C", 0, 0, ' ', "19");
871 TEST (T (0, 0, 0, 1, 0, -1), "%C", 0, 0, ' ', "18");
872 TEST (T (0, 0, 0, 1, 0, 99), "%C", 0, 0, ' ', "19");
873 TEST (T (0, 0, 0, 1, 0, -99), "%C", 0, 0, ' ', "18");
874 TEST (T (0, 0, 0, 1, 0, 100), "%C", 0, 0, ' ', "20");
875 TEST (T (0, 0, 0, 1, 0, -100), "%C", 0, 0, ' ', "18");
876 TEST (T (0, 0, 0, 1, 0, 103), "%C", 0, 0, ' ', "20");
877 TEST (T (0, 0, 0, 1, 0, 199), "%C", 0, 0, ' ', "20");
878 TEST (T (0, 0, 0, 1, 0, 200), "%C", 0, 0, ' ', "21");
879 TEST (T (0, 0, 0, 1, 0, 1000), "%C", 0, 0, ' ', "29");
880 TEST (T (0, 0, 0, 1, 0, -1000), "%C", 0, 0, ' ', "09");
881 TEST (T (0, 0, 0, 1, 0, 8100), "%C", 0, 0, ' ', "00");
882 TEST (T (0, 0, 0, 1, 0, -1900), "%C", 0, 0, ' ', "00");
883
884 // %EC: the name of the base year (period) in the locale's
885 // alternative representation.
886 rw_info (0, 0, __LINE__,
887 "%%EC: the name of the period in alternative representation");
888 TEST (T (0, 0, 0, 1, 0, -1899), "%EC", 0, 0, ' ', "00");
889 TEST (T (0, 0, 0, 1, 0, 1234), "%EC", 0, 0, ' ', "31");
890 TEST (T (0, 0, 0, 1, 0, 8099), "%EC", 0, 0, ' ', "99");
891
892
893 // %d: the day of the month as a decimal number (01-31). [tm_mday]
894 rw_info (0, 0, __LINE__, "%%d: the day of the month as a decimal number");
895 TEST (T (), "%d", 0, 0, ' ', "%d");
896 TEST (T (), "%d", 0, 0, ' ', "01");
897 TEST (T (), "01", 0, 0, ' ', "%d");
898 TEST (T (-1), "%d", 0, 0, ' ', "%d");
899
900 TEST (T (0, 0, 0, 1), "%d", 0, 0, ' ', "%d");
901 TEST (T (0, 0, 0, 2), "%d", 0, 0, ' ', "%d");
902 TEST (T (0, 0, 0, 10), "%d", 0, 0, ' ', "%d");
903 TEST (T (0, 0, 0, 11), "%d", 0, 0, ' ', "%d");
904 TEST (T (0, 0, 0, 20), "%d", 0, 0, ' ', "%d");
905 TEST (T (0, 0, 0, 21), "%d", 0, 0, ' ', "%d");
906 TEST (T (0, 0, 0, 30), "%d", 0, 0, ' ', "%d");
907 TEST (T (0, 0, 0, 31), "%d", 0, 0, ' ', "%d");
908 TEST (T (0, 0, 0, -1), "%d", 0, 0, ' ', 0 /* unspecified */);
909
910 // %Od: the day of the month, using the locale's alternative numeric
911 // symbols (filled as needed with leading zeros, or with leading
912 // spaces if there is no alternative symbol for zero).
913 rw_info (0, 0, __LINE__,
914 "%%Od: the day of the month, using alternative digits");
915 TEST (T (0, 0, 0, 1), "%Od", 0, 0, ' ', "01");
916 TEST (T (0, 0, 0, 9), "%Od", 0, 0, ' ', "09");
917 TEST (T (0, 0, 0, 10), "%Od", 0, 0, ' ', "10");
918 TEST (T (0, 0, 0, 13), "%Od", 0, 0, ' ', "13");
919 TEST (T (0, 0, 0, 22), "%Od", 0, 0, ' ', "22");
920 TEST (T (0, 0, 0, 31), "%Od", 0, 0, ' ', "31");
921 TEST (T (0, 0, 0, -1), "%Od", 0, 0, ' ', 0 /* unspecified */);
922
923 // %D: equivalent to "%m/%d/%y". [tm_mon, tm_mday, tm_year]
924 rw_info (0, 0, __LINE__, "%%D: equivalent to \"%%m/%%d/%%y\"");
925 TEST (T (), "%D", 0, 0, ' ', "%D");
926 TEST (T (), "%D", 0, 0, ' ', "%m/%d/%y");
927 TEST (T (), "%D", 0, 0, ' ', "01/01/00");
928 TEST (T (), "01/01/00", 0, 0, ' ', "%D");
929 TEST (T (-1), "%D", 0, 0, ' ', "%D");
930 TEST (T (0, 0, 0, -1), "%D", 0, 0, ' ', 0 /* unspecified */);
931
932 // %e: the day of the month as a decimal number (1-31);
933 // a single digit is preceded by a space. [tm_mday]
934 rw_info (0, 0, __LINE__, "%%e: the day of the month as a decimal number");
935 TEST (T (), "%e", 0, 0, ' ', "%e");
936 TEST (T (), "%e", 0, 0, ' ', " 1");
937 TEST (T (), " 1", 0, 0, ' ', "%e");
938 TEST (T (-1), "%e", 0, 0, ' ', "%e");
939
940 TEST (T (0, 0, 0, 1), "%e", 0, 0, ' ', "%e");
941 TEST (T (0, 0, 0, 2), "%e", 0, 0, ' ', "%e");
942 TEST (T (0, 0, 0, 10), "%e", 0, 0, ' ', "%e");
943 TEST (T (0, 0, 0, 11), "%e", 0, 0, ' ', "%e");
944 TEST (T (0, 0, 0, 20), "%e", 0, 0, ' ', "%e");
945 TEST (T (0, 0, 0, 21), "%e", 0, 0, ' ', "%e");
946 TEST (T (0, 0, 0, 30), "%e", 0, 0, ' ', "%e");
947 TEST (T (0, 0, 0, 31), "%e", 0, 0, ' ', "%e");
948 TEST (T (0, 0, 0, -1), "%e", 0, 0, ' ', 0 /* unspecified */);
949
950 // %Oe: is replaced by the day of the month, using the locale's
951 // alternative numeric symbols (filled as needed with leading
952 // spaces).
953 rw_info (0, 0, __LINE__,
954 "%%Oe: the day of the month using alternative digits");
955 TEST (T (0, 0, 0, 1), "%Oe", 0, 0, ' ', " 1");
956 TEST (T (0, 0, 0, 29), "%Oe", 0, 0, ' ', "29");
957 TEST (T (0, 0, 0, 30), "%Oe", 0, 0, ' ', "30");
958 TEST (T (0, 0, 0, 31), "%Oe", 0, 0, ' ', "31");
959 TEST (T (0, 0, 0, -1), "%Oe", 0, 0, ' ', 0 /* unspecified */);
960
961 // %F: equivalent to "%Y-%m-%d" (the ISO 8601 date format).
962 // [tm_year, tm_mon, tm_mday]
963 rw_info (0, 0, __LINE__, "%%F: equivalent to \"%%Y-%%m-%%d\"");
964 TEST (T (), "%F", 0, 0, ' ', "%Y-%m-%d");
965 TEST (T (), "%F", 0, 0, ' ', "1900-01-01");
966 TEST (T (0, 0, 0, -1), "%F", 0, 0, ' ', 0 /* unspecified */);
967
968 // %g: the last 2 digits of the week-based year as a decimal number
969 // (00-99). [tm_year, tm_wday, tm_yday]
970 rw_info (0, 0, __LINE__, "%%g: the last 2 digits of the week-based year");
971 TEST (T (0, 0, 0, 1, 0, 0, 0, 0), "%g", 0, 0, ' ', "99");
972 TEST (T (0, 0, 0, 1, 0, 102, 2, 120), "%g", 0, 0, ' ', "02");
973 TEST (T (0, 0, 0, 1, 0, 1901, 4, 0), "%g", 0, 0, ' ', "01");
974 TEST (T (0, 0, 0, 1, 0, 1902, 3, 5), "%g", 0, 0, ' ', "02");
975 TEST (T (0, 0, 0, 1, 0, 0, 0, -1), "%g", 0, 0, ' ', 0 /* unspec. */);
976
977 // %G: the week-based year as a decimal number (e.g., 1997).
978 // [tm_year, tm_wday, tm_yday]
979 rw_info (0, 0, __LINE__, "%%G: the week-based year");
980 TEST (T (0, 0, 0, 1, 0, 0, 0, 0), "%G", 0, 0, ' ', "%G");
981 TEST (T (0, 0, 0, 1, 0, -1899, 0, 0), "%G", 0, 0, ' ', "0");
982 TEST (T (0, 0, 0, 1, 0, -100, 0, 0), "%G", 0, 0, ' ', "1799");
983 TEST (T (0, 0, 0, 1, 0, 0, 0, 0), "%G", 0, 0, ' ', "1899");
984 TEST (T (0, 0, 0, 1, 0, 102, 2, 120), "%G", 0, 0, ' ', "2002");
985 TEST (T (0, 0, 0, 1, 0, 2668, 5, 0), "%G", 0, 0, ' ', "4567");
986 TEST (T (0, 0, 0, 1, 0, 2668, 0, 3), "%G", 0, 0, ' ', "4568");
987 TEST (T (-1), "%G", 0, 0, ' ', "%G");
988 TEST (T (0, 0, 0, 1, 0, 0, 0, -1), "%G", 0, 0, ' ', 0 /* unspec. */);
989
990 // %h: equivalent to "%b". [tm_mon]
991 rw_info (0, 0, __LINE__, "%%h: equivalent to \"%%b\"");
992
993 // %H: the hour (24-hour clock) as a decimal number (00-23). [tm_hour]
994 rw_info (0, 0, __LINE__, "%%H: the hour (24-hour clock)");
995 TEST (T (), "%H", 0, 0, ' ', "%H");
996 TEST (T (), "%H", 0, 0, ' ', "00");
997 TEST (T (), "00", 0, 0, ' ', "%H");
998 TEST (T (-1), "%H", 0, 0, ' ', "%H");
999
1000 TEST (T (0, 0, 1), "%H", 0, 0, ' ', "%H");
1001 TEST (T (0, 0, 2), "%H", 0, 0, ' ', "%H");
1002 TEST (T (0, 0, 10), "%H", 0, 0, ' ', "%H");
1003 TEST (T (0, 0, 11), "%H", 0, 0, ' ', "%H");
1004 TEST (T (0, 0, 20), "%H", 0, 0, ' ', "%H");
1005 TEST (T (0, 0, 21), "%H", 0, 0, ' ', "%H");
1006 TEST (T (0, 0, 22), "%H", 0, 0, ' ', "%H");
1007 TEST (T (0, 0, 23), "%H", 0, 0, ' ', "%H");
1008 TEST (T (0, 0, -1), "%H", 0, 0, ' ', 0 /* unspecified */);
1009
1010 // make sure output is unaffected by members other than tm_hour
1011 TEST (T (0, 99, 9), "%H", 0, 0, ' ', "09");
1012 TEST (T (3600, 60, 18), "%H", 0, 0, ' ', "18");
1013 TEST (T (7200, 60, 19), "%H", 0, 0, ' ', "19");
1014
1015 // %OH: the hour (24-hour clock), using the locale's alternative
1016 // numeric symbols.
1017 rw_info (0, 0, __LINE__,
1018 "%%OH: the hour (24-hour clock), using alternative digits");
1019 TEST (T (0, 0, 0), "%OH", 0, 0, ' ', "00");
1020 TEST (T (0, 0, 3), "%OH", 0, 0, ' ', "03");
1021 TEST (T (0, 0, 12), "%OH", 0, 0, ' ', "12");
1022 TEST (T (0, 0, 19), "%OH", 0, 0, ' ', "19");
1023 TEST (T (0, 0, 18), "%OH", 0, 0, ' ', "18");
1024 TEST (T (0, 0, 17), "%OH", 0, 0, ' ', "17");
1025 TEST (T (0, 0, -7), "%OH", 0, 0, ' ', 0 /* unspecified */);
1026
1027 // %I: the hour (12-hour clock) as a decimal number (01-12). [tm_hour]
1028 rw_info (0, 0, __LINE__, "%%I: the hour (12-hour clock)");
1029 TEST (T (0, 0, 0), "%I", 0, 0, ' ', "%I");
1030 TEST (T (0, 0, 0), "%I", 0, 0, ' ', "%I");
1031 TEST (T (0, 0, 1), "%I", 0, 0, ' ', "%I");
1032 TEST (T (0, 0, 1), "%I", 0, 0, ' ', "01");
1033 TEST (T (0, 0, 2), "%I", 0, 0, ' ', "02");
1034 TEST (T (0, 0, 3), "%I", 0, 0, ' ', "03");
1035 TEST (T (0, 0, 11), "%I", 0, 0, ' ', "11");
1036 TEST (T (0, 0, 12), "%I", 0, 0, ' ', "%I");
1037 TEST (T (0, 0, 12), "%I", 0, 0, ' ', "12");
1038 TEST (T (0, 0, 13), "%I", 0, 0, ' ', "%I");
1039 TEST (T (0, 0, 13), "%I", 0, 0, ' ', "01");
1040 TEST (T (0, 0, 21), "%I", 0, 0, ' ', "09");
1041 TEST (T (0, 0, 22), "%I", 0, 0, ' ', "10");
1042 TEST (T (0, 0, 23), "%I", 0, 0, ' ', "11");
1043 TEST (T (0, 0, 24), "%I", 0, 0, ' ', "%I");
1044 TEST (T (0, 0, 0), "12", 0, 0, ' ', "%I");
1045 TEST (T (-1), "%I", 0, 0, ' ', "%I");
1046 TEST (T (0, 0, -2), "%I", 0, 0, ' ', 0 /* unspecified */);
1047
1048 // %OI: the hour (12-hour clock), using the locale's alternative
1049 // numeric symbols.
1050 rw_info (0, 0, __LINE__,
1051 "%%OI: the hour (12-hour clock) using alternative digits");
1052 TEST (T (0, 0, 24), "%OI", 0, 0, ' ', "12");
1053 TEST (T (0, 0, 16), "%OI", 0, 0, ' ', "04");
1054 TEST (T (0, 0, 15), "%OI", 0, 0, ' ', "03");
1055 TEST (T (0, 0, 14), "%OI", 0, 0, ' ', "02");
1056 TEST (T (0, 0, 12), "%OI", 0, 0, ' ', "12");
1057 TEST (T (0, 0, -3), "%OI", 0, 0, ' ', 0 /* unspecified */);
1058
1059 // %j: the day of the year as a decimal number (001-366). [tm_yday]
1060 rw_info (0, 0, __LINE__, "%%j: the day of the year");
1061 TEST (T (0, 0, 0, 0, 0, 0, 0, 0), "%j", 0, 0, ' ', "%j");
1062 TEST (T (0, 0, 0, 0, 0, 0, 0, 0), "%j", 0, 0, ' ', "001");
1063 TEST (T (0, 0, 0, 0, 0, 0, 0, 1), "%j", 0, 0, ' ', "002");
1064 TEST (T (0, 0, 0, 0, 0, 0, 0, 12), "%j", 0, 0, ' ', "013");
1065 TEST (T (0, 0, 0, 0, 0, 0, 0, 123), "%j", 0, 0, ' ', "124");
1066 TEST (T (0, 0, 0, 0, 0, 0, 0, 365), "%j", 0, 0, ' ', "366");
1067 TEST (T (0, 0, 0, 0, 0, 0, 0, 0), "001", 0, 0, ' ', "%j");
1068 TEST (T (-1), "%j", 0, 0, ' ', "%j");
1069 TEST (T (0, 0, 0, 0, 0, 0, 0, -4), "%j", 0, 0, ' ', 0 /* unspecified */);
1070
1071 // %k: the hour (24-hour clock) with single digits preceded by a blank
1072 rw_info (0, 0, __LINE__,
1073 "%%k: the hour (24-hour clock) with single digits "
1074 "preceded by a blank [AIX, Linux, Solaris extension]");
1075 TEST (T (0, 0, 0), "%k", 0, 0, ' ', " 0");
1076 TEST (T (0, 0, 1), "%k", 0, 0, ' ', " 1");
1077 TEST (T (0, 0, 9), "%k", 0, 0, ' ', " 9");
1078 TEST (T (0, 0, 11), "%k", 0, 0, ' ', "11");
1079 TEST (T (0, 0, 12), "%k", 0, 0, ' ', "12");
1080 TEST (T (0, 0, 23), "%k", 0, 0, ' ', "23");
1081
1082#ifdef _RWSTD_OS_SUNOS
1083 // on Solaris, in addition to the results hardcoded above,
1084 // compare the output with that of strftime() and wcsftime()
1085 TEST (T (0, 0, 0), "%k", 0, 0, ' ', "%k");
1086 TEST (T (0, 0, 2), "%k", 0, 0, ' ', "%k");
1087 TEST (T (0, 0, 9), "%k", 0, 0, ' ', "%k");
1088 TEST (T (0, 0, 10), "%k", 0, 0, ' ', "%k");
1089 TEST (T (0, 0, 11), "%k", 0, 0, ' ', "%k");
1090 TEST (T (0, 0, 12), "%k", 0, 0, ' ', "%k");
1091 TEST (T (0, 0, 13), "%k", 0, 0, ' ', "%k");
1092 TEST (T (0, 0, 23), "%k", 0, 0, ' ', "%k");
1093#endif // SunOS
1094
1095 // %l: the hour (12-hour clock) with single digits preceded by a blank
1096 rw_info (0, 0, __LINE__,
1097 "%%l: the hour (12-hour clock) with single digits "
1098 "preceded by a blank [Linux, Solaris extension]");
1099 TEST (T (0, 0, 0), "%l", 0, 0, ' ', "12");
1100 TEST (T (0, 0, 1), "%l", 0, 0, ' ', " 1");
1101 TEST (T (0, 0, 9), "%l", 0, 0, ' ', " 9");
1102 TEST (T (0, 0, 11), "%l", 0, 0, ' ', "11");
1103 TEST (T (0, 0, 12), "%l", 0, 0, ' ', "12");
1104 TEST (T (0, 0, 13), "%l", 0, 0, ' ', " 1");
1105 TEST (T (0, 0, 21), "%l", 0, 0, ' ', " 9");
1106 TEST (T (0, 0, 23), "%l", 0, 0, ' ', "11");
1107
1108#ifdef _RWSTD_OS_SUNOS
1109 // on Solaris, in addition to the results hardcoded above,
1110 // compare the output with that of strftime() and wcsftime()
1111 TEST (T (0, 0, 0), "%l", 0, 0, ' ', "%l");
1112 TEST (T (0, 0, 2), "%l", 0, 0, ' ', "%l");
1113 TEST (T (0, 0, 8), "%l", 0, 0, ' ', "%l");
1114 TEST (T (0, 0, 11), "%l", 0, 0, ' ', "%l");
1115 TEST (T (0, 0, 12), "%l", 0, 0, ' ', "%l");
1116 TEST (T (0, 0, 13), "%l", 0, 0, ' ', "%l");
1117 TEST (T (0, 0, 20), "%l", 0, 0, ' ', "%l");
1118 TEST (T (0, 0, 23), "%l", 0, 0, ' ', "%l");
1119#endif // SunOS
1120
1121 // %m: the month as a decimal number (01-12). [tm_mon]
1122 rw_info (0, 0, __LINE__, "%%m: the month");
1123 TEST (T (), "%m", 0, 0, ' ', "%m");
1124 TEST (T (), "%m", 0, 0, ' ', "01");
1125 TEST (T (), "01", 0, 0, ' ', "%m");
1126 TEST (T (-1), "%m", 0, 0, ' ', "%m");
1127
1128 // %Om: the month, using the locale's alternative numeric symbols.
1129 rw_info (0, 0, __LINE__, "%%Om: the month, using alternative digits");
1130 TEST (T (0, 0, 0, 0, 9), "%Om", 0, 0, ' ', "10");
1131 TEST (T (0, 0, 0, 0, 10), "%Om", 0, 0, ' ', "11");
1132 TEST (T (0, 0, 0, 0, 11), "%Om", 0, 0, ' ', "12");
1133 TEST (T (0, 0, 0, 0, -5), "%Om", 0, 0, ' ', 0 /* unspecified */);
1134
1135 // %M: the minute as a decimal number (00-59). [tm_min]
1136 rw_info (0, 0, __LINE__, "%%M: the minute");
1137 TEST (T (0, 0), "%M", 0, 0, ' ', "%M");
1138 TEST (T (0, 0), "%M", 0, 0, ' ', "00");
1139 TEST (T (0, 1), "%M", 0, 0, ' ', "01");
1140 TEST (T (0, 9), "%M", 0, 0, ' ', "09");
1141 TEST (T (0, 19), "%M", 0, 0, ' ', "19");
1142 TEST (T (0, 59), "%M", 0, 0, ' ', "59");
1143 TEST (T (0, 0), "00", 0, 0, ' ', "%M");
1144 TEST (T (-1), "%M", 0, 0, ' ', "%M");
1145 TEST (T (0, -6), "00", 0, 0, ' ', 0 /* unspecified */);
1146
1147 // %OM: the minutes, using the locale's alternative numeric symbols.
1148 rw_info (0, 0, __LINE__, "%%OM: the minutes, using alternative digits");
1149 TEST (T (0, 0), "%OM", 0, 0, ' ', "00");
1150 TEST (T (0, 7), "%OM", 0, 0, ' ', "07");
1151 TEST (T (0, 11), "%OM", 0, 0, ' ', "11");
1152 TEST (T (0, 22), "%OM", 0, 0, ' ', "22");
1153 TEST (T (0, 33), "%OM", 0, 0, ' ', "33");
1154 TEST (T (0, 44), "%OM", 0, 0, ' ', "44");
1155 TEST (T (0, -7), "%OM", 0, 0, ' ', 0 /* unspecified */);
1156
1157 // %n: a new-line character.
1158 rw_info (0, 0, __LINE__, "%%n: a new-line character");
1159 TEST (T (), "%n", 0, 0, ' ', "%n");
1160 TEST (T (), "%n", 0, 0, ' ', "\n");
1161 TEST (T (), "%n%n", 0, 0, ' ', "\n\n");
1162 TEST (T (), "\n", 0, 0, ' ', "%n");
1163 TEST (T (), "%n \n", 0, 0, ' ', "\n \n");
1164
1165 // %p: the locale's equivalent of the AM/PM designations
1166 // associated with a 12-hour clock. [tm_hour]
1167 rw_info (0, 0, __LINE__,
1168 "%%p: the locale's equivalent of the AM/PM designations");
1169 TEST (T ( 0, 0, 0), "%p", 0, 0, ' ', "%p");
1170 TEST (T ( 0, 0, 1), "%p", 0, 0, ' ', "AM");
1171 TEST (T ( 0, 0, 2), "%p", 0, 0, ' ', "AM");
1172 TEST (T ( 0, 0, 11), "%p", 0, 0, ' ', "AM");
1173 TEST (T ( 0, 0, 12), "%p", 0, 0, ' ', "%p");
1174 TEST (T ( 0, 0, 12), "%p", 0, 0, ' ', "PM");
1175 TEST (T ( 0, 0, 13), "%p", 0, 0, ' ', "%p");
1176 TEST (T ( 0, 0, 23), "%p", 0, 0, ' ', "%p");
1177 TEST (T ( 0, 0, -8), "%p", 0, 0, ' ', 0 /* unspecified */);
1178
1179 // %r: the locale's 12-hour clock time. [tm_hour, tm_min, tm_sec]
1180 rw_info (0, 0, __LINE__, "%%r: the locale's 12-hour clock time");
1181 TEST (T ( 0, 0, 0), "%r", 0, 0, ' ', "%r");
1182 TEST (T ( 0, 0, 0), "%r", 0, 0, ' ', "%I:%M:%S %p");
1183 TEST (T ( 0, 0, 0), "%r", 0, 0, ' ', "12:00:00 AM");
1184 TEST (T ( 1, 12, 1), "%r", 0, 0, ' ', "01:12:01 AM");
1185 TEST (T ( 3, 23, 2), "%r", 0, 0, ' ', "02:23:03 AM");
1186 TEST (T ( 5, 34, 11), "%r", 0, 0, ' ', "11:34:05 AM");
1187 TEST (T ( 7, 45, 12), "%r", 0, 0, ' ', "12:45:07 PM");
1188 TEST (T ( 9, 56, 13), "%r", 0, 0, ' ', "01:56:09 PM");
1189 TEST (T (59, 59, 23), "%r", 0, 0, ' ', "11:59:59 PM");
1190 TEST (T ( 0, 0, 0), "12:00:00 AM", 0, 0, ' ', "%r");
1191 TEST (T (-1), "%r", 0, 0, ' ', "%r");
1192 TEST (T ( 0, 0, -9), "%r", 0, 0, ' ', 0 /* unspecified */);
1193
1194 // %R: equivalent to "%H:%M". [tm_hour, tm_min]
1195 rw_info (0, 0, __LINE__, "%%R: equivalent to \"%%H:%%M\"");
1196 TEST (T (), "%R", 0, 0, ' ', "%R");
1197 TEST (T (), "%R", 0, 0, ' ', "%H:%M");
1198 TEST (T (), "%R", 0, 0, ' ', "00:00");
1199 TEST (T (), "00:00", 0, 0, ' ', "%R");
1200 TEST (T (-1), "%R", 0, 0, ' ', "%R");
1201
1202 // %S: the second as a decimal number (00-60). [tm_sec]
1203 rw_info (0, 0, __LINE__, "%%S: the seconds");
1204 TEST (T (), "%S", 0, 0, ' ', "%S");
1205 TEST (T (), "%S", 0, 0, ' ', "00");
1206 TEST (T (), "00", 0, 0, ' ', "%S");
1207 TEST (T ( 1), "%S", 0, 0, ' ', "%S");
1208 TEST (T ( 2), "%S", 0, 0, ' ', "02");
1209 TEST (T (11), "%S", 0, 0, ' ', "%S");
1210 TEST (T (21), "%S", 0, 0, ' ', "%S");
1211 TEST (T (39), "%S", 0, 0, ' ', "%S");
1212 TEST (T (59), "%S", 0, 0, ' ', "%S");
1213 TEST (T (60), "%S", 0, 0, ' ', "%S");
1214 TEST (T (60), "%S", 0, 0, ' ', "60");
1215 TEST (T (-1), "%S", 0, 0, ' ', "%S");
1216
1217 // %OS: the seconds, using the locale's alternative numeric symbols.
1218 rw_info (0, 0, __LINE__, "%%OS: the seconds, using alternate digits");
1219 TEST (T ( 6), "%OS", 0, 0, ' ', "06");
1220 TEST (T (17), "%OS", 0, 0, ' ', "17");
1221 TEST (T (28), "%OS", 0, 0, ' ', "28");
1222 TEST (T (39), "%OS", 0, 0, ' ', "39");
1223
1224 // %t: a horizontal-tab character.
1225 rw_info (0, 0, __LINE__, "%%t: a horizontal-tab character");
1226 TEST (T (), "%t", 0, 0, ' ', "%t");
1227 TEST (T (), "%t", 0, 0, ' ', "\t");
1228 TEST (T (), "\t", 0, 0, ' ', "%t");
1229 TEST (T (), "%t\t%t", 0, 0, ' ', "\t\t\t");
1230
1231 // %T: equivalent to "%H:%M:%S" (the ISO 8601 time format).
1232 // [tm_hour, tm_min, tm_sec]
1233 rw_info (0, 0, __LINE__, "%%T: equivalent to \"%%H:%%M:%%S\"");
1234 TEST (T (), "%T", 0, 0, ' ', "%T");
1235 TEST (T (), "%T", 0, 0, ' ', "%H:%M:%S");
1236 TEST (T (), "%T", 0, 0, ' ', "00:00:00");
1237 TEST (T (), "00:00:00", 0, 0, ' ', "%T");
1238 TEST (T (-1), "%T", 0, 0, ' ', "%T");
1239
1240 // %u: the ISO 8601 weekday as a decimal number (1-7),
1241 // where Monday is 1. [tm_wday]
1242 rw_info (0, 0, __LINE__, "%%u: the ISO 8601 weekday");
1243 TEST (T (0, 0, 0, 1, 0, 0, 1), "%u", 0, 0, ' ', "1");
1244 TEST (T (0, 0, 0, 1, 0, 0, 2), "%u", 0, 0, ' ', "2");
1245 TEST (T (0, 0, 0, 1, 0, 0, 3), "%u", 0, 0, ' ', "3");
1246 TEST (T (0, 0, 0, 1, 0, 0, 4), "%u", 0, 0, ' ', "4");
1247 TEST (T (0, 0, 0, 1, 0, 0, 5), "%u", 0, 0, ' ', "5");
1248 TEST (T (0, 0, 0, 1, 0, 0, 6), "%u", 0, 0, ' ', "6");
1249 TEST (T (0, 0, 0, 1, 0, 0, 0), "%u", 0, 0, ' ', "7");
1250 TEST (T (0, 0, 0, 1, 0, 0, 7), "%u", 0, 0, ' ', 0 /* unspecified */);
1251
1252 // %Ou: the ISO 8601 weekday as a number in the locale's alternative
1253 // representation, where Monday is 1.
1254 rw_info (0, 0, __LINE__,
1255 "%%Ou: the ISO 8601 weekday using alternative digits");
1256 TEST (T (0, 0, 0, 1, 0, 0, 1), "%Ou", 0, 0, ' ', "1");
1257 TEST (T (0, 0, 0, 1, 0, 0, 2), "%Ou", 0, 0, ' ', "2");
1258 TEST (T (0, 0, 0, 1, 0, 0, 3), "%Ou", 0, 0, ' ', "3");
1259 TEST (T (0, 0, 0, 1, 0, 0, 4), "%Ou", 0, 0, ' ', "4");
1260 TEST (T (0, 0, 0, 1, 0, 0, 5), "%Ou", 0, 0, ' ', "5");
1261 TEST (T (0, 0, 0, 1, 0, 0, 6), "%Ou", 0, 0, ' ', "6");
1262 TEST (T (0, 0, 0, 1, 0, 0, 0), "%Ou", 0, 0, ' ', "7");
1263 TEST (T (0, 0, 0, 1, 0, 0, 8), "%Ou", 0, 0, ' ', 0 /* unspecified */);
1264
1265 // %U: the week number of the year (the first Sunday as the first
1266 // day of week 1) as a decimal number (00-53).
1267 // [tm_year, tm_wday, tm_yday]
1268 rw_info (0, 0, __LINE__, "%%U: the week number of the year");
1269 TEST (T (), "%U", 0, 0, ' ', "%U");
1270 TEST (T (), "%U", 0, 0, ' ', "01");
1271 TEST (T (), "01", 0, 0, ' ', "%U");
1272 TEST (T (-1), "%U", 0, 0, ' ', "%U");
1273 TEST (T (0, 0, 0, 1, 0, 320, 2, 60), "%U", 0, 0, ' ', "09");
1274
1275 // %OU: the week number, using the locale's alternative numeric
1276 // symbols.
1277 rw_info (0, 0, __LINE__, "%%OU: the week number, using alternative digits");
1278 TEST (T (0, 0, 0, 1, 0, 67, 2, 206), "%U", 0, 0, ' ', "30");
1279 TEST (T (0, 0, 0, 1, 0, 99, 5, 365), "%U", 0, 0, ' ', "52");
1280
1281 // %V: the ISO 8601 week number (see below) as a decimal number
1282 // (01-53). [tm_year, tm_wday, tm_yday]
1283 rw_info (0, 0, __LINE__, "%%V: the ISO 8601 week number");
1284
1285 // 4.3.2.2 of ISO 8601:
1286 // A calendar week is identified within a calendar year by the calendar
1287 // week number. This is its ordinal position within the year, applying
1288 // the rule that the first calendar week of a year is the one that
1289 // includes the first Thursday of that year and that the last calendar
1290 // week of a calendar year is the week immediately preceding the first
1291 // calendar week of the next calendar year.
1292
1293 // NOTE 1 These rules provide for a calendar year to have 52 or 53
1294 // calendar weeks;
1295 //
1296 // NOTE 2 The first calendar week of a calendar year may include up
1297 // to three days from the previous calendar year; the last
1298 // calendar week of a calendar year may include up to three
1299 // days from the following calendar year;
1300 //
1301 // NOTE 3 The time-interval formed by the week dates of a calendar
1302 // year is not the same as the time-interval formed by the
1303 // calendar dates or ordinal dates for the same year. For
1304 // instance:
1305 //
1306 // Sun 1995 Jan 1 is the 7th day of the 52nd week of 1994
1307 // Tue 1996 Dec 31 is the 2nd day of the 1st week 1997.
1308 //
1309 // NOTE 4 The rule for determining the first calendar week is
1310 // equivalent with the rule the first calendar week is
1311 // the week which includes January 4.
1312
1313 TEST (T (0, 0, 0, 1, 0, 95, 0, 0), "%V", 0, 0, ' ', "52");
1314 TEST (T (0, 0, 0, 31, 11, 96, 2, 365), "%V", 0, 0, ' ', "01");
1315
1316 // only tm_year, tm_wday, and tm_yday matter
1317 TEST (T (0, 0, 0, 1, 0, 95, 0, 0), "%V", 0, 0, ' ', "52");
1318 TEST (T (0, 0, 0, 1, 0, 96, 2, 365), "%V", 0, 0, ' ', "01");
1319
1320 TEST (T (0, 0, 0, 1, 0, 99, 5, 364), "%V", 0, 0, ' ', "52");
1321
1322 TEST (T (0, 0, 0, 1, 0, 103, 0, 361), "%V", 0, 0, ' ', "52");
1323 TEST (T (0, 0, 0, 1, 0, 103, 1, 362), "%V", 0, 0, ' ', "01");
1324 TEST (T (0, 0, 0, 1, 0, 104, 0, 3), "%V", 0, 0, ' ', "01");
1325 TEST (T (0, 0, 0, 1, 0, 104, 1, 4), "%V", 0, 0, ' ', "02");
1326
1327 TEST (T (0, 0, 0, 1, 0, 109, 0, 360), "%V", 0, 0, ' ', "52");
1328 TEST (T (0, 0, 0, 1, 0, 109, 1, 361), "%V", 0, 0, ' ', "53");
1329 TEST (T (0, 0, 0, 1, 0, 109, 4, 364), "%V", 0, 0, ' ', "53");
1330 TEST (T (0, 0, 0, 1, 0, 110, 5, 0), "%V", 0, 0, ' ', "53");
1331 TEST (T (0, 0, 0, 1, 0, 110, 0, 2), "%V", 0, 0, ' ', "53");
1332 TEST (T (0, 0, 0, 1, 0, 110, 1, 3), "%V", 0, 0, ' ', "01");
1333
1334 // %OV: the ISO 8601 week number, using the locale's alternative
1335 // numeric symbols.
1336 rw_info (0, 0, __LINE__,
1337 "%%OV: the ISO 8601 week number, using alternative digits");
1338 TEST (T (0, 0, 0, 1, 0, 104, 0, 360), "%V", 0, 0, ' ', "52");
1339 TEST (T (0, 0, 0, 1, 0, 104, 1, 361), "%V", 0, 0, ' ', "53");
1340 TEST (T (0, 0, 0, 1, 0, 104, 5, 365), "%V", 0, 0, ' ', "53");
1341 TEST (T (0, 0, 0, 1, 0, 105, 6, 0), "%V", 0, 0, ' ', "53");
1342 TEST (T (0, 0, 0, 1, 0, 105, 0, 1), "%V", 0, 0, ' ', "53");
1343 TEST (T (0, 0, 0, 1, 0, 105, 1, 2), "%V", 0, 0, ' ', "01");
1344
1345
1346 // %w: the weekday as a decimal number (0-6), where Sunday is 0.
1347 // [tm_wday]
1348 rw_info (0, 0, __LINE__, "%%w: the weekday");
1349 TEST (T (), "%w", 0, 0, ' ', "%w");
1350 TEST (T (), "%w", 0, 0, ' ', "0");
1351 TEST (T (), "0", 0, 0, ' ', "%w");
1352 TEST (T (-1), "%w", 0, 0, ' ', "%w");
1353
1354 TEST (T (0, 0, 0, 1, 0, 0, 1), "%w", 0, 0, ' ', "%w");
1355 TEST (T (0, 0, 0, 1, 0, 0, 2), "%w", 0, 0, ' ', "%w");
1356 TEST (T (0, 0, 0, 1, 0, 0, 3), "%w", 0, 0, ' ', "%w");
1357 TEST (T (0, 0, 0, 1, 0, 0, 4), "%w", 0, 0, ' ', "%w");
1358 TEST (T (0, 0, 0, 1, 0, 0, 5), "%w", 0, 0, ' ', "%w");
1359 TEST (T (0, 0, 0, 1, 0, 0, 6), "%w", 0, 0, ' ', "%w");
1360 TEST (T (0, 0, 0, 1, 0, 0, 6), "%w", 0, 0, ' ', "6");
1361
1362 // make sure output is not affected by members other than tm_wday
1363 TEST (T (0, 0, 0, 2, 0, 0, 0), "%w", 0, 0, ' ', "%w");
1364 TEST (T (0, 0, 0, 2, 0, 0, 1), "%w", 0, 0, ' ', "%w");
1365 TEST (T (0, 0, 0, 2, 0, 0, 2), "%w", 0, 0, ' ', "%w");
1366 TEST (T (0, 0, 0, 2, 0, 0, 3), "%w", 0, 0, ' ', "%w");
1367 TEST (T (0, 0, 0, 2, 0, 0, 4), "%w", 0, 0, ' ', "%w");
1368 TEST (T (0, 0, 0, 2, 0, 0, 5), "%w", 0, 0, ' ', "%w");
1369 TEST (T (0, 0, 0, 2, 0, 0, 6), "%w", 0, 0, ' ', "%w");
1370 TEST (T (0, 0, 0, 2, 0, 0, 6), "%w", 0, 0, ' ', "6");
1371
1372 // %Ow: the weekday as a number, using the locale's alternative
1373 // numeric symbols.
1374 rw_info (0, 0, __LINE__,
1375 "%%Ow: the weekday as a number using alternative digits");
1376 TEST (T (0, 0, 0, 1, 0, 0, 0), "%Ow", 0, 0, ' ', "0");
1377 TEST (T (0, 0, 0, 1, 0, 0, 1), "%Ow", 0, 0, ' ', "1");
1378 TEST (T (0, 0, 0, 1, 0, 0, 2), "%Ow", 0, 0, ' ', "2");
1379 TEST (T (0, 0, 0, 1, 0, 0, 3), "%Ow", 0, 0, ' ', "3");
1380 TEST (T (0, 0, 0, 1, 0, 0, 4), "%Ow", 0, 0, ' ', "4");
1381 TEST (T (0, 0, 0, 1, 0, 0, 5), "%Ow", 0, 0, ' ', "5");
1382 TEST (T (0, 0, 0, 1, 0, 0, 6), "%Ow", 0, 0, ' ', "6");
1383
1384 // %W: the week number of the year (the first Monday as the first
1385 // day of week 1) as a decimal number (00-53).
1386 // [tm_year, tm_wday, tm_yday]
1387 rw_info (0, 0, __LINE__, "%%W: the week number of the year");
1388 TEST (T (), "%W", 0, 0, ' ', "%W");
1389 TEST (T (), "%W", 0, 0, ' ', "00");
1390 TEST (T (), "00", 0, 0, ' ', "%W");
1391 TEST (T (-1), "%W", 0, 0, ' ', "%W");
1392
1393 // Monday, 1/1/1900 is week 1 of 1900
1394 TEST (T (0, 0, 0, 1, 0, 0, 1, 0), "%W", 0, 0, ' ', "%W");
1395 // Sunday, 1/7/1900 is week 2 of 1900
1396 TEST (T (0, 0, 0, 1, 0, 0, 0, 6), "%W", 0, 0, ' ', "%W");
1397 // Monday, 1/1/1901 is week 1 of 1901
1398 TEST (T (0, 0, 0, 1, 0, 1, 1, 6), "%W", 0, 0, ' ', "%W");
1399
1400 // %OW: the week number of the year, using the locale's alternative
1401 // numeric symbols.
1402
1403 // Thursday, 7/4/1776 is week 27 of 1776
1404 TEST (T (0, 0, 0, 1, 0, -124, 4, 185), "%OW", 0, 0, ' ', "27");
1405
1406 // %x: the locale's appropriate date representation.
1407 // [all specified in 7.23.1 of C99]
1408 rw_info (0, 0, __LINE__,
1409 "%%x: the locale's appropriate date representation");
1410 TEST (T (), "%x", 0, 0, ' ', "%x");
1411 TEST (T (-1), "%x", 0, 0, ' ', "%x");
1412
1413 // extension: passing (std::tm*)0 to std::time_put<>::put()
1414 // and 'X' as the format specifier produces the formatting
1415 // pattern corresponding to the locale date format
1416 TEST (T (INT_MAX), "%x", 0, 0, ' ', "%m/%d/%y");
1417
1418 // %Ex: the locale's alternative date representation.
1419 rw_info (0, 0, __LINE__,
1420 "%%Ex: the locale's alternative date representation");
1421 TEST (T (0, 0, 0, 18, 2, 90), "%Ex", 0, 0, ' ', "03/18/90");
1422
1423 // %X: the locale's appropriate time representation.
1424 // [all specified in 7.23.1 of C99]
1425 rw_info (0, 0, __LINE__,
1426 "%%X: the locale's appropriate time representation");
1427 TEST (T (), "%X", 0, 0, ' ', "%X");
1428 TEST (T (-1), "%X", 0, 0, ' ', "%X");
1429
1430 // extension: passing (std::tm*)0 to std::time_put<>::put()
1431 // and 'X' as the format specifier produces the formatting
1432 // pattern corresponding to the locale time format
1433 TEST (T (INT_MAX), "%X", 0, 0, ' ', "%H:%M:%S");
1434
1435 // %y: the last 2 digits of the year as a decimal number (00-99).
1436 // [tm_year]
1437 rw_info (0, 0, __LINE__, "%%y: the last 2 digits of the year");
1438 TEST (T (), "%y", 0, 0, ' ', "%y");
1439 TEST (T (), "%y", 0, 0, ' ', "00");
1440 TEST (T (), "00", 0, 0, ' ', "%y");
1441 TEST (T (-1), "%y", 0, 0, ' ', "%y");
1442
1443 TEST (T (0, 0, 0, 1, 0, 99), "%y", 0, 0, ' ', "%y");
1444 TEST (T (0, 0, 0, 1, 0, 99), "%y", 0, 0, ' ', "99");
1445 TEST (T (0, 0, 0, 1, 0, 199), "%y", 0, 0, ' ', "99");
1446 TEST (T (0, 0, 0, 1, 0, 299), "%y", 0, 0, ' ', "99");
1447 TEST (T (0, 0, 0, 1, 0, 399), "%y", 0, 0, ' ', "99");
1448 TEST (T (0, 0, 0, 1, 0, -1), "%y", 0, 0, ' ', "99");
1449 TEST (T (0, 0, 0, 1, 0, -101), "%y", 0, 0, ' ', "99");
1450 TEST (T (0, 0, 0, 1, 0, -201), "%y", 0, 0, ' ', "99");
1451
1452 // %Y: the year as a decimal number (e.g., 1997). [tm_year]
1453 rw_info (0, 0, __LINE__, "%%Y: the year");
1454 TEST (T (), "%Y", 0, 0, ' ', "%Y");
1455 TEST (T (), "%Y", 0, 0, ' ', "1900");
1456 TEST (T (), "1900", 0, 0, ' ', "%Y");
1457 TEST (T (-1), "%Y", 0, 0, ' ', "%Y");
1458
1460 // %z: the offset from UTC in the ISO 8601:2000 standard format
1461 // (+hhmm or -hhmm), or no characters if no timezone can be
1462 // determined.
1463 // For example, "-0430" means 4 hours 30 minutes behind UTC
1464 // (west of Greenwich).
1465 // If tm_isdst is zero, the standard time offset is used.
1466 // If tm_isdst is greater than zero, the daylight savings
1467 // time offset is used.
1468 // If tm_isdst is negative, no characters are returned.
1469 // [tm_isdst]
1470
1471 rw_info (0, 0, __LINE__, "%%z: the offset from UTC in the ISO 8601 format");
1472
1473 // UNIX 98 TZ format
1474 //
1475 // If TZ is of the first format (that is, if the first character
1476 // is a colon), the characters following the colon are handled
1477 // in an implementation-dependent manner. The expanded format
1478 // (for all TZs whose value does not have a colon as the first
1479 // character) is as follows:
1480 //
1481 // stdoffset[dst[offset][,start[/time],end[/time]]]
1482 //
1483 // Where:
1484 //
1485 // std and dst
1486 // Indicates no less than three, nor more than {TZNAME_MAX}, bytes
1487 // that are the designation for the standard (std) or the alternative
1488 // (dst - such as Daylight Savings Time) timezone. Only std is required;
1489 // if dst is missing, then the alternative time does not apply in this
1490 // locale.
1491 // Upper- and lower-case letters are explicitly allowed. Any graphic
1492 // characters except a leading colon (:) or digits, the comma (,),
1493 // the minus (-), the plus (+), and the null character are permitted
1494 // to appear in these fields, but their meaning is unspecified.
1495
1496 // IEEE Std 1003.1-2001
1497 //
1498 // Where:
1499 //
1500 // std and dst
1501 // Indicate no less than three, nor more than {TZNAME_MAX}, bytes
1502 // that are the designation for the standard (std) or the alternative
1503 // (dst - such as Daylight Savings Time) timezone. Only std is required;
1504 // if dst is missing, then the alternative time does not apply in this
1505 // locale.
1506 //
1507 // Each of these fields may occur in either of two formats quoted
1508 // or unquoted:
1509 //
1510 // In the quoted form, the first character shall be the less-than ('<')
1511 // character and the last character shall be the greater-than ('>')
1512 // character. All characters between these quoting characters shall
1513 // be alphanumeric characters from the portable character set in
1514 // the current locale, the plus-sign ('+') character, or the minus-sign
1515 // ('-') character. The std and dst fields in this case shall not include
1516 // the quoting characters.
1517 //
1518 // In the unquoted form, all characters in these fields shall be alphabetic
1519 // characters from the portable character set in the current locale.
1520 //
1521 // The interpretation of these fields is unspecified if either field is
1522 // less than three bytes (except for the case when dst is missing), more
1523 // than {TZNAME_MAX} bytes, or if they contain characters other than those
1524 // specified.
1525
1526 // set TZ to a value in the standard format, arbitrarily choosing
1527 // strings for the std and, optionally, dst parts of the variable
1528 // (they're not used for anything except the name(s) assigned to
1529 // the tznames global variable by tzset())
1530
1531 // unset TZ -- expect no output
1532 set_TZ ("TZ=");
1533 TEST (T (0, 0, 0, 1, 0, 0, 0, 0, 0), "%z", 0, 0, ' ', "");
1534 TEST (T (0, 0, 0, 1, 0, 0, 0, 0, +1), "%z", 0, 0, ' ', "");
1535 TEST (T (0, 0, 0, 1, 0, 0, 0, 0, -1), "%z", 0, 0, ' ', "");
1536
1537 // set TZ to GMT (UTC) plus zero hours, no DST
1538 set_TZ ("TZ=std0");
1539 TEST (T (0, 0, 0, 1, 0, 0, 0, 0, 0), "%z", 0, 0, ' ', "+0000");
1540 // no DST specified, zone info not applicable
1541 // TEST (T (0, 0, 1, 0, 0, 0, 0, 0, +1), "%z", 0, 0, ' ', "+0000");
1542 TEST (T (0, 0, 0, 1, 0, 0, 0, 0, -1), "%z", 0, 0, ' ', "");
1543
1544 // set TZ to GMT+7 hours, no DST
1545 set_TZ ("TZ=foo+7");
1546 TEST (T (0, 0, 0, 1, 0, 0, 0, 0, 0), "%z", 0, 0, ' ', "+0700");
1547 // no DST specified, zone info not applicable
1548 // TEST (T (0, 0, 1, 0, 0, 0, 0, 0, 1), "%z", 0, 0, ' ', "+0700");
1549 TEST (T (0, 0, 0, 1, 0, 0, 0, 0, -1), "%z", 0, 0, ' ', "");
1550
1551 // set TZ to GMT+1 hours and DST to GMT+2 hours
1552 set_TZ ("TZ=abc1def2");
1553 TEST (T (0, 0, 0, 1, 0, 0, 0, 0, 0), "%z", 0, 0, ' ', "+0100");
1554 TEST (T (0, 0, 0, 1, 0, 0, 0, 0, 1), "%z", 0, 0, ' ', "+0200");
1555 TEST (T (0, 0, 0, 1, 0, 0, 0, 0, -1), "%z", 0, 0, ' ', "");
1556
1557 // set TZ to GMT+2 hours and DST to GMT+4 hours
1558 set_TZ ("TZ=abc2def4");
1559 TEST (T (0, 0, 0, 1, 0, 0, 0, 0, 0), "%z", 0, 0, ' ', "+0200");
1560 TEST (T (0, 0, 0, 1, 0, 0, 0, 0, 1), "%z", 0, 0, ' ', "+0400");
1561 TEST (T (0, 0, 0, 1, 0, 0, 0, 0, -1), "%z", 0, 0, ' ', "");
1562
1563 // set TZ to GMT+3 hours and DST to GMT+4 hours
1564 set_TZ ("TZ=abc3:00def4:00");
1565 TEST (T (0, 0, 0, 1, 0, 0, 0, 0, 0), "%z", 0, 0, ' ', "+0300");
1566 TEST (T (0, 0, 0, 1, 0, 0, 0, 0, 1), "%z", 0, 0, ' ', "+0400");
1567
1568 // set TZ to GMT+11:30 hours and DST to GMT+11:45 hours
1569 set_TZ ("TZ=abc11:30:00def11:45");
1570 TEST (T (0, 0, 0, 1, 0, 0, 0, 0, 0), "%z", 0, 0, ' ', "+1130");
1571 TEST (T (0, 0, 0, 1, 0, 0, 0, 0, 1), "%z", 0, 0, ' ', "+1145");
1572
1573 // TZ: STD=GMT+12:34, empty DST
1574 // According to POSIX, when no offset follows DST, the alternative
1575 // time is assumed to be one hour ahead of standard time.
1576 set_TZ ("TZ=bcd12:34efg");
1577 TEST (T (0, 0, 0, 1, 0, 0, 0, 0, 0), "%z", 0, 0, ' ', "+1234");
1578 TEST (T (0, 0, 0, 1, 0, 0, 0, 0, 1), "%z", 0, 0, ' ', "+1334");
1579
1580 // TZ: STD=GMT+23:01, empty DST
1581 set_TZ ("TZ=cde23:01fgh");
1582 TEST (T (0, 0, 0, 1, 0, 0, 0, 0, 0), "%z", 0, 0, ' ', "+2301");
1583 TEST (T (0, 0, 0, 1, 0, 0, 0, 0, 1), "%z", 0, 0, ' ', "+0001");
1584
1585 // TZ: STD=GMT+23:59, empty DST
1586 set_TZ ("TZ=def23:59ghi");
1587 TEST (T (0, 0, 0, 1, 0, 0, 0, 0, 0), "%z", 0, 0, ' ', "+2359");
1588 TEST (T (0, 0, 0, 1, 0, 0, 0, 0, 1), "%z", 0, 0, ' ', "+0059");
1589
1590 set_TZ ("TZ=EST03:00<EDT1>04:00");
1591 TEST (T (0, 0, 0, 1, 0, 0, 0, 0, 0), "%z", 0, 0, ' ', "+0300");
1592 TEST (T (0, 0, 0, 1, 0, 0, 0, 0, 1), "%z", 0, 0, ' ', "+0400");
1593
1594# if 0 // disabled tests of funky std/dst strings
1595
1596 set_TZ ("TZ=<EST+2>03:21EDT04:32");
1597 TEST (T (0, 0, 0, 1, 0, 0, 0, 0, 0), "%z", 0, 0, ' ', "+0321");
1598 TEST (T (0, 0, 0, 1, 0, 0, 0, 0, 1), "%z", 0, 0, ' ', "+0432");
1599
1600 set_TZ ("TZ=EST04:32:10<EDT+03>05:43:21");
1601 TEST (T (0, 0, 0, 1, 0, 0, 0, 0, 0), "%z", 0, 0, ' ', "+0432");
1602 TEST (T (0, 0, 0, 1, 0, 0, 0, 0, 1), "%z", 0, 0, ' ', "+0543");
1603
1604# endif // 0/1
1605
1606 set_TZ ("TZ=EST-4EDT-5");
1607 TEST (T (0, 0, 0, 1, 0, 0, 0, 0, 0), "%z", 0, 0, ' ', "-0400");
1608 TEST (T (0, 0, 0, 1, 0, 0, 0, 0, 1), "%z", 0, 0, ' ', "-0500");
1609
1610 set_TZ ("TZ=EST-5:00EDT-6:00");
1611 TEST (T (0, 0, 0, 1, 0, 0, 0, 0, 0), "%z", 0, 0, ' ', "-0500");
1612 TEST (T (0, 0, 0, 1, 0, 0, 0, 0, 1), "%z", 0, 0, ' ', "-0600");
1613
1614 set_TZ ("TZ=EST-5:43EDT-6:54");
1615 TEST (T (0, 0, 0, 1, 0, 0, 0, 0, 0), "%z", 0, 0, ' ', "-0543");
1616 TEST (T (0, 0, 0, 1, 0, 0, 0, 0, 1), "%z", 0, 0, ' ', "-0654");
1617
1618#ifdef __GLIBC__
1619
1620 rw_info (0, 0, __LINE__, "%%z: with tm::tm_gmtoff - GNU glibc extension");
1621
1622 // exercise support for glibc `tm_gmtoff' extension
1623 // the extension is supported for all non-zero values of tm_gmtoff
1624 // (all other struct tm members, including tm_isdst, are ignored)
1625 // with the idea being that if a program sets the value, it most
1626 // likely expects it to take effect; otherwise POSIX-compliant
1627 // behavior is assumed to be expected
1628
1629 set_TZ ("TZ"); // unset
1630 TEST (T (0, 0, 0, 1, 0, 0, 0, 0, 0, 60), "%z", 0, 0, ' ', "+0001");
1631 TEST (T (0, 0, 0, 1, 0, 0, 0, 0, 1, 120), "%z", 0, 0, ' ', "+0002");
1632 TEST (T (0, 0, 0, 1, 0, 0, 0, 0, -1, 180), "%z", 0, 0, ' ', "");
1633
1634 // setting TZ to an arbitrary value should have no effect
1635 // regardless of the value of the tm_isdst flag
1636 set_TZ ("TZ=PST8");
1637 TEST (T (0, 0, 0, 1, 0, 0, 0, 0, 0, 3600), "%z", 0, 0, ' ', "+0100");
1638 TEST (T (0, 0, 0, 1, 0, 0, 0, 0, 1, -7260), "%z", 0, 0, ' ', "-0201");
1639 TEST (T (0, 0, 0, 1, 0, 0, 0, 0, -1, 1234), "%z", 0, 0, ' ', "");
1640
1641 TEST (T (0, 0, 0, 1, 0, 0, 0, 0, 0, 60), "%z", 0, 0, ' ', "%z");
1642 TEST (T (0, 0, 0, 1, 0, 0, 0, 0, 1, 120), "%z", 0, 0, ' ', "%z");
1643
1644 TEST (T (0, 0, 0, 1, 0, 0, 0, 0, 0, 10800), "%z", 0, 0, ' ', "%z");
1645 TEST (T (0, 0, 0, 1, 0, 0, 0, 0, 1, -14400), "%z", 0, 0, ' ', "%z");
1646
1647#endif // __GLIBC__
1648
1649#ifdef _RWSTD_OS_SUNOS
1650
1651 // exercise platform-specific behavior -- see man -s 5 environ
1652 // and the /usr/share/lib/zoneinfo/ Solaris zone info database
1653
1654 rw_info (0, 0, __LINE__, "%%z: SunOS UZ/zone format [platform-specific]");
1655
1656 set_TZ ("TZ=US/Eastern");
1657 TEST (T (0, 0, 0, 1, 0, 0, 0, 0, 0), "%z", 0, 0, ' ', "+0500");
1658 TEST (T (0, 0, 0, 1, 0, 0, 0, 0, 1), "%z", 0, 0, ' ', "+0600");
1659
1660 set_TZ ("TZ=US/Central");
1661 TEST (T (0, 0, 0, 1, 0, 0, 0, 0, 0), "%z", 0, 0, ' ', "+0600");
1662 TEST (T (0, 0, 0, 1, 0, 0, 0, 0, 1), "%z", 0, 0, ' ', "+0700");
1663
1664 set_TZ ("TZ=US/Mountain");
1665 TEST (T (0, 0, 0, 1, 0, 0, 0, 0, 0), "%z", 0, 0, ' ', "+0700");
1666 TEST (T (0, 0, 0, 1, 0, 0, 0, 0, 1), "%z", 0, 0, ' ', "+0800");
1667
1668 set_TZ ("TZ=US/Pacific");
1669 TEST (T (0, 0, 0, 1, 0, 0, 0, 0, 0), "%z", 0, 0, ' ', "+0800");
1670 TEST (T (0, 0, 0, 1, 0, 0, 0, 0, 1), "%z", 0, 0, ' ', "+0900");
1671
1672#endif // _RWSTD_OS_SUNOS
1673
1675 // %Z: the locale's time zone name or abbreviation, or by no
1676 // characters if no time zone is determinable. [tm_isdst]
1677 rw_info (0, 0, __LINE__,
1678 "%%Z: the locale's time zone name or abbreviation");
1679
1680 set_TZ ("TZ=foo0bar1");
1681 TEST (T (0, 0, 0, 1, 0, 0, 0, 0, 0), "%Z", 0, 0, ' ', "foo");
1682 TEST (T (0, 0, 0, 1, 0, 0, 0, 0, 1), "%Z", 0, 0, ' ', "bar");
1683
1684 // the behavior when tmb is invalid (e.g., when (tm_isdst < 0))
1685 // is undefined, avoid exercising it
1686 // TEST (T (0, 0, 0, 1, 0, 0, 0, 0, -1), "%Z", 0, 0, ' ', "bar");
1687
1688 set_TZ ("TZ=EST1EDT2");
1689 TEST (T (0, 0, 0, 1, 0, 0, 0, 0, 0), "%Z", 0, 0, ' ', "EST");
1690 TEST (T (0, 0, 0, 1, 0, 0, 0, 0, 1), "%Z", 0, 0, ' ', "EDT");
1691
1692 // the behavior when tmb is invalid (e.g., when (tm_isdst < 0))
1693 // is undefined, avoid exercising it
1694 // TEST (T (0, 0, 0, 1, 0, 0, 0, 0, -1), "%Z", 0, 0, ' ', "EDT");
1695
1696 // exercise two-digit hour
1697 set_TZ ("TZ=ABC01DEF02");
1698 TEST (T (0, 0, 0, 1, 0, 0, 0, 0, 0), "%Z", 0, 0, ' ', "ABC");
1699 TEST (T (0, 0, 0, 1, 0, 0, 0, 0, 1), "%Z", 0, 0, ' ', "DEF");
1700
1701 // exercise time zone name of maximum length
1702#if defined (TZNAME_MAX) && !defined (_MSC_VER)
1703 // MSVC may define TZNAME_MAX (if _POSIX_ is defined),
1704 // but tzset() uses hardcoded value equal to 3 instead
1705
1706 char std_name [TZNAME_MAX + 1];
1707 std::memset (std_name, 'A', TZNAME_MAX);
1708 std_name [TZNAME_MAX] = '\0';
1709
1710 char dst_name [TZNAME_MAX + 1];
1711 std::memset (dst_name, 'B', TZNAME_MAX);
1712 dst_name [TZNAME_MAX] = '\0';
1713
1714 char tz_buf [2 * TZNAME_MAX + 8] = "TZ=";
1715 std::strcat (tz_buf, std_name);
1716 std::strcat (tz_buf, "01");
1717 std::strcat (tz_buf, dst_name);
1718 std::strcat (tz_buf, "02");
1719
1720 set_TZ (tz_buf);
1721
1722 TEST (T (0, 0, 0, 1, 0, 0, 0, 0, 0), "%Z", 0, 0, ' ', std_name);
1723 TEST (T (0, 0, 0, 1, 0, 0, 0, 0, 1), "%Z", 0, 0, ' ', dst_name);
1724#endif // TZNAME_MAX && !_MSC_VER
1725
1727 // %%: replaced by %
1728 TEST (T (), " %%", 0, 0, ' ', " %");
1729 TEST (T (), " %%%", 0, 0, ' ', " %%");
1730 TEST (T (), " %%%%", 0, 0, ' ', " %%");
1731 TEST (T (), " %% %%", 0, 0, ' ', " % %");
1732
1733
1734 // exercise non-trivial format strings
1735 TEST (T (), "%%C ", 0, 0, ' ', "%%C ");
1736 TEST (T (), " %%C", 0, 0, ' ', " %C");
1737 TEST (T (), " %%C%", 0, 0, ' ', " %C%");
1738 TEST (T (), " %%C%%", 0, 0, ' ', " %C%");
1739 TEST (T (), " %%%C%%", 0, 0, ' ', " %19%");
1740
1741 TEST (T (), " %%%d%%%", 0, 0, ' ', " %01%%");
1742
1743 TEST (T (), "%Y%%%y", 0, 0, ' ', "1900%00");
1744 TEST (T (), "%C%y", 0, 0, ' ', "1900");
1745 TEST (T (-1), "%Y", 0, 0, ' ', "%Y");
1746
1747 // exercise padding
1748 TEST (T (), "%w", 0, 10, ' ', " 0");
1749 TEST (T (), "%w", 0, 10, '0', "0000000000");
1750 TEST (T (0, 0, 0, 1, 0, 0, 1), "%w", 0, 10, '0', "0000000001");
1751
1752 TEST (T (1), "%S", std::ios::left, 10, '*', "01********");
1753 TEST (T (2), "%S", std::ios::right, 10, '*', "********02");
1754 TEST (T (3), "%S", std::ios::internal, 10, '*', "********03");
1755
1756 TEST (T (13), "%S", std::ios::left | std::ios::right, 11, '_',
1757 "_________13");
1758
1759 TEST (T (24), "%S", std::ios::left | std::ios::internal, 12, '_',
1760 "__________24");
1761
1762 TEST (T (35), "%S",
1763 std::ios::left | std::ios::right | std::ios::internal, 13, '_',
1764 "___________35");
1765
1766 // 7.23.3.5, p5 of C99:
1767 // %g, %G, and %V give values according to the ISO 8601 week-based
1768 // year. In this system, weeks begin on a Monday and week 1 of the
1769 // year is the week that includes January 4th, which is also the
1770 // week that includes the first Thursday of the year, and is also
1771 // the first week that contains at least four days in the year.
1772
1773 // If the first Monday of January is the 2nd, 3rd, or 4th, the
1774 // preceding days are part of the last week of the preceding year;
1775 // thus, for Saturday 2nd January 1999, %G is replaced by 1998 and
1776 // %V is replaced by 53. If December 29th, 30th, or 31st is a Monday,
1777 // it and any following days are part of week 1 of the following
1778 // year. Thus, for Tuesday 30th December 1997, %G is replaced by
1779 // 1998 and %V is replaced by 01.
1780
1781 // Saturday 2nd January 1999
1782 TEST (T (0, 0, 0, 2, 0, 99, 6, 1), "%g", 0, 0, ' ', "98");
1783 TEST (T (0, 0, 0, 2, 0, 99, 6, 1), "%G", 0, 0, ' ', "1998");
1784 TEST (T (0, 0, 0, 2, 0, 99, 6, 1), "%V", 0, 0, ' ', "53");
1785
1786 // only [tm_year, tm_wday, tm_yday] are considered
1787 // leave tm_mday 0 and check that the result is the same
1788 TEST (T (0, 0, 0, 1, 0, 99, 6, 1), "%g", 0, 0, ' ', "98");
1789 TEST (T (0, 0, 0, 1, 0, 99, 6, 1), "%G", 0, 0, ' ', "1998");
1790 TEST (T (0, 0, 0, 1, 0, 99, 6, 1), "%V", 0, 0, ' ', "53");
1791
1792 // Tuesday 30th December 1997
1793 TEST (T (0, 0, 0, 30, 11, 97, 2, 363), "%g", 0, 0, ' ', "98");
1794 TEST (T (0, 0, 0, 30, 11, 97, 2, 363), "%G", 0, 0, ' ', "1998");
1795 TEST (T (0, 0, 0, 30, 11, 97, 2, 363), "%V", 0, 0, ' ', "01");
1796
1797 // only [tm_year, tm_wday, tm_yday] are considered
1798 // leave tm_mday 0 and check the result
1799 TEST (T (0, 0, 0, 1, 0, 97, 2, 363), "%g", 0, 0, ' ', "98");
1800 TEST (T (0, 0, 0, 1, 0, 97, 2, 363), "%G", 0, 0, ' ', "1998");
1801 TEST (T (0, 0, 0, 1, 0, 97, 2, 363), "%V", 0, 0, ' ', "01");
1802}
1803
1804
1807template <class charT>
1808void test_user (charT, const char *tname)
1809{
1810 rw_info (0, 0, 0,
1811 "std::time_put<%s>, using generated LC_TIME data", tname);
1812
1813 const char* /* const */ alt_digits[] = {
1814 "", "1st", "2nd", "3rd", "4th",
1815 "5th", "6th", "7th", "8th", "9th",
1816 "10th", "11th", "12th", "13th", "14th",
1817 "15th", "16th", "17th", "18th", "19th",
1818 "20th", "21st", "22nd", "23rd", "24th",
1819 "25th", "26th", "27th", "28th", "29th",
1820 "30th", "31st", 0 // sentinel
1821 };
1822
1823 const time_data::era_data era[] = {
1824 // some entries copied and modified from HP-UX 11.11 ja_JP.utf8
1825 //
1826 // # 1990-01-02 and onward: "Heisei%EyNen" (1990 is Heisei 2 Nen.)
1827 // # 1990-01-01 to 1990-01-02: "%C" (no era specified)
1828 // # 1989-01-08 to 1989-12-31: "HeiseiGannen"
1829 // # 1927-01-01 to 1989-01-07: "Showa%EyNen" (1927 is Showa 2 Nen.)
1830 // # 1927-01-01 and prior: "foo"
1831 // era "+:2:1990/01/02:+*:<U????><U????>:%EC%Ey<U????>";
1832 // "+:1:1989/01/08:1989/12/31:<U????>:%EC<U????><U????>";
1833 // "+:2:1927/01/01:1989/01/07:<U????><U????>:%EC%Ey<U????>";
1834 // "-:7:1926/12/31:-*:foo:bar%EC%Ey"
1835
1836 // 7|2 |1 | |2 starting year in an era
1837 // <<<|>>>>>>>>>|>>>>>>>>>|.|>>> direction in which years increase
1838 // ^ ^ ^ ^
1839 // | | | |
1840 // | | | +-> Jan 2, 1990 (Heisei %Ey Nen)
1841 // | | +-> Dec 31, 1989 (%C)
1842 // | +-> Jan 7, 1989 (Heisei Gannen)
1843 // +-> Jan 1, 1927 (Showa %Ey Nen)
1844 // +-< Dec 31, 1926 (foobar %Ey)
1845
1846 { 2, 2, 0, 90, 0, 0, INT_MAX, "Heisei", "%EC %Ey Nen" },
1847 { 1, 8, 0, 89, 31, 11, 89, "Heisei", "%EC Gannen" },
1848 { 2, 1, 0, 27, 7, 0, 89, "Showa", "%EC %Ey Nen" },
1849 { -7, 31, 11, 26, 0, 0, INT_MIN, "bar", "foo%EC %Ey" },
1850 { INT_MIN /* sentinel entry */, 0, 0, 0, 0, 0, 0, 0, 0 }
1851 };
1852
1853 const time_data td = {
1854 // %a
1855 { "[Sun]", "[Mon]", "[Tue]", "[Wed]", "[Thu]", "[Fri]", "[Sat]" },
1856
1857 // %A
1858 {
1859 "[Sunday]", "[Monday]", "[Tuesday]", "[Wednesday]", "[Thursday]",
1860 "[Friday]", "[Saturday]"
1861 },
1862
1863 // %b
1864 {
1865 "[Jan]", "[Feb]", "[Mar]", "[Apr]", "[May]", "[Jun]",
1866 "[Jul]", "[Aug]", "[Sep]", "[Oct]", "[Nov]", "[Dec]",
1867 },
1868
1869 // %B
1870 {
1871 "[January]", "[February]", "[March]", "[April]", "[May]", "[June]",
1872 "[July]", "[August]", "[September]", "[October]", "[November]",
1873 "[December]",
1874 },
1875
1876 { "[A.M.]", "[P.M.]" }, // %p
1877
1878 "[[%a][%b][%d][%H][%M][%S][%y]]", // %c
1879 "[[%3m][%.4d][%4.3y]]", // %x
1880 "[[%3H][%.4M][%4.3S]]", // %X
1881 "[[%I][%M][%S][%p]]", // %r
1882 "[[%A][%B][%d][%H][%M][%S][%Y]]", // %Ec
1883 "[[%B][%d][%Y]]", // %Ex
1884 "[[%H hrs][%M min][%S sec]]", // %EX
1885
1886 alt_digits, era
1887 };
1888
1889 // create a LC_TIME database based on data above
1890 const char* const locname = make_LC_TIME (&td);
1891
1892 if (!rw_error (0 != locname, 0, __LINE__,
1893 "failed to generate LC_TIME locale data"))
1894 return;
1895
1896 // construct a locale object from the binary database
1897 std::locale loc;
1898
1899 _TRY {
1900 loc = std::locale (std::locale (), locname, std::locale::time);
1901 }
1902 _CATCH (...) {
1903 rw_error (0, 0, __LINE__,
1904 "std::locale (std::locale (), \"%s\", std::locale::time) "
1905 "unexpectedly threw an exception", locname);
1906 return;
1907 }
1908
1909 // set the global locale (used by the test function)
1910 std::locale::global (loc);
1911
1912 unsigned i;
1913
1914 rw_info (0, 0, __LINE__, "%%a: the locale's abbreviated weekday name");
1915 rw_info (0, 0, __LINE__, "%%A: the locale's full weekday name");
1916
1917 // verify that data formatted by std::time_put match that specified above
1918 for (i = 0; i != 7; ++i) {
1919 TEST (T (0, 0, 0, 1, 0, 0, i), "%a", 0, 0, ' ', td.abday [i]);
1920 TEST (T (0, 0, 0, 1, 0, 0, i), "%A", 0, 0, ' ', td.day [i]);
1921 }
1922
1923 rw_info (0, 0, __LINE__, "%%b: the locale's abbreviated month name");
1924 rw_info (0, 0, __LINE__, "%%B: the locale's full month name");
1925
1926 for (i = 0; i != 12; ++i) {
1927 TEST (T (0, 0, 0, 1, i), "%b", 0, 0, ' ', td.abmon [i]);
1928 TEST (T (0, 0, 0, 1, i), "%B", 0, 0, ' ', td.mon [i]);
1929 }
1930
1931 rw_info (0, 0, __LINE__,
1932 "%%c: the locale's appropriate date and time representation");
1933 TEST (T (INT_MAX), "%c", 0, 0, ' ', td.d_t_fmt);
1934
1935 rw_info (0, 0, __LINE__,
1936 "%%r: the locale's time representation in the AM/PM notation");
1937 TEST (T (INT_MAX), "%r", 0, 0, ' ', td.t_fmt_ampm);
1938
1939 rw_info (0, 0, __LINE__,
1940 "%%X: the locale's appropriate time representation");
1941 TEST (T (INT_MAX), "%X", 0, 0, ' ', td.t_fmt);
1942
1943 // extension: format specifies width and optional precision
1944 // not available through time_put interface (only allowed in
1945 // formats contained in the database)
1946 //
1947 // format "[[%3H][%.4M][%4.3S]]" specifies:
1948 // ^ ^^ ^ ^
1949 // | || | |
1950 // +----|+----|-+-- minimum number of digits, padded with '0'
1951 // +-----+---- minimum field with, padded with ' '
1952 //
1953 TEST (T (1, 2, 3), "%X", 0, 0, ' ', "[[ 3][0002][ 001]]");
1954
1955 rw_info (0, 0, __LINE__,
1956 "%%x: the locale's appropriate date and time representation");
1957 TEST (T (0, 0, 0, 4, 5, 6), "%x", 0, 0, ' ', "[[ 6][0004][ 006]]");
1958 TEST (T (INT_MAX), "%x", 0, 0, ' ', td.d_fmt);
1959
1960
1961 // %Ec: the alternative date and time representation.
1962 rw_info (0, 0, __LINE__,
1963 "%%Ec: the alternative date and time representation");
1964 TEST (T (INT_MAX), "%Ec", 0, 0, ' ', td.era_d_t_fmt);
1965 TEST (T (22, 5, 18, 26, 3, 102, 5), "%Ec", 0, 0, ' ',
1966 // "[[%A][%B][%d][%H][%M][%S][%Y]]"
1967 "[[[Friday]][[April]][26][18][05][22][2002]]");
1968
1969
1970 // %EC: the name of the base year (period) in the locale's
1971 // alternative representation.
1972 rw_info (0, 0, __LINE__,
1973 "%%Ec: the name of the base year (period) in the locale's "
1974 "alternative representation");
1975 TEST (T (0, 0, 0, 1, 0, -100), "%EC", 0, 0, ' ', era [3].name);
1976 TEST (T (0, 0, 0, 1, 0, 0), "%EC", 0, 0, ' ', era [3].name);
1977 TEST (T (0, 0, 0, 31, 11, 26), "%EC", 0, 0, ' ', era [3].name);
1978 TEST (T (0, 0, 0, 1, 0, 27), "%EC", 0, 0, ' ', era [2].name);
1979 TEST (T (0, 0, 0, 7, 0, 89), "%EC", 0, 0, ' ', era [2].name);
1980 TEST (T (0, 0, 0, 8, 0, 89), "%EC", 0, 0, ' ', era [1].name);
1981 TEST (T (0, 0, 0, 31, 11, 89), "%EC", 0, 0, ' ', era [1].name);
1982 TEST (T (0, 0, 0, 1, 0, 90), "%EC", 0, 0, ' ', "19");
1983 TEST (T (0, 0, 0, 2, 0, 90), "%EC", 0, 0, ' ', era [0].name);
1984 TEST (T (0, 0, 0, 30, 3, 102), "%EC", 0, 0, ' ', era [0].name);
1985
1986
1987 // %Ex: the locale's alternative date representation.
1988 rw_info (0, 0, __LINE__,
1989 "%%Ex: the locale's alternative date representation");
1990 TEST (T (INT_MAX), "%Ex", 0, 0, ' ', td.era_d_fmt);
1991 // "[[%B][%d][%Y]]"
1992 TEST (T (0, 0, 0, 26, 3, 102), "%Ex", 0, 0, ' ', "[[[April]][26][2002]]");
1993
1994 // %EX: the locale's alternative time representation.
1995 rw_info (0, 0, __LINE__,
1996 "%%EX: the locale's alternative time representation");
1997 TEST (T (INT_MAX), "%EX", 0, 0, ' ', td.era_t_fmt);
1998 // "[[%H hrs][%M min][%S sec]]"
1999 TEST (T (22, 5, 18), "%EX", 0, 0, ' ', "[[18 hrs][05 min][22 sec]]");
2000
2001 // %Ey: the offset from %EC (year only) in the alternative representation.
2002 rw_info (0, 0, __LINE__,
2003 "%%Ey: the offset from %%EC in the alternative representation");
2004 TEST (T (0, 0, 0, 1, 0, -100), "%Ey", 0, 0, ' ', "133"); // grows down
2005 TEST (T (0, 0, 0, 1, 0, 0), "%Ey", 0, 0, ' ', "33"); // grows down
2006 TEST (T (0, 0, 0, 1, 0, 2), "%Ey", 0, 0, ' ', "31st"); // grows down
2007 TEST (T (0, 0, 0, 1, 0, 20), "%Ey", 0, 0, ' ', "13th"); // grows down
2008 TEST (T (0, 0, 0, 31, 11, 26), "%Ey", 0, 0, ' ', "7th"); // grows down
2009 TEST (T (0, 0, 0, 1, 0, 27), "%Ey", 0, 0, ' ', "2nd"); // grows up
2010 TEST (T (0, 0, 0, 7, 0, 89), "%Ey", 0, 0, ' ', "64"); // no era
2011 TEST (T (0, 0, 0, 8, 0, 89), "%Ey", 0, 0, ' ', "1st"); // grows up
2012 TEST (T (0, 0, 0, 31, 11, 89), "%Ey", 0, 0, ' ', "1st"); // grows up
2013 TEST (T (0, 0, 0, 1, 0, 90), "%Ey", 0, 0, ' ', "90"); // grows up
2014 TEST (T (0, 0, 0, 2, 0, 90), "%Ey", 0, 0, ' ', "2nd"); // grows up
2015 TEST (T (0, 0, 0, 30, 3, 102), "%Ey", 0, 0, ' ', "14th"); // grows up
2016
2017 // %EY: the full alternative year representation.
2018 rw_info (0, 0, __LINE__, "%%EY: the full alternative year representation");
2019 TEST (T (0, 0, 0, 1, 0, 0), "%EY", 0, 0, ' ', "foobar 33");
2020 TEST (T (0, 0, 0, 31, 11, 26), "%EY", 0, 0, ' ', "foobar 7th");
2021 TEST (T (0, 0, 0, 1, 0, 27), "%EY", 0, 0, ' ', "Showa 2nd Nen");
2022 TEST (T (0, 0, 0, 7, 0, 89), "%EY", 0, 0, ' ', "Showa 64 Nen");
2023 TEST (T (0, 0, 0, 8, 0, 89), "%EY", 0, 0, ' ', "Heisei Gannen");
2024 TEST (T (0, 0, 0, 31, 11, 89), "%EY", 0, 0, ' ', "Heisei Gannen");
2025 TEST (T (0, 0, 0, 1, 0, 90), "%EY", 0, 0, ' ', "1990");
2026 TEST (T (0, 0, 0, 2, 0, 90), "%EY", 0, 0, ' ', "Heisei 2nd Nen");
2027 TEST (T (0, 0, 0, 30, 3, 102), "%EY", 0, 0, ' ', "Heisei 14th Nen");
2028
2029 // reset the global locale and delete the temporary combined locale
2030 std::locale::global (std::locale ("C"));
2031}
2032
2033
2035static int
2036run_test (int, char*[])
2037{
2038 // set up RWSTD_LOCALE_ROOT and other environment variables
2039 // here as opposed to at program startup to work around a
2040 // SunOS 5.7 putenv() bug (PR #30017)
2042
2043 // exercise std::time_put in the C/POSIX locale
2044 test_POSIX (char (), "char");
2045
2046 // exercise std::time_put in a user-specified locale
2047 test_user (char (), "char");
2048
2049#ifndef _RWSTD_NO_WCHAR_T
2050
2051 test_POSIX (wchar_t (), "wchar_t");
2052
2053 test_user (wchar_t (), "wchar_t");
2054
2055#endif // _RWSTD_NO_WCHAR_T
2056
2057 return 0;
2058
2059}
2060
2061
2063int main (int argc, char *argv[])
2064{
2065 return rw_test (argc, argv, __FILE__,
2066 "lib.locale.time.put",
2067 0 /* no comment */,
2068 run_test,
2069 "",
2070 0);
2071}
#define i
Definition 17.names.cpp:126
#define t
Definition 17.names.cpp:136
#define loc
Definition 17.names.cpp:492
#define sec
Definition 17.names.cpp:539
#define sb
Definition 17.names.cpp:542
#define lineno
Definition 17.names.cpp:491
#define buf
Definition 17.names.cpp:452
#define charT
Definition 17.names.cpp:456
#define tmp
Definition 17.names.cpp:553
#define len
Definition 17.names.cpp:488
#define n
Definition 17.names.cpp:130
volatile int result
const char std_name[]
#define flags
#define T
const char * make_LC_TIME(const time_data *td)
void test_POSIX(charT, const char *tname)
void test_user(charT, const char *tname)
const char * widen(char *dst, const char *src)
std::size_t rw_strftime(char *buf, std::size_t bufsize, const char *pat, const std::tm *tmb)
void set_TZ(const char *str)
const char * narrow(char *dst, const char *src)
#define TEST
const char * locale_root
const std::tm * mktm(int sec=0, int min=0, int hour=0, int mday=1, int mon=0, int year=0, int wday=0, int yday=0, int isdst=0, long gmtoff=0, const char *zone=0)
void do_test(int line, const char *src, std::size_t resoff, ForwardIterator dummy_iter, const T *, const char *predname)
void run_test(const ForwardIterator &dummy, T *, Predicate *pred)
const int end
#define main
#define assert(expr)
Definition _cassert.h:40
#define _RWSTD_PATH_SEP
Definition _config.h:297
#define _RWSTD_DLLIMPORT
Definition _config.h:391
#define _RWSTD_UNUSED(arg)
Definition _defs.h:972
#define _LIBC_THROWS()
Definition _defs.h:1152
#define _TRY
Definition _defs.h:850
#define _CATCH(ex)
Definition _defs.h:851
const char * name
Definition codecvt1.cpp:72
std::mbstate_t init
Definition codecvt1.cpp:80
const char * str
Definition exec.cpp:170
#define INT_MIN
Definition limits.h:80
#define INT_MAX
Definition limits.h:76
_TEST_EXPORT int rw_test(int argc, char *argv[], const char *filename, const char *clause, const char *comment, int(*testfun)(int, char **), const char *optspec,...)
_TEST_EXPORT int rw_info(int, const char *, int, const char *,...)
Definition driver.cpp:1681
_TEST_EXPORT int rw_assert(int, const char *, int, const char *,...)
Definition driver.cpp:1630
_TEST_EXPORT int rw_error(int, const char *, int, const char *,...)
Definition driver.cpp:1613
_TEST_EXPORT int rw_warn(int, const char *, int, const char *,...)
Definition driver.cpp:1647
_TEST_EXPORT int rw_putenv(const char *, int=-1)
Definition environ.cpp:69
_TEST_EXPORT void pcs_write(void *, const char *)
Definition file.cpp:89
_TEST_EXPORT const char * rw_set_locale_root()
Definition locale.cpp:324
_TEST_EXPORT const char * rw_localedef(const char *, const char *, const char *, const char *)
Definition locale.cpp:154
_TEST_EXPORT int rw_snprintf(char *, _RWSTD_SIZE_T, const char *,...)
#define RW_ASSERT(expr)
_TEST_EXPORT int rw_strncmp(const char *, const char *, _RWSTD_SIZE_T=_RWSTD_SIZE_MAX, int=CMP_NULTERM)
unsigned char UChar
Definition collate.cpp:122
void pubsetp(charT *beg, charT *end)
Buffer(charT *beg, charT *end)
const era_data * era
const char * t_fmt_ampm
const char * am_pm[2]
const char *const * alt_digits
const char * abday[7]
const char * abmon[12]
const char * d_fmt
const char * era_t_fmt
const char * era_d_fmt
const char * era_d_t_fmt
const char * day[7]
const char * mon[12]
const char ** alt_digits
const char * d_t_fmt
const char * t_fmt
#define min(a, b)