General Utility Library for C++17 25.4.1
date.h
Go to the documentation of this file.
1
40#ifndef GUL17_DATE_H_
41#define GUL17_DATE_H_
42
43#include <algorithm>
44#include <cassert>
45#include <cctype>
46#include <chrono>
47#include <climits>
48#include <cmath>
49#include <cstddef>
50#include <cstdint>
51#include <cstdlib>
52#include <ctime>
53#include <ios>
54#include <istream>
55#include <iterator>
56#include <limits>
57#include <locale>
58#include <memory>
59#include <ostream>
60#include <ratio>
61#include <sstream>
62#include <stdexcept>
63#include <string_view>
64#include <string>
65#include <type_traits>
66#include <utility>
67
69
70#ifdef __GNUC__
71# pragma GCC diagnostic push
72# if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 7)
73# pragma GCC diagnostic ignored "-Wpedantic"
74# endif
75# if __GNUC__ < 5
76 // GCC 4.9 Bug 61489 Wrong warning with -Wmissing-field-initializers
77# pragma GCC diagnostic ignored "-Wmissing-field-initializers"
78# endif
79#endif
80
81#ifdef _MSC_VER
82# pragma warning(push)
83// warning C4127: conditional expression is constant
84# pragma warning(disable : 4127)
85#endif
86
87namespace gul17 {
88namespace date {
89
90//---------------+
91// Configuration |
92//---------------+
93
94#ifndef ONLY_C_LOCALE
95# define ONLY_C_LOCALE 0
96#endif
97
98#ifndef HAS_UNCAUGHT_EXCEPTIONS
99# if __cplusplus >= 201703 || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
100# define HAS_UNCAUGHT_EXCEPTIONS 1
101# else
102# define HAS_UNCAUGHT_EXCEPTIONS 0
103# endif
104#endif // HAS_UNCAUGHT_EXCEPTIONS
105
106#ifndef HAS_VOID_T
107# if __cplusplus >= 201703 || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
108# define HAS_VOID_T 1
109# else
110# define HAS_VOID_T 0
111# endif
112#endif // HAS_VOID_T
113
114// Work around for a NVCC compiler bug which causes it to fail
115// to compile std::ratio_{multiply,divide} when used directly
116// in the std::chrono::duration template instantiations below
117namespace detail {
118template <typename R1, typename R2>
119using ratio_multiply = decltype(std::ratio_multiply<R1, R2>{});
120
121template <typename R1, typename R2>
122using ratio_divide = decltype(std::ratio_divide<R1, R2>{});
123} // namespace detail
124
125//-----------+
126// Interface |
127//-----------+
128
129// durations
130
131using days = std::chrono::duration
132 <int, detail::ratio_multiply<std::ratio<24>, std::chrono::hours::period>>;
133
134using weeks = std::chrono::duration
135 <int, detail::ratio_multiply<std::ratio<7>, days::period>>;
136
137using years = std::chrono::duration
138 <int, detail::ratio_multiply<std::ratio<146097, 400>, days::period>>;
139
140using months = std::chrono::duration
141 <int, detail::ratio_divide<years::period, std::ratio<12>>>;
142
143// time_point
144
145template <class Duration>
146 using sys_time = std::chrono::time_point<std::chrono::system_clock, Duration>;
147
150
151struct local_t {};
152
153template <class Duration>
154 using local_time = std::chrono::time_point<local_t, Duration>;
155
158
159// types
160
161struct last_spec
162{
163 explicit last_spec() = default;
164};
165
166class day;
167class month;
168class year;
169
170class weekday;
171class weekday_indexed;
172class weekday_last;
173
174class month_day;
175class month_day_last;
176class month_weekday;
178
179class year_month;
180
181class year_month_day;
185
186// date composition operators
187
188constexpr year_month operator/(const year& y, const month& m) noexcept;
189constexpr year_month operator/(const year& y, int m) noexcept;
190
191constexpr month_day operator/(const day& d, const month& m) noexcept;
192constexpr month_day operator/(const day& d, int m) noexcept;
193constexpr month_day operator/(const month& m, const day& d) noexcept;
194constexpr month_day operator/(const month& m, int d) noexcept;
195constexpr month_day operator/(int m, const day& d) noexcept;
196
197constexpr month_day_last operator/(const month& m, last_spec) noexcept;
198constexpr month_day_last operator/(int m, last_spec) noexcept;
199constexpr month_day_last operator/(last_spec, const month& m) noexcept;
200constexpr month_day_last operator/(last_spec, int m) noexcept;
201
202constexpr month_weekday operator/(const month& m, const weekday_indexed& wdi) noexcept;
203constexpr month_weekday operator/(int m, const weekday_indexed& wdi) noexcept;
204constexpr month_weekday operator/(const weekday_indexed& wdi, const month& m) noexcept;
205constexpr month_weekday operator/(const weekday_indexed& wdi, int m) noexcept;
206
207constexpr month_weekday_last operator/(const month& m, const weekday_last& wdl) noexcept;
208constexpr month_weekday_last operator/(int m, const weekday_last& wdl) noexcept;
209constexpr month_weekday_last operator/(const weekday_last& wdl, const month& m) noexcept;
210constexpr month_weekday_last operator/(const weekday_last& wdl, int m) noexcept;
211
212constexpr year_month_day operator/(const year_month& ym, const day& d) noexcept;
213constexpr year_month_day operator/(const year_month& ym, int d) noexcept;
214constexpr year_month_day operator/(const year& y, const month_day& md) noexcept;
215constexpr year_month_day operator/(int y, const month_day& md) noexcept;
216constexpr year_month_day operator/(const month_day& md, const year& y) noexcept;
217constexpr year_month_day operator/(const month_day& md, int y) noexcept;
218
219constexpr
221constexpr
222 year_month_day_last operator/(const year& y, const month_day_last& mdl) noexcept;
223constexpr
224 year_month_day_last operator/(int y, const month_day_last& mdl) noexcept;
225constexpr
226 year_month_day_last operator/(const month_day_last& mdl, const year& y) noexcept;
227constexpr
228 year_month_day_last operator/(const month_day_last& mdl, int y) noexcept;
229
230constexpr year_month_weekday
231operator/(const year_month& ym, const weekday_indexed& wdi) noexcept;
232
233constexpr year_month_weekday
234operator/(const year& y, const month_weekday& mwd) noexcept;
235
236constexpr year_month_weekday
237operator/(int y, const month_weekday& mwd) noexcept;
238
239constexpr year_month_weekday
240operator/(const month_weekday& mwd, const year& y) noexcept;
241
242constexpr year_month_weekday
243operator/(const month_weekday& mwd, int y) noexcept;
244
246operator/(const year_month& ym, const weekday_last& wdl) noexcept;
247
249operator/(const year& y, const month_weekday_last& mwdl) noexcept;
250
252operator/(int y, const month_weekday_last& mwdl) noexcept;
253
255operator/(const month_weekday_last& mwdl, const year& y) noexcept;
256
258operator/(const month_weekday_last& mwdl, int y) noexcept;
259
260// Detailed interface
261
262// day
263
264class day
265{
266 unsigned char d_;
267
268public:
269 day() = default;
270 explicit constexpr day(unsigned d) noexcept;
271
272 constexpr day& operator++() noexcept;
273 constexpr day operator++(int) noexcept;
274 constexpr day& operator--() noexcept;
275 constexpr day operator--(int) noexcept;
276
277 constexpr day& operator+=(const days& d) noexcept;
278 constexpr day& operator-=(const days& d) noexcept;
279
280 constexpr explicit operator unsigned() const noexcept;
281 constexpr bool ok() const noexcept;
282};
283
284constexpr bool operator==(const day& x, const day& y) noexcept;
285constexpr bool operator!=(const day& x, const day& y) noexcept;
286constexpr bool operator< (const day& x, const day& y) noexcept;
287constexpr bool operator> (const day& x, const day& y) noexcept;
288constexpr bool operator<=(const day& x, const day& y) noexcept;
289constexpr bool operator>=(const day& x, const day& y) noexcept;
290
291constexpr day operator+(const day& x, const days& y) noexcept;
292constexpr day operator+(const days& x, const day& y) noexcept;
293constexpr day operator-(const day& x, const days& y) noexcept;
294constexpr days operator-(const day& x, const day& y) noexcept;
295
296template<class CharT, class Traits>
297std::basic_ostream<CharT, Traits>&
298operator<<(std::basic_ostream<CharT, Traits>& os, const day& d);
299
300// month
301
302class month
303{
304 unsigned char m_;
305
306public:
307 month() = default;
308 explicit constexpr month(unsigned m) noexcept;
309
310 constexpr month& operator++() noexcept;
311 constexpr month operator++(int) noexcept;
312 constexpr month& operator--() noexcept;
313 constexpr month operator--(int) noexcept;
314
315 constexpr month& operator+=(const months& m) noexcept;
316 constexpr month& operator-=(const months& m) noexcept;
317
318 constexpr explicit operator unsigned() const noexcept;
319 constexpr bool ok() const noexcept;
320};
321
322constexpr bool operator==(const month& x, const month& y) noexcept;
323constexpr bool operator!=(const month& x, const month& y) noexcept;
324constexpr bool operator< (const month& x, const month& y) noexcept;
325constexpr bool operator> (const month& x, const month& y) noexcept;
326constexpr bool operator<=(const month& x, const month& y) noexcept;
327constexpr bool operator>=(const month& x, const month& y) noexcept;
328
329constexpr month operator+(const month& x, const months& y) noexcept;
330constexpr month operator+(const months& x, const month& y) noexcept;
331constexpr month operator-(const month& x, const months& y) noexcept;
332constexpr months operator-(const month& x, const month& y) noexcept;
333
334template<class CharT, class Traits>
335std::basic_ostream<CharT, Traits>&
336operator<<(std::basic_ostream<CharT, Traits>& os, const month& m);
337
338// year
339
340class year
341{
342 short y_;
343
344public:
345 year() = default;
346 explicit constexpr year(int y) noexcept;
347
348 constexpr year& operator++() noexcept;
349 constexpr year operator++(int) noexcept;
350 constexpr year& operator--() noexcept;
351 constexpr year operator--(int) noexcept;
352
353 constexpr year& operator+=(const years& y) noexcept;
354 constexpr year& operator-=(const years& y) noexcept;
355
356 constexpr year operator-() const noexcept;
357 constexpr year operator+() const noexcept;
358
359 constexpr bool is_leap() const noexcept;
360
361 constexpr explicit operator int() const noexcept;
362 constexpr bool ok() const noexcept;
363
364 static constexpr year min() noexcept { return year{-32767}; }
365 static constexpr year max() noexcept { return year{32767}; }
366};
367
368constexpr bool operator==(const year& x, const year& y) noexcept;
369constexpr bool operator!=(const year& x, const year& y) noexcept;
370constexpr bool operator< (const year& x, const year& y) noexcept;
371constexpr bool operator> (const year& x, const year& y) noexcept;
372constexpr bool operator<=(const year& x, const year& y) noexcept;
373constexpr bool operator>=(const year& x, const year& y) noexcept;
374
375constexpr year operator+(const year& x, const years& y) noexcept;
376constexpr year operator+(const years& x, const year& y) noexcept;
377constexpr year operator-(const year& x, const years& y) noexcept;
378constexpr years operator-(const year& x, const year& y) noexcept;
379
380template<class CharT, class Traits>
381std::basic_ostream<CharT, Traits>&
382operator<<(std::basic_ostream<CharT, Traits>& os, const year& y);
383
384// weekday
385
386class weekday
387{
388 unsigned char wd_;
389public:
390 weekday() = default;
391 explicit constexpr weekday(unsigned wd) noexcept;
392 constexpr weekday(const sys_days& dp) noexcept;
393 constexpr explicit weekday(const local_days& dp) noexcept;
394
395 constexpr weekday& operator++() noexcept;
396 constexpr weekday operator++(int) noexcept;
397 constexpr weekday& operator--() noexcept;
398 constexpr weekday operator--(int) noexcept;
399
400 constexpr weekday& operator+=(const days& d) noexcept;
401 constexpr weekday& operator-=(const days& d) noexcept;
402
403 constexpr bool ok() const noexcept;
404
405 constexpr unsigned c_encoding() const noexcept;
406 constexpr unsigned iso_encoding() const noexcept;
407
408 constexpr weekday_indexed operator[](unsigned index) const noexcept;
409 constexpr weekday_last operator[](last_spec) const noexcept;
410
411private:
412 static constexpr unsigned char weekday_from_days(int z) noexcept;
413
414 friend constexpr bool operator==(const weekday& x, const weekday& y) noexcept;
415 friend constexpr days operator-(const weekday& x, const weekday& y) noexcept;
416 friend constexpr weekday operator+(const weekday& x, const days& y) noexcept;
417 template<class CharT, class Traits>
418 friend std::basic_ostream<CharT, Traits>&
419 operator<<(std::basic_ostream<CharT, Traits>& os, const weekday& wd);
420 friend class weekday_indexed;
421};
422
423constexpr bool operator==(const weekday& x, const weekday& y) noexcept;
424constexpr bool operator!=(const weekday& x, const weekday& y) noexcept;
425
426constexpr weekday operator+(const weekday& x, const days& y) noexcept;
427constexpr weekday operator+(const days& x, const weekday& y) noexcept;
428constexpr weekday operator-(const weekday& x, const days& y) noexcept;
429constexpr days operator-(const weekday& x, const weekday& y) noexcept;
430
431template<class CharT, class Traits>
432std::basic_ostream<CharT, Traits>&
433operator<<(std::basic_ostream<CharT, Traits>& os, const weekday& wd);
434
435// weekday_indexed
436
437class weekday_indexed
438{
439 unsigned char wd_ : 4;
440 unsigned char index_ : 4;
441
442public:
443 weekday_indexed() = default;
444 constexpr weekday_indexed(const gul17::date::weekday& wd, unsigned index) noexcept;
445
446 constexpr gul17::date::weekday weekday() const noexcept;
447 constexpr unsigned index() const noexcept;
448 constexpr bool ok() const noexcept;
449};
450
451constexpr bool operator==(const weekday_indexed& x, const weekday_indexed& y) noexcept;
452constexpr bool operator!=(const weekday_indexed& x, const weekday_indexed& y) noexcept;
453
454template<class CharT, class Traits>
455std::basic_ostream<CharT, Traits>&
456operator<<(std::basic_ostream<CharT, Traits>& os, const weekday_indexed& wdi);
457
458// weekday_last
459
460class weekday_last
461{
462 gul17::date::weekday wd_;
463
464public:
465 explicit constexpr weekday_last(const gul17::date::weekday& wd) noexcept;
466
467 constexpr gul17::date::weekday weekday() const noexcept;
468 constexpr bool ok() const noexcept;
469};
470
471constexpr bool operator==(const weekday_last& x, const weekday_last& y) noexcept;
472constexpr bool operator!=(const weekday_last& x, const weekday_last& y) noexcept;
473
474template<class CharT, class Traits>
475std::basic_ostream<CharT, Traits>&
476operator<<(std::basic_ostream<CharT, Traits>& os, const weekday_last& wdl);
477
478namespace detail
479{
480
481struct unspecified_month_disambiguator {};
482
483} // namespace detail
484
485// year_month
486
487class year_month
488{
489 gul17::date::year y_;
490 gul17::date::month m_;
491
492public:
493 year_month() = default;
494 constexpr year_month(const gul17::date::year& y, const gul17::date::month& m) noexcept;
495
496 constexpr gul17::date::year year() const noexcept;
497 constexpr gul17::date::month month() const noexcept;
498
499 template<class = detail::unspecified_month_disambiguator>
500 constexpr year_month& operator+=(const months& dm) noexcept;
501 template<class = detail::unspecified_month_disambiguator>
502 constexpr year_month& operator-=(const months& dm) noexcept;
503 constexpr year_month& operator+=(const years& dy) noexcept;
504 constexpr year_month& operator-=(const years& dy) noexcept;
505
506 constexpr bool ok() const noexcept;
507};
508
509constexpr bool operator==(const year_month& x, const year_month& y) noexcept;
510constexpr bool operator!=(const year_month& x, const year_month& y) noexcept;
511constexpr bool operator< (const year_month& x, const year_month& y) noexcept;
512constexpr bool operator> (const year_month& x, const year_month& y) noexcept;
513constexpr bool operator<=(const year_month& x, const year_month& y) noexcept;
514constexpr bool operator>=(const year_month& x, const year_month& y) noexcept;
515
516template<class = detail::unspecified_month_disambiguator>
517constexpr year_month operator+(const year_month& ym, const months& dm) noexcept;
518template<class = detail::unspecified_month_disambiguator>
519constexpr year_month operator+(const months& dm, const year_month& ym) noexcept;
520template<class = detail::unspecified_month_disambiguator>
521constexpr year_month operator-(const year_month& ym, const months& dm) noexcept;
522
523constexpr months operator-(const year_month& x, const year_month& y) noexcept;
524constexpr year_month operator+(const year_month& ym, const years& dy) noexcept;
525constexpr year_month operator+(const years& dy, const year_month& ym) noexcept;
526constexpr year_month operator-(const year_month& ym, const years& dy) noexcept;
527
528template<class CharT, class Traits>
529std::basic_ostream<CharT, Traits>&
530operator<<(std::basic_ostream<CharT, Traits>& os, const year_month& ym);
531
532// month_day
533
534class month_day
535{
536 gul17::date::month m_;
537 gul17::date::day d_;
538
539public:
540 month_day() = default;
541 constexpr month_day(const gul17::date::month& m, const gul17::date::day& d) noexcept;
542
543 constexpr gul17::date::month month() const noexcept;
544 constexpr gul17::date::day day() const noexcept;
545
546 constexpr bool ok() const noexcept;
547};
548
549constexpr bool operator==(const month_day& x, const month_day& y) noexcept;
550constexpr bool operator!=(const month_day& x, const month_day& y) noexcept;
551constexpr bool operator< (const month_day& x, const month_day& y) noexcept;
552constexpr bool operator> (const month_day& x, const month_day& y) noexcept;
553constexpr bool operator<=(const month_day& x, const month_day& y) noexcept;
554constexpr bool operator>=(const month_day& x, const month_day& y) noexcept;
555
556template<class CharT, class Traits>
557std::basic_ostream<CharT, Traits>&
558operator<<(std::basic_ostream<CharT, Traits>& os, const month_day& md);
559
560// month_day_last
561
562class month_day_last
563{
564 gul17::date::month m_;
565
566public:
567 constexpr explicit month_day_last(const gul17::date::month& m) noexcept;
568
569 constexpr gul17::date::month month() const noexcept;
570 constexpr bool ok() const noexcept;
571};
572
573constexpr bool operator==(const month_day_last& x, const month_day_last& y) noexcept;
574constexpr bool operator!=(const month_day_last& x, const month_day_last& y) noexcept;
575constexpr bool operator< (const month_day_last& x, const month_day_last& y) noexcept;
576constexpr bool operator> (const month_day_last& x, const month_day_last& y) noexcept;
577constexpr bool operator<=(const month_day_last& x, const month_day_last& y) noexcept;
578constexpr bool operator>=(const month_day_last& x, const month_day_last& y) noexcept;
579
580template<class CharT, class Traits>
581std::basic_ostream<CharT, Traits>&
582operator<<(std::basic_ostream<CharT, Traits>& os, const month_day_last& mdl);
583
584// month_weekday
585
586class month_weekday
587{
588 gul17::date::month m_;
589 gul17::date::weekday_indexed wdi_;
590public:
591 constexpr month_weekday(const gul17::date::month& m,
592 const gul17::date::weekday_indexed& wdi) noexcept;
593
594 constexpr gul17::date::month month() const noexcept;
595 constexpr gul17::date::weekday_indexed weekday_indexed() const noexcept;
596
597 constexpr bool ok() const noexcept;
598};
599
600constexpr bool operator==(const month_weekday& x, const month_weekday& y) noexcept;
601constexpr bool operator!=(const month_weekday& x, const month_weekday& y) noexcept;
602
603template<class CharT, class Traits>
604std::basic_ostream<CharT, Traits>&
605operator<<(std::basic_ostream<CharT, Traits>& os, const month_weekday& mwd);
606
607// month_weekday_last
608
609class month_weekday_last
610{
611 gul17::date::month m_;
612 gul17::date::weekday_last wdl_;
613
614public:
615 constexpr month_weekday_last(const gul17::date::month& m,
616 const gul17::date::weekday_last& wd) noexcept;
617
618 constexpr gul17::date::month month() const noexcept;
619 constexpr gul17::date::weekday_last weekday_last() const noexcept;
620
621 constexpr bool ok() const noexcept;
622};
623
624constexpr
625 bool operator==(const month_weekday_last& x, const month_weekday_last& y) noexcept;
626constexpr
627 bool operator!=(const month_weekday_last& x, const month_weekday_last& y) noexcept;
628
629template<class CharT, class Traits>
630std::basic_ostream<CharT, Traits>&
631operator<<(std::basic_ostream<CharT, Traits>& os, const month_weekday_last& mwdl);
632
633// class year_month_day
634
635class year_month_day
636{
637 gul17::date::year y_;
638 gul17::date::month m_;
639 gul17::date::day d_;
640
641public:
642 year_month_day() = default;
643 constexpr year_month_day(const gul17::date::year& y, const gul17::date::month& m,
644 const gul17::date::day& d) noexcept;
645 constexpr year_month_day(const year_month_day_last& ymdl) noexcept;
646
647 constexpr year_month_day(sys_days dp) noexcept;
648 constexpr explicit year_month_day(local_days dp) noexcept;
649
650 template<class = detail::unspecified_month_disambiguator>
651 constexpr year_month_day& operator+=(const months& m) noexcept;
652 template<class = detail::unspecified_month_disambiguator>
653 constexpr year_month_day& operator-=(const months& m) noexcept;
654 constexpr year_month_day& operator+=(const years& y) noexcept;
655 constexpr year_month_day& operator-=(const years& y) noexcept;
656
657 constexpr gul17::date::year year() const noexcept;
658 constexpr gul17::date::month month() const noexcept;
659 constexpr gul17::date::day day() const noexcept;
660
661 constexpr operator sys_days() const noexcept;
662 constexpr explicit operator local_days() const noexcept;
663 constexpr bool ok() const noexcept;
664
665private:
666 static constexpr year_month_day from_days(days dp) noexcept;
667 constexpr days to_days() const noexcept;
668};
669
670constexpr bool operator==(const year_month_day& x, const year_month_day& y) noexcept;
671constexpr bool operator!=(const year_month_day& x, const year_month_day& y) noexcept;
672constexpr bool operator< (const year_month_day& x, const year_month_day& y) noexcept;
673constexpr bool operator> (const year_month_day& x, const year_month_day& y) noexcept;
674constexpr bool operator<=(const year_month_day& x, const year_month_day& y) noexcept;
675constexpr bool operator>=(const year_month_day& x, const year_month_day& y) noexcept;
676
677template<class = detail::unspecified_month_disambiguator>
678constexpr year_month_day operator+(const year_month_day& ymd, const months& dm) noexcept;
679template<class = detail::unspecified_month_disambiguator>
680constexpr year_month_day operator+(const months& dm, const year_month_day& ymd) noexcept;
681template<class = detail::unspecified_month_disambiguator>
682constexpr year_month_day operator-(const year_month_day& ymd, const months& dm) noexcept;
683constexpr year_month_day operator+(const year_month_day& ymd, const years& dy) noexcept;
684constexpr year_month_day operator+(const years& dy, const year_month_day& ymd) noexcept;
685constexpr year_month_day operator-(const year_month_day& ymd, const years& dy) noexcept;
686
687template<class CharT, class Traits>
688std::basic_ostream<CharT, Traits>&
689operator<<(std::basic_ostream<CharT, Traits>& os, const year_month_day& ymd);
690
691// year_month_day_last
692
693class year_month_day_last
694{
695 gul17::date::year y_;
696 gul17::date::month_day_last mdl_;
697
698public:
699 constexpr year_month_day_last(const gul17::date::year& y,
700 const gul17::date::month_day_last& mdl) noexcept;
701
702 template<class = detail::unspecified_month_disambiguator>
703 constexpr year_month_day_last& operator+=(const months& m) noexcept;
704 template<class = detail::unspecified_month_disambiguator>
705 constexpr year_month_day_last& operator-=(const months& m) noexcept;
706 constexpr year_month_day_last& operator+=(const years& y) noexcept;
707 constexpr year_month_day_last& operator-=(const years& y) noexcept;
708
709 constexpr gul17::date::year year() const noexcept;
710 constexpr gul17::date::month month() const noexcept;
711 constexpr gul17::date::month_day_last month_day_last() const noexcept;
712 constexpr gul17::date::day day() const noexcept;
713
714 constexpr operator sys_days() const noexcept;
715 constexpr explicit operator local_days() const noexcept;
716 constexpr bool ok() const noexcept;
717};
718
719constexpr
720 bool operator==(const year_month_day_last& x, const year_month_day_last& y) noexcept;
721constexpr
722 bool operator!=(const year_month_day_last& x, const year_month_day_last& y) noexcept;
723constexpr
724 bool operator< (const year_month_day_last& x, const year_month_day_last& y) noexcept;
725constexpr
726 bool operator> (const year_month_day_last& x, const year_month_day_last& y) noexcept;
727constexpr
728 bool operator<=(const year_month_day_last& x, const year_month_day_last& y) noexcept;
729constexpr
730 bool operator>=(const year_month_day_last& x, const year_month_day_last& y) noexcept;
731
732template<class = detail::unspecified_month_disambiguator>
733constexpr
734year_month_day_last
735operator+(const year_month_day_last& ymdl, const months& dm) noexcept;
736
737template<class = detail::unspecified_month_disambiguator>
738constexpr
739year_month_day_last
740operator+(const months& dm, const year_month_day_last& ymdl) noexcept;
741
742constexpr
743year_month_day_last
744operator+(const year_month_day_last& ymdl, const years& dy) noexcept;
745
746constexpr
747year_month_day_last
748operator+(const years& dy, const year_month_day_last& ymdl) noexcept;
749
750template<class = detail::unspecified_month_disambiguator>
751constexpr
752year_month_day_last
753operator-(const year_month_day_last& ymdl, const months& dm) noexcept;
754
755constexpr
756year_month_day_last
757operator-(const year_month_day_last& ymdl, const years& dy) noexcept;
758
759template<class CharT, class Traits>
760std::basic_ostream<CharT, Traits>&
761operator<<(std::basic_ostream<CharT, Traits>& os, const year_month_day_last& ymdl);
762
763// year_month_weekday
764
765class year_month_weekday
766{
767 gul17::date::year y_;
768 gul17::date::month m_;
769 gul17::date::weekday_indexed wdi_;
770
771public:
772 year_month_weekday() = default;
773 constexpr year_month_weekday(const gul17::date::year& y, const gul17::date::month& m,
774 const gul17::date::weekday_indexed& wdi) noexcept;
775 constexpr year_month_weekday(const sys_days& dp) noexcept;
776 constexpr explicit year_month_weekday(const local_days& dp) noexcept;
777
778 template<class = detail::unspecified_month_disambiguator>
779 constexpr year_month_weekday& operator+=(const months& m) noexcept;
780 template<class = detail::unspecified_month_disambiguator>
781 constexpr year_month_weekday& operator-=(const months& m) noexcept;
782 constexpr year_month_weekday& operator+=(const years& y) noexcept;
783 constexpr year_month_weekday& operator-=(const years& y) noexcept;
784
785 constexpr gul17::date::year year() const noexcept;
786 constexpr gul17::date::month month() const noexcept;
787 constexpr gul17::date::weekday weekday() const noexcept;
788 constexpr unsigned index() const noexcept;
789 constexpr gul17::date::weekday_indexed weekday_indexed() const noexcept;
790
791 constexpr operator sys_days() const noexcept;
792 constexpr explicit operator local_days() const noexcept;
793 constexpr bool ok() const noexcept;
794
795private:
796 static constexpr year_month_weekday from_days(days dp) noexcept;
797 constexpr days to_days() const noexcept;
798};
799
800constexpr
801 bool operator==(const year_month_weekday& x, const year_month_weekday& y) noexcept;
802constexpr
803 bool operator!=(const year_month_weekday& x, const year_month_weekday& y) noexcept;
804
805template<class = detail::unspecified_month_disambiguator>
806constexpr
807year_month_weekday
808operator+(const year_month_weekday& ymwd, const months& dm) noexcept;
809
810template<class = detail::unspecified_month_disambiguator>
811constexpr
812year_month_weekday
813operator+(const months& dm, const year_month_weekday& ymwd) noexcept;
814
815constexpr
816year_month_weekday
817operator+(const year_month_weekday& ymwd, const years& dy) noexcept;
818
819constexpr
820year_month_weekday
821operator+(const years& dy, const year_month_weekday& ymwd) noexcept;
822
823template<class = detail::unspecified_month_disambiguator>
824constexpr
825year_month_weekday
826operator-(const year_month_weekday& ymwd, const months& dm) noexcept;
827
828constexpr
829year_month_weekday
830operator-(const year_month_weekday& ymwd, const years& dy) noexcept;
831
832template<class CharT, class Traits>
833std::basic_ostream<CharT, Traits>&
834operator<<(std::basic_ostream<CharT, Traits>& os, const year_month_weekday& ymwdi);
835
836// year_month_weekday_last
837
838class year_month_weekday_last
839{
840 gul17::date::year y_;
841 gul17::date::month m_;
842 gul17::date::weekday_last wdl_;
843
844public:
845 constexpr year_month_weekday_last(const gul17::date::year& y, const gul17::date::month& m,
846 const gul17::date::weekday_last& wdl) noexcept;
847
848 template<class = detail::unspecified_month_disambiguator>
849 constexpr year_month_weekday_last& operator+=(const months& m) noexcept;
850 template<class = detail::unspecified_month_disambiguator>
851 constexpr year_month_weekday_last& operator-=(const months& m) noexcept;
852 constexpr year_month_weekday_last& operator+=(const years& y) noexcept;
853 constexpr year_month_weekday_last& operator-=(const years& y) noexcept;
854
855 constexpr gul17::date::year year() const noexcept;
856 constexpr gul17::date::month month() const noexcept;
857 constexpr gul17::date::weekday weekday() const noexcept;
858 constexpr gul17::date::weekday_last weekday_last() const noexcept;
859
860 constexpr operator sys_days() const noexcept;
861 constexpr explicit operator local_days() const noexcept;
862 constexpr bool ok() const noexcept;
863
864private:
865 constexpr days to_days() const noexcept;
866};
867
868constexpr
869bool
870operator==(const year_month_weekday_last& x, const year_month_weekday_last& y) noexcept;
871
872constexpr
873bool
874operator!=(const year_month_weekday_last& x, const year_month_weekday_last& y) noexcept;
875
876template<class = detail::unspecified_month_disambiguator>
877constexpr
878year_month_weekday_last
879operator+(const year_month_weekday_last& ymwdl, const months& dm) noexcept;
880
881template<class = detail::unspecified_month_disambiguator>
882constexpr
883year_month_weekday_last
884operator+(const months& dm, const year_month_weekday_last& ymwdl) noexcept;
885
886constexpr
887year_month_weekday_last
888operator+(const year_month_weekday_last& ymwdl, const years& dy) noexcept;
889
890constexpr
891year_month_weekday_last
892operator+(const years& dy, const year_month_weekday_last& ymwdl) noexcept;
893
894template<class = detail::unspecified_month_disambiguator>
895constexpr
896year_month_weekday_last
897operator-(const year_month_weekday_last& ymwdl, const months& dm) noexcept;
898
899constexpr
900year_month_weekday_last
901operator-(const year_month_weekday_last& ymwdl, const years& dy) noexcept;
902
903template<class CharT, class Traits>
904std::basic_ostream<CharT, Traits>&
905operator<<(std::basic_ostream<CharT, Traits>& os, const year_month_weekday_last& ymwdl);
906
907#if !defined(_MSC_VER) || (_MSC_VER >= 1900)
908inline namespace literals
909{
910
911constexpr gul17::date::day operator "" _d(unsigned long long d) noexcept;
912constexpr gul17::date::year operator "" _y(unsigned long long y) noexcept;
913
914} // inline namespace literals
915#endif // !defined(_MSC_VER) || (_MSC_VER >= 1900)
916
917// constexpr const gul17::date::month January{1};
918// constexpr const gul17::date::month February{2};
919// constexpr const gul17::date::month March{3};
920// constexpr const gul17::date::month April{4};
921// constexpr const gul17::date::month May{5};
922// constexpr const gul17::date::month June{6};
923// constexpr const gul17::date::month July{7};
924// constexpr const gul17::date::month August{8};
925// constexpr const gul17::date::month September{9};
926// constexpr const gul17::date::month October{10};
927// constexpr const gul17::date::month November{11};
928// constexpr const gul17::date::month December{12};
929//
930// constexpr const gul17::date::weekday Sunday{0u};
931// constexpr const gul17::date::weekday Monday{1u};
932// constexpr const gul17::date::weekday Tuesday{2u};
933// constexpr const gul17::date::weekday Wednesday{3u};
934// constexpr const gul17::date::weekday Thursday{4u};
935// constexpr const gul17::date::weekday Friday{5u};
936// constexpr const gul17::date::weekday Saturday{6u};
937
938#if HAS_VOID_T
939
940template <class T, class = std::void_t<>>
941struct is_clock
942 : std::false_type
943{};
944
945template <class T>
946struct is_clock<T, std::void_t<decltype(T::now()), typename T::rep, typename T::period,
947 typename T::duration, typename T::time_point,
948 decltype(T::is_steady)>>
949 : std::true_type
950{};
951
952template<class T> inline constexpr bool is_clock_v = is_clock<T>::value;
953
954#endif // HAS_VOID_T
955
956//----------------+
957// Implementation |
958//----------------+
959
960// utilities
961namespace detail {
962
963template<class CharT, class Traits = std::char_traits<CharT>>
964class save_istream
965{
966protected:
967 std::basic_ios<CharT, Traits>& is_;
968 CharT fill_;
969 std::ios::fmtflags flags_;
970 std::streamsize precision_;
971 std::streamsize width_;
972 std::basic_ostream<CharT, Traits>* tie_;
973 std::locale loc_;
974
975public:
976 ~save_istream()
977 {
978 is_.fill(fill_);
979 is_.flags(flags_);
980 is_.precision(precision_);
981 is_.width(width_);
982 is_.imbue(loc_);
983 is_.tie(tie_);
984 }
985
986 save_istream(const save_istream&) = delete;
987 save_istream& operator=(const save_istream&) = delete;
988
989 explicit save_istream(std::basic_ios<CharT, Traits>& is)
990 : is_(is)
991 , fill_(is.fill())
992 , flags_(is.flags())
993 , precision_(is.precision())
994 , width_(is.width(0))
995 , tie_(is.tie(nullptr))
996 , loc_(is.getloc())
997 {
998 if (tie_ != nullptr)
999 tie_->flush();
1000 }
1001};
1002
1003template<class CharT, class Traits = std::char_traits<CharT>>
1004class save_ostream
1005 : private save_istream<CharT, Traits>
1006{
1007public:
1008 ~save_ostream()
1009 {
1010 if ((this->flags_ & std::ios::unitbuf) &&
1011#if HAS_UNCAUGHT_EXCEPTIONS
1012 std::uncaught_exceptions() == 0 &&
1013#else
1014 !std::uncaught_exception() &&
1015#endif
1016 this->is_.good())
1017 this->is_.rdbuf()->pubsync();
1018 }
1019
1020 save_ostream(const save_ostream&) = delete;
1021 save_ostream& operator=(const save_ostream&) = delete;
1022
1023 explicit save_ostream(std::basic_ios<CharT, Traits>& os)
1024 : save_istream<CharT, Traits>(os)
1025 {
1026 }
1027};
1028
1029template <class T>
1030struct choose_trunc_type
1031{
1032 static const int digits = std::numeric_limits<T>::digits;
1033 using type = typename std::conditional
1034 <
1035 digits < 32,
1036 std::int32_t,
1037 typename std::conditional
1038 <
1039 digits < 64,
1040 std::int64_t,
1041#ifdef __SIZEOF_INT128__
1042 __int128
1043#else
1044 std::int64_t
1045#endif
1046 >::type
1047 >::type;
1048};
1049
1050template <class T>
1051constexpr inline
1052typename std::enable_if
1053<
1054 !std::chrono::treat_as_floating_point<T>::value,
1055 T
1056>::type
1057trunc(T t) noexcept
1058{
1059 return t;
1060}
1061
1062template <class T>
1063constexpr inline
1064typename std::enable_if
1065<
1066 std::chrono::treat_as_floating_point<T>::value,
1067 T
1068>::type
1069trunc(T t) noexcept
1070{
1071 using std::numeric_limits;
1072 using I = typename choose_trunc_type<T>::type;
1073 constexpr const auto digits = numeric_limits<T>::digits;
1074 static_assert(digits < numeric_limits<I>::digits, "");
1075 constexpr const auto max = I{1} << (digits-1);
1076 constexpr const auto min = -max;
1077 const auto negative = t < T{0};
1078 if (min <= t && t <= max && t != 0 && t == t)
1079 {
1080 t = static_cast<T>(static_cast<I>(t));
1081 if (t == 0 && negative)
1082 t = -t;
1083 }
1084 return t;
1085}
1086
1087template <std::intmax_t Xp, std::intmax_t Yp>
1088struct static_gcd
1089{
1090 static const std::intmax_t value = static_gcd<Yp, Xp % Yp>::value;
1091};
1092
1093template <std::intmax_t Xp>
1094struct static_gcd<Xp, 0>
1095{
1096 static const std::intmax_t value = Xp;
1097};
1098
1099template <>
1100struct static_gcd<0, 0>
1101{
1102 static const std::intmax_t value = 1;
1103};
1104
1105template <class R1, class R2>
1106struct no_overflow
1107{
1108private:
1109 static const std::intmax_t gcd_n1_n2 = static_gcd<R1::num, R2::num>::value;
1110 static const std::intmax_t gcd_d1_d2 = static_gcd<R1::den, R2::den>::value;
1111 static const std::intmax_t n1 = R1::num / gcd_n1_n2;
1112 static const std::intmax_t d1 = R1::den / gcd_d1_d2;
1113 static const std::intmax_t n2 = R2::num / gcd_n1_n2;
1114 static const std::intmax_t d2 = R2::den / gcd_d1_d2;
1115#ifdef __cpp_constexpr
1116 static const std::intmax_t max = std::numeric_limits<std::intmax_t>::max();
1117#else
1118 static const std::intmax_t max = LLONG_MAX;
1119#endif
1120
1121 template <std::intmax_t Xp, std::intmax_t Yp, bool overflow>
1122 struct mul // overflow == false
1123 {
1124 static const std::intmax_t value = Xp * Yp;
1125 };
1126
1127 template <std::intmax_t Xp, std::intmax_t Yp>
1128 struct mul<Xp, Yp, true>
1129 {
1130 static const std::intmax_t value = 1;
1131 };
1132
1133public:
1134 static const bool value = (n1 <= max / d2) && (n2 <= max / d1);
1135 typedef std::ratio<mul<n1, d2, !value>::value,
1136 mul<n2, d1, !value>::value> type;
1137};
1138
1139} // detail
1140
1141// trunc towards zero
1142template <class To, class Rep, class Period>
1143constexpr inline
1144typename std::enable_if
1145<
1146 detail::no_overflow<Period, typename To::period>::value,
1147 To
1148>::type
1149trunc(const std::chrono::duration<Rep, Period>& d)
1150{
1151 return To{detail::trunc(std::chrono::duration_cast<To>(d).count())};
1152}
1153
1154template <class To, class Rep, class Period>
1155constexpr inline
1156typename std::enable_if
1157<
1158 !detail::no_overflow<Period, typename To::period>::value,
1159 To
1160>::type
1161trunc(const std::chrono::duration<Rep, Period>& d)
1162{
1163 using std::chrono::duration_cast;
1164 using std::chrono::duration;
1165 using rep = typename std::common_type<Rep, typename To::rep>::type;
1166 return To{detail::trunc(duration_cast<To>(duration_cast<duration<rep>>(d)).count())};
1167}
1168
1169#ifndef HAS_CHRONO_ROUNDING
1170# if defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 190023918 || (_MSC_FULL_VER >= 190000000 && defined (__clang__)))
1171# define HAS_CHRONO_ROUNDING 1
1172# elif defined(__cpp_lib_chrono) && __cplusplus > 201402 && __cpp_lib_chrono >= 201510
1173# define HAS_CHRONO_ROUNDING 1
1174# elif defined(_LIBCPP_VERSION) && __cplusplus > 201402 && _LIBCPP_VERSION >= 3800
1175# define HAS_CHRONO_ROUNDING 1
1176# else
1177# define HAS_CHRONO_ROUNDING 0
1178# endif
1179#endif // HAS_CHRONO_ROUNDING
1180
1181#if HAS_CHRONO_ROUNDING == 0
1182
1183// round down
1184template <class To, class Rep, class Period>
1185constexpr inline
1186typename std::enable_if
1187<
1188 detail::no_overflow<Period, typename To::period>::value,
1189 To
1190>::type
1191floor(const std::chrono::duration<Rep, Period>& d)
1192{
1193 auto t = trunc<To>(d);
1194 if (t > d)
1195 return t - To{1};
1196 return t;
1197}
1198
1199template <class To, class Rep, class Period>
1200constexpr inline
1201typename std::enable_if
1202<
1203 !detail::no_overflow<Period, typename To::period>::value,
1204 To
1205>::type
1206floor(const std::chrono::duration<Rep, Period>& d)
1207{
1208 using rep = typename std::common_type<Rep, typename To::rep>::type;
1209 return floor<To>(floor<std::chrono::duration<rep>>(d));
1210}
1211
1212// round to nearest, to even on tie
1213template <class To, class Rep, class Period>
1214constexpr inline
1215To
1216round(const std::chrono::duration<Rep, Period>& d)
1217{
1218 auto t0 = floor<To>(d);
1219 auto t1 = t0 + To{1};
1220 if (t1 == To{0} && t0 < To{0})
1221 t1 = -t1;
1222 auto diff0 = d - t0;
1223 auto diff1 = t1 - d;
1224 if (diff0 == diff1)
1225 {
1226 if (t0 - trunc<To>(t0/2)*2 == To{0})
1227 return t0;
1228 return t1;
1229 }
1230 if (diff0 < diff1)
1231 return t0;
1232 return t1;
1233}
1234
1235// round up
1236template <class To, class Rep, class Period>
1237constexpr inline
1238To
1239ceil(const std::chrono::duration<Rep, Period>& d)
1240{
1241 auto t = trunc<To>(d);
1242 if (t < d)
1243 return t + To{1};
1244 return t;
1245}
1246
1247template <class Rep, class Period,
1248 class = typename std::enable_if
1249 <
1250 std::numeric_limits<Rep>::is_signed
1251 >::type>
1252constexpr
1253std::chrono::duration<Rep, Period>
1254abs(std::chrono::duration<Rep, Period> d)
1255{
1256 return d >= d.zero() ? d : -d;
1257}
1258
1259// round down
1260template <class To, class Clock, class FromDuration>
1261constexpr inline
1262std::chrono::time_point<Clock, To>
1263floor(const std::chrono::time_point<Clock, FromDuration>& tp)
1264{
1265 using std::chrono::time_point;
1266 return time_point<Clock, To>{gul17::date::floor<To>(tp.time_since_epoch())};
1267}
1268
1269// round to nearest, to even on tie
1270template <class To, class Clock, class FromDuration>
1271constexpr inline
1272std::chrono::time_point<Clock, To>
1273round(const std::chrono::time_point<Clock, FromDuration>& tp)
1274{
1275 using std::chrono::time_point;
1276 return time_point<Clock, To>{round<To>(tp.time_since_epoch())};
1277}
1278
1279// round up
1280template <class To, class Clock, class FromDuration>
1281constexpr inline
1282std::chrono::time_point<Clock, To>
1283ceil(const std::chrono::time_point<Clock, FromDuration>& tp)
1284{
1285 using std::chrono::time_point;
1286 return time_point<Clock, To>{ceil<To>(tp.time_since_epoch())};
1287}
1288
1289#else // HAS_CHRONO_ROUNDING == 1
1290
1291using std::chrono::floor;
1292using std::chrono::ceil;
1293using std::chrono::round;
1294using std::chrono::abs;
1295
1296#endif // HAS_CHRONO_ROUNDING
1297
1298namespace detail
1299{
1300
1301template <class To, class Rep, class Period>
1302constexpr inline
1303typename std::enable_if
1304<
1305 !std::chrono::treat_as_floating_point<typename To::rep>::value,
1306 To
1307>::type
1308round_i(const std::chrono::duration<Rep, Period>& d)
1309{
1310 return round<To>(d);
1311}
1312
1313template <class To, class Rep, class Period>
1314constexpr inline
1315typename std::enable_if
1316<
1317 std::chrono::treat_as_floating_point<typename To::rep>::value,
1318 To
1319>::type
1320round_i(const std::chrono::duration<Rep, Period>& d)
1321{
1322 return d;
1323}
1324
1325template <class To, class Clock, class FromDuration>
1326constexpr inline
1327std::chrono::time_point<Clock, To>
1328round_i(const std::chrono::time_point<Clock, FromDuration>& tp)
1329{
1330 using std::chrono::time_point;
1331 return time_point<Clock, To>{round_i<To>(tp.time_since_epoch())};
1332}
1333
1334} // detail
1335
1336// trunc towards zero
1337template <class To, class Clock, class FromDuration>
1338constexpr inline
1339std::chrono::time_point<Clock, To>
1340trunc(const std::chrono::time_point<Clock, FromDuration>& tp)
1341{
1342 using std::chrono::time_point;
1343 return time_point<Clock, To>{trunc<To>(tp.time_since_epoch())};
1344}
1345
1346// day
1347
1348constexpr inline day::day(unsigned d) noexcept : d_(static_cast<decltype(d_)>(d)) {}
1349constexpr inline day& day::operator++() noexcept {++d_; return *this;}
1350constexpr inline day day::operator++(int) noexcept {auto tmp(*this); ++(*this); return tmp;}
1351constexpr inline day& day::operator--() noexcept {--d_; return *this;}
1352constexpr inline day day::operator--(int) noexcept {auto tmp(*this); --(*this); return tmp;}
1353constexpr inline day& day::operator+=(const days& d) noexcept {*this = *this + d; return *this;}
1354constexpr inline day& day::operator-=(const days& d) noexcept {*this = *this - d; return *this;}
1355constexpr inline day::operator unsigned() const noexcept {return d_;}
1356constexpr inline bool day::ok() const noexcept {return 1 <= d_ && d_ <= 31;}
1357
1358constexpr inline bool
1359operator==(const day& x, const day& y) noexcept
1360{
1361 return static_cast<unsigned>(x) == static_cast<unsigned>(y);
1362}
1363
1364constexpr inline bool
1365operator!=(const day& x, const day& y) noexcept
1366{
1367 return !(x == y);
1368}
1369
1370constexpr inline bool
1371operator<(const day& x, const day& y) noexcept
1372{
1373 return static_cast<unsigned>(x) < static_cast<unsigned>(y);
1374}
1375
1376constexpr inline bool
1377operator>(const day& x, const day& y) noexcept
1378{
1379 return y < x;
1380}
1381
1382constexpr inline bool
1383operator<=(const day& x, const day& y) noexcept
1384{
1385 return !(y < x);
1386}
1387
1388constexpr inline bool
1389operator>=(const day& x, const day& y) noexcept
1390{
1391 return !(x < y);
1392}
1393
1394constexpr inline days
1395operator-(const day& x, const day& y) noexcept
1396{
1397 return days{static_cast<days::rep>(static_cast<unsigned>(x)
1398 - static_cast<unsigned>(y))};
1399}
1400
1401constexpr inline day
1402operator+(const day& x, const days& y) noexcept
1403{
1404 return day{static_cast<unsigned>(x) + static_cast<unsigned>(y.count())};
1405}
1406
1407constexpr inline day
1408operator+(const days& x, const day& y) noexcept
1409{
1410 return y + x;
1411}
1412
1413constexpr inline day
1414operator-(const day& x, const days& y) noexcept
1415{
1416 return x + -y;
1417}
1418
1419namespace detail
1420{
1421
1422template<class CharT, class Traits>
1423std::basic_ostream<CharT, Traits>&
1424low_level_fmt(std::basic_ostream<CharT, Traits>& os, const day& d)
1425{
1426 detail::save_ostream<CharT, Traits> _(os);
1427 os.fill('0');
1428 os.flags(std::ios::dec | std::ios::right);
1429 os.width(2);
1430 os << static_cast<unsigned>(d);
1431 return os;
1432}
1433
1434} // namespace detail
1435
1436template<class CharT, class Traits>
1437inline
1438std::basic_ostream<CharT, Traits>&
1439operator<<(std::basic_ostream<CharT, Traits>& os, const day& d)
1440{
1441 detail::low_level_fmt(os, d);
1442 if (!d.ok())
1443 os << " is not a valid day";
1444 return os;
1445}
1446
1447// month
1448
1449constexpr inline month::month(unsigned m) noexcept : m_(static_cast<decltype(m_)>(m)) {}
1450constexpr inline month& month::operator++() noexcept {*this += months{1}; return *this;}
1451constexpr inline month month::operator++(int) noexcept {auto tmp(*this); ++(*this); return tmp;}
1452constexpr inline month& month::operator--() noexcept {*this -= months{1}; return *this;}
1453constexpr inline month month::operator--(int) noexcept {auto tmp(*this); --(*this); return tmp;}
1454
1455constexpr inline month&
1456month::operator+=(const months& m) noexcept
1457{
1458 *this = *this + m;
1459 return *this;
1460}
1461
1462constexpr inline month&
1463month::operator-=(const months& m) noexcept
1464{
1465 *this = *this - m;
1466 return *this;
1467}
1468
1469constexpr inline month::operator unsigned() const noexcept {return m_;}
1470constexpr inline bool month::ok() const noexcept {return 1 <= m_ && m_ <= 12;}
1471
1472constexpr inline bool
1473operator==(const month& x, const month& y) noexcept
1474{
1475 return static_cast<unsigned>(x) == static_cast<unsigned>(y);
1476}
1477
1478constexpr inline bool
1479operator!=(const month& x, const month& y) noexcept
1480{
1481 return !(x == y);
1482}
1483
1484constexpr inline bool
1485operator<(const month& x, const month& y) noexcept
1486{
1487 return static_cast<unsigned>(x) < static_cast<unsigned>(y);
1488}
1489
1490constexpr inline bool
1491operator>(const month& x, const month& y) noexcept
1492{
1493 return y < x;
1494}
1495
1496constexpr inline bool
1497operator<=(const month& x, const month& y) noexcept
1498{
1499 return !(y < x);
1500}
1501
1502constexpr inline bool
1503operator>=(const month& x, const month& y) noexcept
1504{
1505 return !(x < y);
1506}
1507
1508constexpr inline months
1509operator-(const month& x, const month& y) noexcept
1510{
1511 auto const d = static_cast<unsigned>(x) - static_cast<unsigned>(y);
1512 return months(d <= 11 ? d : d + 12);
1513}
1514
1515constexpr inline month
1516operator+(const month& x, const months& y) noexcept
1517{
1518 auto const mu = static_cast<long long>(static_cast<unsigned>(x)) + y.count() - 1;
1519 auto const yr = (mu >= 0 ? mu : mu-11) / 12;
1520 return month{static_cast<unsigned>(mu - yr * 12 + 1)};
1521}
1522
1523constexpr inline month
1524operator+(const months& x, const month& y) noexcept
1525{
1526 return y + x;
1527}
1528
1529constexpr inline month
1530operator-(const month& x, const months& y) noexcept
1531{
1532 return x + -y;
1533}
1534
1535namespace detail
1536{
1537
1538template<class CharT, class Traits>
1539std::basic_ostream<CharT, Traits>&
1540low_level_fmt(std::basic_ostream<CharT, Traits>& os, const month& m)
1541{
1542 if (m.ok())
1543 {
1544 CharT fmt[] = {'%', 'b', 0};
1545 os << format(os.getloc(), fmt, m);
1546 }
1547 else
1548 os << static_cast<unsigned>(m);
1549 return os;
1550}
1551
1552} // namespace detail
1553
1554template<class CharT, class Traits>
1555inline
1556std::basic_ostream<CharT, Traits>&
1557operator<<(std::basic_ostream<CharT, Traits>& os, const month& m)
1558{
1559 detail::low_level_fmt(os, m);
1560 if (!m.ok())
1561 os << " is not a valid month";
1562 return os;
1563}
1564
1565// year
1566
1567constexpr inline year::year(int y) noexcept : y_(static_cast<decltype(y_)>(y)) {}
1568constexpr inline year& year::operator++() noexcept {++y_; return *this;}
1569constexpr inline year year::operator++(int) noexcept {auto tmp(*this); ++(*this); return tmp;}
1570constexpr inline year& year::operator--() noexcept {--y_; return *this;}
1571constexpr inline year year::operator--(int) noexcept {auto tmp(*this); --(*this); return tmp;}
1572constexpr inline year& year::operator+=(const years& y) noexcept {*this = *this + y; return *this;}
1573constexpr inline year& year::operator-=(const years& y) noexcept {*this = *this - y; return *this;}
1574constexpr inline year year::operator-() const noexcept {return year{-y_};}
1575constexpr inline year year::operator+() const noexcept {return *this;}
1576
1577constexpr inline bool
1578year::is_leap() const noexcept
1579{
1580 return y_ % 4 == 0 && (y_ % 100 != 0 || y_ % 400 == 0);
1581}
1582
1583constexpr inline year::operator int() const noexcept {return y_;}
1584
1585constexpr inline bool
1586year::ok() const noexcept
1587{
1588 return y_ != std::numeric_limits<short>::min();
1589}
1590
1591constexpr inline bool
1592operator==(const year& x, const year& y) noexcept
1593{
1594 return static_cast<int>(x) == static_cast<int>(y);
1595}
1596
1597constexpr inline bool
1598operator!=(const year& x, const year& y) noexcept
1599{
1600 return !(x == y);
1601}
1602
1603constexpr inline bool
1604operator<(const year& x, const year& y) noexcept
1605{
1606 return static_cast<int>(x) < static_cast<int>(y);
1607}
1608
1609constexpr inline bool
1610operator>(const year& x, const year& y) noexcept
1611{
1612 return y < x;
1613}
1614
1615constexpr inline bool
1616operator<=(const year& x, const year& y) noexcept
1617{
1618 return !(y < x);
1619}
1620
1621constexpr inline bool
1622operator>=(const year& x, const year& y) noexcept
1623{
1624 return !(x < y);
1625}
1626
1627constexpr inline years
1628operator-(const year& x, const year& y) noexcept
1629{
1630 return years{static_cast<int>(x) - static_cast<int>(y)};
1631}
1632
1633constexpr inline year
1634operator+(const year& x, const years& y) noexcept
1635{
1636 return year{static_cast<int>(x) + y.count()};
1637}
1638
1639constexpr inline year
1640operator+(const years& x, const year& y) noexcept
1641{
1642 return y + x;
1643}
1644
1645constexpr inline year
1646operator-(const year& x, const years& y) noexcept
1647{
1648 return year{static_cast<int>(x) - y.count()};
1649}
1650
1651namespace detail
1652{
1653
1654template<class CharT, class Traits>
1655std::basic_ostream<CharT, Traits>&
1656low_level_fmt(std::basic_ostream<CharT, Traits>& os, const year& y)
1657{
1658 detail::save_ostream<CharT, Traits> _(os);
1659 os.fill('0');
1660 os.flags(std::ios::dec | std::ios::internal);
1661 os.width(4 + (y < year{0}));
1662 os.imbue(std::locale::classic());
1663 os << static_cast<int>(y);
1664 return os;
1665}
1666
1667} // namespace detail
1668
1669template<class CharT, class Traits>
1670inline
1671std::basic_ostream<CharT, Traits>&
1672operator<<(std::basic_ostream<CharT, Traits>& os, const year& y)
1673{
1674 detail::low_level_fmt(os, y);
1675 if (!y.ok())
1676 os << " is not a valid year";
1677 return os;
1678}
1679
1680// weekday
1681
1682constexpr inline
1683unsigned char
1684weekday::weekday_from_days(int z) noexcept
1685{
1686 auto u = static_cast<unsigned>(z);
1687 return static_cast<unsigned char>(z >= -4 ? (u+4) % 7 : u % 7);
1688}
1689
1690constexpr inline
1691weekday::weekday(unsigned wd) noexcept
1692 : wd_(static_cast<decltype(wd_)>(wd != 7 ? wd : 0))
1693 {}
1694
1695constexpr inline
1696weekday::weekday(const sys_days& dp) noexcept
1697 : wd_(weekday_from_days(dp.time_since_epoch().count()))
1698 {}
1699
1700constexpr inline
1701weekday::weekday(const local_days& dp) noexcept
1702 : wd_(weekday_from_days(dp.time_since_epoch().count()))
1703 {}
1704
1705constexpr inline weekday& weekday::operator++() noexcept {*this += days{1}; return *this;}
1706constexpr inline weekday weekday::operator++(int) noexcept {auto tmp(*this); ++(*this); return tmp;}
1707constexpr inline weekday& weekday::operator--() noexcept {*this -= days{1}; return *this;}
1708constexpr inline weekday weekday::operator--(int) noexcept {auto tmp(*this); --(*this); return tmp;}
1709
1710constexpr inline weekday&
1711weekday::operator+=(const days& d) noexcept
1712{
1713 *this = *this + d;
1714 return *this;
1715}
1716
1717constexpr inline weekday&
1718weekday::operator-=(const days& d) noexcept
1719{
1720 *this = *this - d;
1721 return *this;
1722}
1723
1724constexpr inline bool weekday::ok() const noexcept {return wd_ <= 6;}
1725
1726constexpr inline unsigned weekday::c_encoding() const noexcept
1727{
1728 return unsigned{wd_};
1729}
1730
1731constexpr inline unsigned weekday::iso_encoding() const noexcept
1732{
1733 return unsigned{((wd_ == 0u) ? 7u : wd_)};
1734}
1735
1736constexpr inline bool
1737operator==(const weekday& x, const weekday& y) noexcept
1738{
1739 return x.wd_ == y.wd_;
1740}
1741
1742constexpr inline bool
1743operator!=(const weekday& x, const weekday& y) noexcept
1744{
1745 return !(x == y);
1746}
1747
1748constexpr inline days
1749operator-(const weekday& x, const weekday& y) noexcept
1750{
1751 auto const wdu = x.wd_ - y.wd_;
1752 auto const wk = (wdu >= 0 ? wdu : wdu-6) / 7;
1753 return days{wdu - wk * 7};
1754}
1755
1756constexpr inline weekday
1757operator+(const weekday& x, const days& y) noexcept
1758{
1759 auto const wdu = static_cast<long long>(static_cast<unsigned>(x.wd_)) + y.count();
1760 auto const wk = (wdu >= 0 ? wdu : wdu-6) / 7;
1761 return weekday{static_cast<unsigned>(wdu - wk * 7)};
1762}
1763
1764constexpr inline weekday
1765operator+(const days& x, const weekday& y) noexcept
1766{
1767 return y + x;
1768}
1769
1770constexpr inline weekday
1771operator-(const weekday& x, const days& y) noexcept
1772{
1773 return x + -y;
1774}
1775
1776namespace detail
1777{
1778
1779template<class CharT, class Traits>
1780std::basic_ostream<CharT, Traits>&
1781low_level_fmt(std::basic_ostream<CharT, Traits>& os, const weekday& wd)
1782{
1783 if (wd.ok())
1784 {
1785 CharT fmt[] = {'%', 'a', 0};
1786 os << format(fmt, wd);
1787 }
1788 else
1789 os << wd.c_encoding();
1790 return os;
1791}
1792
1793} // namespace detail
1794
1795template<class CharT, class Traits>
1796inline
1797std::basic_ostream<CharT, Traits>&
1798operator<<(std::basic_ostream<CharT, Traits>& os, const weekday& wd)
1799{
1800 detail::low_level_fmt(os, wd);
1801 if (!wd.ok())
1802 os << " is not a valid weekday";
1803 return os;
1804}
1805
1806#if !defined(_MSC_VER) || (_MSC_VER >= 1900)
1807inline namespace literals
1808{
1809
1810constexpr inline
1811gul17::date::day
1812operator "" _d(unsigned long long d) noexcept
1813{
1814 return gul17::date::day{static_cast<unsigned>(d)};
1815}
1816
1817constexpr inline
1818gul17::date::year
1819operator "" _y(unsigned long long y) noexcept
1820{
1821 return gul17::date::year(static_cast<int>(y));
1822}
1823#endif // !defined(_MSC_VER) || (_MSC_VER >= 1900)
1824
1825constexpr const gul17::date::last_spec last{};
1826
1827constexpr const gul17::date::month jan{1};
1828constexpr const gul17::date::month feb{2};
1829constexpr const gul17::date::month mar{3};
1830constexpr const gul17::date::month apr{4};
1831constexpr const gul17::date::month may{5};
1832constexpr const gul17::date::month jun{6};
1833constexpr const gul17::date::month jul{7};
1834constexpr const gul17::date::month aug{8};
1835constexpr const gul17::date::month sep{9};
1836constexpr const gul17::date::month oct{10};
1837constexpr const gul17::date::month nov{11};
1838constexpr const gul17::date::month dec{12};
1839
1840constexpr const gul17::date::weekday sun{0u};
1841constexpr const gul17::date::weekday mon{1u};
1842constexpr const gul17::date::weekday tue{2u};
1843constexpr const gul17::date::weekday wed{3u};
1844constexpr const gul17::date::weekday thu{4u};
1845constexpr const gul17::date::weekday fri{5u};
1846constexpr const gul17::date::weekday sat{6u};
1847
1848#if !defined(_MSC_VER) || (_MSC_VER >= 1900)
1849} // inline namespace literals
1850#endif
1851
1852constexpr const gul17::date::month January{1};
1853constexpr const gul17::date::month February{2};
1854constexpr const gul17::date::month March{3};
1855constexpr const gul17::date::month April{4};
1856constexpr const gul17::date::month May{5};
1857constexpr const gul17::date::month June{6};
1858constexpr const gul17::date::month July{7};
1859constexpr const gul17::date::month August{8};
1860constexpr const gul17::date::month September{9};
1861constexpr const gul17::date::month October{10};
1862constexpr const gul17::date::month November{11};
1863constexpr const gul17::date::month December{12};
1864
1865constexpr const gul17::date::weekday Monday{1};
1866constexpr const gul17::date::weekday Tuesday{2};
1867constexpr const gul17::date::weekday Wednesday{3};
1868constexpr const gul17::date::weekday Thursday{4};
1869constexpr const gul17::date::weekday Friday{5};
1870constexpr const gul17::date::weekday Saturday{6};
1871constexpr const gul17::date::weekday Sunday{7};
1872
1873// weekday_indexed
1874
1875constexpr inline
1876weekday
1877weekday_indexed::weekday() const noexcept
1878{
1879 return gul17::date::weekday{static_cast<unsigned>(wd_)};
1880}
1881
1882constexpr inline unsigned weekday_indexed::index() const noexcept {return index_;}
1883
1884constexpr inline bool
1885weekday_indexed::ok() const noexcept
1886{
1887 return weekday().ok() && 1 <= index_ && index_ <= 5;
1888}
1889
1890#ifdef __GNUC__
1891# pragma GCC diagnostic push
1892# pragma GCC diagnostic ignored "-Wconversion"
1893#endif // __GNUC__
1894
1895constexpr inline
1896weekday_indexed::weekday_indexed(const gul17::date::weekday& wd, unsigned index) noexcept
1897 : wd_(static_cast<decltype(wd_)>(static_cast<unsigned>(wd.wd_)))
1898 , index_(static_cast<decltype(index_)>(index))
1899 {}
1900
1901#ifdef __GNUC__
1902# pragma GCC diagnostic pop
1903#endif // __GNUC__
1904
1905namespace detail
1906{
1907
1908template<class CharT, class Traits>
1909std::basic_ostream<CharT, Traits>&
1910low_level_fmt(std::basic_ostream<CharT, Traits>& os, const weekday_indexed& wdi)
1911{
1912 return low_level_fmt(os, wdi.weekday()) << '[' << wdi.index() << ']';
1913}
1914
1915} // namespace detail
1916
1917template<class CharT, class Traits>
1918inline
1919std::basic_ostream<CharT, Traits>&
1920operator<<(std::basic_ostream<CharT, Traits>& os, const weekday_indexed& wdi)
1921{
1922 detail::low_level_fmt(os, wdi);
1923 if (!wdi.ok())
1924 os << " is not a valid weekday_indexed";
1925 return os;
1926}
1927
1928constexpr inline weekday_indexed
1929weekday::operator[](unsigned index) const noexcept
1930{
1931 return {*this, index};
1932}
1933
1934constexpr inline bool
1935operator==(const weekday_indexed& x, const weekday_indexed& y) noexcept
1936{
1937 return x.weekday() == y.weekday() && x.index() == y.index();
1938}
1939
1940constexpr inline bool
1941operator!=(const weekday_indexed& x, const weekday_indexed& y) noexcept
1942{
1943 return !(x == y);
1944}
1945
1946// weekday_last
1947
1948constexpr inline gul17::date::weekday weekday_last::weekday() const noexcept {return wd_;}
1949constexpr inline bool weekday_last::ok() const noexcept {return wd_.ok();}
1950constexpr inline weekday_last::weekday_last(const gul17::date::weekday& wd) noexcept : wd_(wd) {}
1951
1952constexpr inline bool
1953operator==(const weekday_last& x, const weekday_last& y) noexcept
1954{
1955 return x.weekday() == y.weekday();
1956}
1957
1958constexpr inline bool
1959operator!=(const weekday_last& x, const weekday_last& y) noexcept
1960{
1961 return !(x == y);
1962}
1963
1964namespace detail
1965{
1966
1967template<class CharT, class Traits>
1968std::basic_ostream<CharT, Traits>&
1969low_level_fmt(std::basic_ostream<CharT, Traits>& os, const weekday_last& wdl)
1970{
1971 return low_level_fmt(os, wdl.weekday()) << "[last]";
1972}
1973
1974} // namespace detail
1975
1976template<class CharT, class Traits>
1977inline
1978std::basic_ostream<CharT, Traits>&
1979operator<<(std::basic_ostream<CharT, Traits>& os, const weekday_last& wdl)
1980{
1981 detail::low_level_fmt(os, wdl);
1982 if (!wdl.ok())
1983 os << " is not a valid weekday_last";
1984 return os;
1985}
1986
1987constexpr inline
1988weekday_last
1989weekday::operator[](last_spec) const noexcept
1990{
1991 return weekday_last{*this};
1992}
1993
1994// year_month
1995
1996constexpr inline
1997year_month::year_month(const gul17::date::year& y, const gul17::date::month& m) noexcept
1998 : y_(y)
1999 , m_(m)
2000 {}
2001
2002constexpr inline year year_month::year() const noexcept {return y_;}
2003constexpr inline month year_month::month() const noexcept {return m_;}
2004constexpr inline bool year_month::ok() const noexcept {return y_.ok() && m_.ok();}
2005
2006template<class>
2007constexpr inline year_month&
2008year_month::operator+=(const months& dm) noexcept
2009{
2010 *this = *this + dm;
2011 return *this;
2012}
2013
2014template<class>
2015constexpr inline year_month&
2016year_month::operator-=(const months& dm) noexcept
2017{
2018 *this = *this - dm;
2019 return *this;
2020}
2021
2022constexpr inline year_month&
2023year_month::operator+=(const years& dy) noexcept
2024{
2025 *this = *this + dy;
2026 return *this;
2027}
2028
2029constexpr inline year_month&
2030year_month::operator-=(const years& dy) noexcept
2031{
2032 *this = *this - dy;
2033 return *this;
2034}
2035
2036constexpr inline bool
2037operator==(const year_month& x, const year_month& y) noexcept
2038{
2039 return x.year() == y.year() && x.month() == y.month();
2040}
2041
2042constexpr inline bool
2043operator!=(const year_month& x, const year_month& y) noexcept
2044{
2045 return !(x == y);
2046}
2047
2048constexpr inline bool
2049operator<(const year_month& x, const year_month& y) noexcept
2050{
2051 return x.year() < y.year() ? true
2052 : (x.year() > y.year() ? false
2053 : (x.month() < y.month()));
2054}
2055
2056constexpr inline bool
2057operator>(const year_month& x, const year_month& y) noexcept
2058{
2059 return y < x;
2060}
2061
2062constexpr inline bool
2063operator<=(const year_month& x, const year_month& y) noexcept
2064{
2065 return !(y < x);
2066}
2067
2068constexpr inline bool
2069operator>=(const year_month& x, const year_month& y) noexcept
2070{
2071 return !(x < y);
2072}
2073
2074template<class>
2075constexpr inline year_month
2076operator+(const year_month& ym, const months& dm) noexcept
2077{
2078 auto dmi = static_cast<int>(static_cast<unsigned>(ym.month())) - 1 + dm.count();
2079 auto dy = (dmi >= 0 ? dmi : dmi-11) / 12;
2080 dmi = dmi - dy * 12 + 1;
2081 return (ym.year() + years(dy)) / month(static_cast<unsigned>(dmi));
2082}
2083
2084template<class>
2085constexpr inline year_month
2086operator+(const months& dm, const year_month& ym) noexcept
2087{
2088 return ym + dm;
2089}
2090
2091template<class>
2092constexpr inline year_month
2093operator-(const year_month& ym, const months& dm) noexcept
2094{
2095 return ym + -dm;
2096}
2097
2098constexpr inline months
2099operator-(const year_month& x, const year_month& y) noexcept
2100{
2101 return (x.year() - y.year()) +
2102 months(static_cast<unsigned>(x.month()) - static_cast<unsigned>(y.month()));
2103}
2104
2105constexpr inline year_month
2106operator+(const year_month& ym, const years& dy) noexcept
2107{
2108 return (ym.year() + dy) / ym.month();
2109}
2110
2111constexpr inline year_month
2112operator+(const years& dy, const year_month& ym) noexcept
2113{
2114 return ym + dy;
2115}
2116
2117constexpr inline year_month
2118operator-(const year_month& ym, const years& dy) noexcept
2119{
2120 return ym + -dy;
2121}
2122
2123namespace detail
2124{
2125
2126template<class CharT, class Traits>
2127std::basic_ostream<CharT, Traits>&
2128low_level_fmt(std::basic_ostream<CharT, Traits>& os, const year_month& ym)
2129{
2130 low_level_fmt(os, ym.year()) << '/';
2131 return low_level_fmt(os, ym.month());
2132}
2133
2134} // namespace detail
2135
2136template<class CharT, class Traits>
2137inline
2138std::basic_ostream<CharT, Traits>&
2139operator<<(std::basic_ostream<CharT, Traits>& os, const year_month& ym)
2140{
2141 detail::low_level_fmt(os, ym);
2142 if (!ym.ok())
2143 os << " is not a valid year_month";
2144 return os;
2145}
2146
2147// month_day
2148
2149constexpr inline
2150month_day::month_day(const gul17::date::month& m, const gul17::date::day& d) noexcept
2151 : m_(m)
2152 , d_(d)
2153 {}
2154
2155constexpr inline gul17::date::month month_day::month() const noexcept {return m_;}
2156constexpr inline gul17::date::day month_day::day() const noexcept {return d_;}
2157
2158constexpr inline bool
2159month_day::ok() const noexcept
2160{
2161 constexpr const gul17::date::day d[] =
2162 {
2163 gul17::date::day(31), gul17::date::day(29), gul17::date::day(31),
2164 gul17::date::day(30), gul17::date::day(31), gul17::date::day(30),
2165 gul17::date::day(31), gul17::date::day(31), gul17::date::day(30),
2166 gul17::date::day(31), gul17::date::day(30), gul17::date::day(31)
2167 };
2168 return m_.ok() && gul17::date::day{1} <= d_ && d_ <= d[static_cast<unsigned>(m_)-1];
2169}
2170
2171constexpr inline bool
2172operator==(const month_day& x, const month_day& y) noexcept
2173{
2174 return x.month() == y.month() && x.day() == y.day();
2175}
2176
2177constexpr inline bool
2178operator!=(const month_day& x, const month_day& y) noexcept
2179{
2180 return !(x == y);
2181}
2182
2183constexpr inline bool
2184operator<(const month_day& x, const month_day& y) noexcept
2185{
2186 return x.month() < y.month() ? true
2187 : (x.month() > y.month() ? false
2188 : (x.day() < y.day()));
2189}
2190
2191constexpr inline bool
2192operator>(const month_day& x, const month_day& y) noexcept
2193{
2194 return y < x;
2195}
2196
2197constexpr inline bool
2198operator<=(const month_day& x, const month_day& y) noexcept
2199{
2200 return !(y < x);
2201}
2202
2203constexpr inline bool
2204operator>=(const month_day& x, const month_day& y) noexcept
2205{
2206 return !(x < y);
2207}
2208
2209namespace detail
2210{
2211
2212template<class CharT, class Traits>
2213std::basic_ostream<CharT, Traits>&
2214low_level_fmt(std::basic_ostream<CharT, Traits>& os, const month_day& md)
2215{
2216 low_level_fmt(os, md.month()) << '/';
2217 return low_level_fmt(os, md.day());
2218}
2219
2220} // namespace detail
2221
2222template<class CharT, class Traits>
2223inline
2224std::basic_ostream<CharT, Traits>&
2225operator<<(std::basic_ostream<CharT, Traits>& os, const month_day& md)
2226{
2227 detail::low_level_fmt(os, md);
2228 if (!md.ok())
2229 os << " is not a valid month_day";
2230 return os;
2231}
2232
2233// month_day_last
2234
2235constexpr inline month month_day_last::month() const noexcept {return m_;}
2236constexpr inline bool month_day_last::ok() const noexcept {return m_.ok();}
2237constexpr inline month_day_last::month_day_last(const gul17::date::month& m) noexcept : m_(m) {}
2238
2239constexpr inline bool
2240operator==(const month_day_last& x, const month_day_last& y) noexcept
2241{
2242 return x.month() == y.month();
2243}
2244
2245constexpr inline bool
2246operator!=(const month_day_last& x, const month_day_last& y) noexcept
2247{
2248 return !(x == y);
2249}
2250
2251constexpr inline bool
2252operator<(const month_day_last& x, const month_day_last& y) noexcept
2253{
2254 return x.month() < y.month();
2255}
2256
2257constexpr inline bool
2258operator>(const month_day_last& x, const month_day_last& y) noexcept
2259{
2260 return y < x;
2261}
2262
2263constexpr inline bool
2264operator<=(const month_day_last& x, const month_day_last& y) noexcept
2265{
2266 return !(y < x);
2267}
2268
2269constexpr inline bool
2270operator>=(const month_day_last& x, const month_day_last& y) noexcept
2271{
2272 return !(x < y);
2273}
2274
2275namespace detail
2276{
2277
2278template<class CharT, class Traits>
2279std::basic_ostream<CharT, Traits>&
2280low_level_fmt(std::basic_ostream<CharT, Traits>& os, const month_day_last& mdl)
2281{
2282 return low_level_fmt(os, mdl.month()) << "/last";
2283}
2284
2285} // namespace detail
2286
2287template<class CharT, class Traits>
2288inline
2289std::basic_ostream<CharT, Traits>&
2290operator<<(std::basic_ostream<CharT, Traits>& os, const month_day_last& mdl)
2291{
2292 detail::low_level_fmt(os, mdl);
2293 if (!mdl.ok())
2294 os << " is not a valid month_day_last";
2295 return os;
2296}
2297
2298// month_weekday
2299
2300constexpr inline
2301month_weekday::month_weekday(const gul17::date::month& m,
2302 const gul17::date::weekday_indexed& wdi) noexcept
2303 : m_(m)
2304 , wdi_(wdi)
2305 {}
2306
2307constexpr inline month month_weekday::month() const noexcept {return m_;}
2308
2309constexpr inline weekday_indexed
2310month_weekday::weekday_indexed() const noexcept
2311{
2312 return wdi_;
2313}
2314
2315constexpr inline bool
2316month_weekday::ok() const noexcept
2317{
2318 return m_.ok() && wdi_.ok();
2319}
2320
2321constexpr inline bool
2322operator==(const month_weekday& x, const month_weekday& y) noexcept
2323{
2324 return x.month() == y.month() && x.weekday_indexed() == y.weekday_indexed();
2325}
2326
2327constexpr inline bool
2328operator!=(const month_weekday& x, const month_weekday& y) noexcept
2329{
2330 return !(x == y);
2331}
2332
2333namespace detail
2334{
2335
2336template<class CharT, class Traits>
2337std::basic_ostream<CharT, Traits>&
2338low_level_fmt(std::basic_ostream<CharT, Traits>& os, const month_weekday& mwd)
2339{
2340 low_level_fmt(os, mwd.month()) << '/';
2341 return low_level_fmt(os, mwd.weekday_indexed());
2342}
2343
2344} // namespace detail
2345
2346template<class CharT, class Traits>
2347inline
2348std::basic_ostream<CharT, Traits>&
2349operator<<(std::basic_ostream<CharT, Traits>& os, const month_weekday& mwd)
2350{
2351 detail::low_level_fmt(os, mwd);
2352 if (!mwd.ok())
2353 os << " is not a valid month_weekday";
2354 return os;
2355}
2356
2357// month_weekday_last
2358
2359constexpr inline
2360month_weekday_last::month_weekday_last(const gul17::date::month& m,
2361 const gul17::date::weekday_last& wdl) noexcept
2362 : m_(m)
2363 , wdl_(wdl)
2364 {}
2365
2366constexpr inline month month_weekday_last::month() const noexcept {return m_;}
2367
2368constexpr inline weekday_last
2369month_weekday_last::weekday_last() const noexcept
2370{
2371 return wdl_;
2372}
2373
2374constexpr inline bool
2375month_weekday_last::ok() const noexcept
2376{
2377 return m_.ok() && wdl_.ok();
2378}
2379
2380constexpr inline bool
2381operator==(const month_weekday_last& x, const month_weekday_last& y) noexcept
2382{
2383 return x.month() == y.month() && x.weekday_last() == y.weekday_last();
2384}
2385
2386constexpr inline bool
2387operator!=(const month_weekday_last& x, const month_weekday_last& y) noexcept
2388{
2389 return !(x == y);
2390}
2391
2392namespace detail
2393{
2394
2395template<class CharT, class Traits>
2396std::basic_ostream<CharT, Traits>&
2397low_level_fmt(std::basic_ostream<CharT, Traits>& os, const month_weekday_last& mwdl)
2398{
2399 low_level_fmt(os, mwdl.month()) << '/';
2400 return low_level_fmt(os, mwdl.weekday_last());
2401}
2402
2403} // namespace detail
2404
2405template<class CharT, class Traits>
2406inline
2407std::basic_ostream<CharT, Traits>&
2408operator<<(std::basic_ostream<CharT, Traits>& os, const month_weekday_last& mwdl)
2409{
2410 detail::low_level_fmt(os, mwdl);
2411 if (!mwdl.ok())
2412 os << " is not a valid month_weekday_last";
2413 return os;
2414}
2415
2416// year_month_day_last
2417
2418constexpr inline year_month_day_last::year_month_day_last(const gul17::date::year& y,
2419 const gul17::date::month_day_last& mdl) noexcept
2420 : y_(y)
2421 , mdl_(mdl)
2422 {}
2423
2424template<class>
2425constexpr inline year_month_day_last&
2426year_month_day_last::operator+=(const months& m) noexcept
2427{
2428 *this = *this + m;
2429 return *this;
2430}
2431
2432template<class>
2433constexpr inline year_month_day_last&
2434year_month_day_last::operator-=(const months& m) noexcept
2435{
2436 *this = *this - m;
2437 return *this;
2438}
2439
2440constexpr inline year_month_day_last&
2441year_month_day_last::operator+=(const years& y) noexcept
2442{
2443 *this = *this + y;
2444 return *this;
2445}
2446
2447constexpr inline year_month_day_last&
2448year_month_day_last::operator-=(const years& y) noexcept
2449{
2450 *this = *this - y;
2451 return *this;
2452}
2453
2454constexpr inline year year_month_day_last::year() const noexcept {return y_;}
2455constexpr inline month year_month_day_last::month() const noexcept {return mdl_.month();}
2456
2457constexpr inline
2458month_day_last
2459year_month_day_last::month_day_last() const noexcept
2460{
2461 return mdl_;
2462}
2463
2464constexpr inline
2465day
2466year_month_day_last::day() const noexcept
2467{
2468 constexpr const gul17::date::day d[] =
2469 {
2470 gul17::date::day(31), gul17::date::day(28), gul17::date::day(31),
2471 gul17::date::day(30), gul17::date::day(31), gul17::date::day(30),
2472 gul17::date::day(31), gul17::date::day(31), gul17::date::day(30),
2473 gul17::date::day(31), gul17::date::day(30), gul17::date::day(31)
2474 };
2475 return (month() != February || !y_.is_leap()) && mdl_.ok() ?
2476 d[static_cast<unsigned>(month()) - 1] : gul17::date::day{29};
2477}
2478
2479constexpr inline
2480year_month_day_last::operator sys_days() const noexcept
2481{
2482 return sys_days(year()/month()/day());
2483}
2484
2485constexpr inline
2486year_month_day_last::operator local_days() const noexcept
2487{
2488 return local_days(year()/month()/day());
2489}
2490
2491constexpr inline bool
2492year_month_day_last::ok() const noexcept
2493{
2494 return y_.ok() && mdl_.ok();
2495}
2496
2497constexpr inline bool
2498operator==(const year_month_day_last& x, const year_month_day_last& y) noexcept
2499{
2500 return x.year() == y.year() && x.month_day_last() == y.month_day_last();
2501}
2502
2503constexpr inline bool
2504operator!=(const year_month_day_last& x, const year_month_day_last& y) noexcept
2505{
2506 return !(x == y);
2507}
2508
2509constexpr inline bool
2510operator<(const year_month_day_last& x, const year_month_day_last& y) noexcept
2511{
2512 return x.year() < y.year() ? true
2513 : (x.year() > y.year() ? false
2514 : (x.month_day_last() < y.month_day_last()));
2515}
2516
2517constexpr inline bool
2518operator>(const year_month_day_last& x, const year_month_day_last& y) noexcept
2519{
2520 return y < x;
2521}
2522
2523constexpr inline bool
2524operator<=(const year_month_day_last& x, const year_month_day_last& y) noexcept
2525{
2526 return !(y < x);
2527}
2528
2529constexpr inline bool
2530operator>=(const year_month_day_last& x, const year_month_day_last& y) noexcept
2531{
2532 return !(x < y);
2533}
2534
2535namespace detail
2536{
2537
2538template<class CharT, class Traits>
2539std::basic_ostream<CharT, Traits>&
2540low_level_fmt(std::basic_ostream<CharT, Traits>& os, const year_month_day_last& ymdl)
2541{
2542 low_level_fmt(os, ymdl.year()) << '/';
2543 return low_level_fmt(os, ymdl.month_day_last());
2544}
2545
2546} // namespace detail
2547
2548template<class CharT, class Traits>
2549inline
2550std::basic_ostream<CharT, Traits>&
2551operator<<(std::basic_ostream<CharT, Traits>& os, const year_month_day_last& ymdl)
2552{
2553 detail::low_level_fmt(os, ymdl);
2554 if (!ymdl.ok())
2555 os << " is not a valid year_month_day_last";
2556 return os;
2557}
2558
2559template<class>
2560constexpr inline
2561year_month_day_last
2562operator+(const year_month_day_last& ymdl, const months& dm) noexcept
2563{
2564 return (ymdl.year() / ymdl.month() + dm) / last;
2565}
2566
2567template<class>
2568constexpr inline
2569year_month_day_last
2570operator+(const months& dm, const year_month_day_last& ymdl) noexcept
2571{
2572 return ymdl + dm;
2573}
2574
2575template<class>
2576constexpr inline
2577year_month_day_last
2578operator-(const year_month_day_last& ymdl, const months& dm) noexcept
2579{
2580 return ymdl + (-dm);
2581}
2582
2583constexpr inline
2584year_month_day_last
2585operator+(const year_month_day_last& ymdl, const years& dy) noexcept
2586{
2587 return {ymdl.year()+dy, ymdl.month_day_last()};
2588}
2589
2590constexpr inline
2591year_month_day_last
2592operator+(const years& dy, const year_month_day_last& ymdl) noexcept
2593{
2594 return ymdl + dy;
2595}
2596
2597constexpr inline
2598year_month_day_last
2599operator-(const year_month_day_last& ymdl, const years& dy) noexcept
2600{
2601 return ymdl + (-dy);
2602}
2603
2604// year_month_day
2605
2606constexpr inline
2607year_month_day::year_month_day(const gul17::date::year& y, const gul17::date::month& m,
2608 const gul17::date::day& d) noexcept
2609 : y_(y)
2610 , m_(m)
2611 , d_(d)
2612 {}
2613
2614constexpr inline
2615year_month_day::year_month_day(const year_month_day_last& ymdl) noexcept
2616 : y_(ymdl.year())
2617 , m_(ymdl.month())
2618 , d_(ymdl.day())
2619 {}
2620
2621constexpr inline
2622year_month_day::year_month_day(sys_days dp) noexcept
2623 : year_month_day(from_days(dp.time_since_epoch()))
2624 {}
2625
2626constexpr inline
2627year_month_day::year_month_day(local_days dp) noexcept
2628 : year_month_day(from_days(dp.time_since_epoch()))
2629 {}
2630
2631constexpr inline year year_month_day::year() const noexcept {return y_;}
2632constexpr inline month year_month_day::month() const noexcept {return m_;}
2633constexpr inline day year_month_day::day() const noexcept {return d_;}
2634
2635template<class>
2636constexpr inline
2637year_month_day&
2638year_month_day::operator+=(const months& m) noexcept
2639{
2640 *this = *this + m;
2641 return *this;
2642}
2643
2644template<class>
2645constexpr inline
2646year_month_day&
2647year_month_day::operator-=(const months& m) noexcept
2648{
2649 *this = *this - m;
2650 return *this;
2651}
2652
2653constexpr inline
2654year_month_day&
2655year_month_day::operator+=(const years& y) noexcept
2656{
2657 *this = *this + y;
2658 return *this;
2659}
2660
2661constexpr inline
2662year_month_day&
2663year_month_day::operator-=(const years& y) noexcept
2664{
2665 *this = *this - y;
2666 return *this;
2667}
2668
2669constexpr inline
2670days
2671year_month_day::to_days() const noexcept
2672{
2673 static_assert(std::numeric_limits<unsigned>::digits >= 18,
2674 "This algorithm has not been ported to a 16 bit unsigned integer");
2675 static_assert(std::numeric_limits<int>::digits >= 20,
2676 "This algorithm has not been ported to a 16 bit signed integer");
2677 auto const y = static_cast<int>(y_) - (m_ <= February);
2678 auto const m = static_cast<unsigned>(m_);
2679 auto const d = static_cast<unsigned>(d_);
2680 auto const era = (y >= 0 ? y : y-399) / 400;
2681 auto const yoe = static_cast<unsigned>(y - era * 400); // [0, 399]
2682 auto const doy = (153*(m > 2 ? m-3 : m+9) + 2)/5 + d-1; // [0, 365]
2683 auto const doe = yoe * 365 + yoe/4 - yoe/100 + doy; // [0, 146096]
2684 return days{era * 146097 + static_cast<int>(doe) - 719468};
2685}
2686
2687constexpr inline
2688year_month_day::operator sys_days() const noexcept
2689{
2690 return sys_days{to_days()};
2691}
2692
2693constexpr inline
2694year_month_day::operator local_days() const noexcept
2695{
2696 return local_days{to_days()};
2697}
2698
2699constexpr inline bool
2700year_month_day::ok() const noexcept
2701{
2702 if (!(y_.ok() && m_.ok()))
2703 return false;
2704 return gul17::date::day{1} <= d_ && d_ <= (y_ / m_ / last).day();
2705}
2706
2707constexpr inline bool
2708operator==(const year_month_day& x, const year_month_day& y) noexcept
2709{
2710 return x.year() == y.year() && x.month() == y.month() && x.day() == y.day();
2711}
2712
2713constexpr inline bool
2714operator!=(const year_month_day& x, const year_month_day& y) noexcept
2715{
2716 return !(x == y);
2717}
2718
2719constexpr inline bool
2720operator<(const year_month_day& x, const year_month_day& y) noexcept
2721{
2722 return x.year() < y.year() ? true
2723 : (x.year() > y.year() ? false
2724 : (x.month() < y.month() ? true
2725 : (x.month() > y.month() ? false
2726 : (x.day() < y.day()))));
2727}
2728
2729constexpr inline bool
2730operator>(const year_month_day& x, const year_month_day& y) noexcept
2731{
2732 return y < x;
2733}
2734
2735constexpr inline bool
2736operator<=(const year_month_day& x, const year_month_day& y) noexcept
2737{
2738 return !(y < x);
2739}
2740
2741constexpr inline bool
2742operator>=(const year_month_day& x, const year_month_day& y) noexcept
2743{
2744 return !(x < y);
2745}
2746
2747template<class CharT, class Traits>
2748inline
2749std::basic_ostream<CharT, Traits>&
2750operator<<(std::basic_ostream<CharT, Traits>& os, const year_month_day& ymd)
2751{
2752 detail::save_ostream<CharT, Traits> _(os);
2753 os.fill('0');
2754 os.flags(std::ios::dec | std::ios::right);
2755 os.imbue(std::locale::classic());
2756 os << static_cast<int>(ymd.year()) << '-';
2757 os.width(2);
2758 os << static_cast<unsigned>(ymd.month()) << '-';
2759 os.width(2);
2760 os << static_cast<unsigned>(ymd.day());
2761 if (!ymd.ok())
2762 os << " is not a valid year_month_day";
2763 return os;
2764}
2765
2766constexpr inline
2767year_month_day
2768year_month_day::from_days(days dp) noexcept
2769{
2770 static_assert(std::numeric_limits<unsigned>::digits >= 18,
2771 "This algorithm has not been ported to a 16 bit unsigned integer");
2772 static_assert(std::numeric_limits<int>::digits >= 20,
2773 "This algorithm has not been ported to a 16 bit signed integer");
2774 auto const z = dp.count() + 719468;
2775 auto const era = (z >= 0 ? z : z - 146096) / 146097;
2776 auto const doe = static_cast<unsigned>(z - era * 146097); // [0, 146096]
2777 auto const yoe = (doe - doe/1460 + doe/36524 - doe/146096) / 365; // [0, 399]
2778 auto const y = static_cast<days::rep>(yoe) + era * 400;
2779 auto const doy = doe - (365*yoe + yoe/4 - yoe/100); // [0, 365]
2780 auto const mp = (5*doy + 2)/153; // [0, 11]
2781 auto const d = doy - (153*mp+2)/5 + 1; // [1, 31]
2782 auto const m = mp < 10 ? mp+3 : mp-9; // [1, 12]
2783 return year_month_day{gul17::date::year{y + (m <= 2)}, gul17::date::month(m), gul17::date::day(d)};
2784}
2785
2786template<class>
2787constexpr inline
2788year_month_day
2789operator+(const year_month_day& ymd, const months& dm) noexcept
2790{
2791 return (ymd.year() / ymd.month() + dm) / ymd.day();
2792}
2793
2794template<class>
2795constexpr inline
2796year_month_day
2797operator+(const months& dm, const year_month_day& ymd) noexcept
2798{
2799 return ymd + dm;
2800}
2801
2802template<class>
2803constexpr inline
2804year_month_day
2805operator-(const year_month_day& ymd, const months& dm) noexcept
2806{
2807 return ymd + (-dm);
2808}
2809
2810constexpr inline
2811year_month_day
2812operator+(const year_month_day& ymd, const years& dy) noexcept
2813{
2814 return (ymd.year() + dy) / ymd.month() / ymd.day();
2815}
2816
2817constexpr inline
2818year_month_day
2819operator+(const years& dy, const year_month_day& ymd) noexcept
2820{
2821 return ymd + dy;
2822}
2823
2824constexpr inline
2825year_month_day
2826operator-(const year_month_day& ymd, const years& dy) noexcept
2827{
2828 return ymd + (-dy);
2829}
2830
2831// year_month_weekday
2832
2833constexpr inline
2834year_month_weekday::year_month_weekday(const gul17::date::year& y, const gul17::date::month& m,
2835 const gul17::date::weekday_indexed& wdi)
2836 noexcept
2837 : y_(y)
2838 , m_(m)
2839 , wdi_(wdi)
2840 {}
2841
2842constexpr inline
2843year_month_weekday::year_month_weekday(const sys_days& dp) noexcept
2844 : year_month_weekday(from_days(dp.time_since_epoch()))
2845 {}
2846
2847constexpr inline
2848year_month_weekday::year_month_weekday(const local_days& dp) noexcept
2849 : year_month_weekday(from_days(dp.time_since_epoch()))
2850 {}
2851
2852template<class>
2853constexpr inline
2854year_month_weekday&
2855year_month_weekday::operator+=(const months& m) noexcept
2856{
2857 *this = *this + m;
2858 return *this;
2859}
2860
2861template<class>
2862constexpr inline
2863year_month_weekday&
2864year_month_weekday::operator-=(const months& m) noexcept
2865{
2866 *this = *this - m;
2867 return *this;
2868}
2869
2870constexpr inline
2871year_month_weekday&
2872year_month_weekday::operator+=(const years& y) noexcept
2873{
2874 *this = *this + y;
2875 return *this;
2876}
2877
2878constexpr inline
2879year_month_weekday&
2880year_month_weekday::operator-=(const years& y) noexcept
2881{
2882 *this = *this - y;
2883 return *this;
2884}
2885
2886constexpr inline year year_month_weekday::year() const noexcept {return y_;}
2887constexpr inline month year_month_weekday::month() const noexcept {return m_;}
2888
2889constexpr inline
2890weekday
2891year_month_weekday::weekday() const noexcept
2892{
2893 return wdi_.weekday();
2894}
2895
2896constexpr inline
2897unsigned
2898year_month_weekday::index() const noexcept
2899{
2900 return wdi_.index();
2901}
2902
2903constexpr inline
2904weekday_indexed
2905year_month_weekday::weekday_indexed() const noexcept
2906{
2907 return wdi_;
2908}
2909
2910constexpr inline
2911year_month_weekday::operator sys_days() const noexcept
2912{
2913 return sys_days{to_days()};
2914}
2915
2916constexpr inline
2917year_month_weekday::operator local_days() const noexcept
2918{
2919 return local_days{to_days()};
2920}
2921
2922constexpr inline bool
2923year_month_weekday::ok() const noexcept
2924{
2925 if (!y_.ok() || !m_.ok() || !wdi_.weekday().ok() || wdi_.index() < 1)
2926 return false;
2927 if (wdi_.index() <= 4)
2928 return true;
2929 auto d2 = wdi_.weekday() - gul17::date::weekday(static_cast<sys_days>(y_/m_/1)) +
2930 days((wdi_.index()-1)*7 + 1);
2931 return static_cast<unsigned>(d2.count()) <= static_cast<unsigned>((y_/m_/last).day());
2932}
2933
2934constexpr inline
2935year_month_weekday
2936year_month_weekday::from_days(days d) noexcept
2937{
2938 sys_days dp{d};
2939 auto const wd = gul17::date::weekday(dp);
2940 auto const ymd = year_month_day(dp);
2941 return {ymd.year(), ymd.month(), wd[(static_cast<unsigned>(ymd.day())-1)/7+1]};
2942}
2943
2944constexpr inline
2945days
2946year_month_weekday::to_days() const noexcept
2947{
2948 auto d = sys_days(y_/m_/1);
2949 return (d + (wdi_.weekday() - gul17::date::weekday(d) + days{(wdi_.index()-1)*7})
2950 ).time_since_epoch();
2951}
2952
2953constexpr inline bool
2954operator==(const year_month_weekday& x, const year_month_weekday& y) noexcept
2955{
2956 return x.year() == y.year() && x.month() == y.month() &&
2957 x.weekday_indexed() == y.weekday_indexed();
2958}
2959
2960constexpr inline bool
2961operator!=(const year_month_weekday& x, const year_month_weekday& y) noexcept
2962{
2963 return !(x == y);
2964}
2965
2966template<class CharT, class Traits>
2967inline
2968std::basic_ostream<CharT, Traits>&
2969operator<<(std::basic_ostream<CharT, Traits>& os, const year_month_weekday& ymwdi)
2970{
2971 detail::low_level_fmt(os, ymwdi.year()) << '/';
2972 detail::low_level_fmt(os, ymwdi.month()) << '/';
2973 detail::low_level_fmt(os, ymwdi.weekday_indexed());
2974 if (!ymwdi.ok())
2975 os << " is not a valid year_month_weekday";
2976 return os;
2977}
2978
2979template<class>
2980constexpr inline
2981year_month_weekday
2982operator+(const year_month_weekday& ymwd, const months& dm) noexcept
2983{
2984 return (ymwd.year() / ymwd.month() + dm) / ymwd.weekday_indexed();
2985}
2986
2987template<class>
2988constexpr inline
2989year_month_weekday
2990operator+(const months& dm, const year_month_weekday& ymwd) noexcept
2991{
2992 return ymwd + dm;
2993}
2994
2995template<class>
2996constexpr inline
2997year_month_weekday
2998operator-(const year_month_weekday& ymwd, const months& dm) noexcept
2999{
3000 return ymwd + (-dm);
3001}
3002
3003constexpr inline
3004year_month_weekday
3005operator+(const year_month_weekday& ymwd, const years& dy) noexcept
3006{
3007 return {ymwd.year()+dy, ymwd.month(), ymwd.weekday_indexed()};
3008}
3009
3010constexpr inline
3011year_month_weekday
3012operator+(const years& dy, const year_month_weekday& ymwd) noexcept
3013{
3014 return ymwd + dy;
3015}
3016
3017constexpr inline
3018year_month_weekday
3019operator-(const year_month_weekday& ymwd, const years& dy) noexcept
3020{
3021 return ymwd + (-dy);
3022}
3023
3024// year_month_weekday_last
3025
3026constexpr inline
3027year_month_weekday_last::year_month_weekday_last(const gul17::date::year& y,
3028 const gul17::date::month& m,
3029 const gul17::date::weekday_last& wdl) noexcept
3030 : y_(y)
3031 , m_(m)
3032 , wdl_(wdl)
3033 {}
3034
3035template<class>
3036constexpr inline
3037year_month_weekday_last&
3038year_month_weekday_last::operator+=(const months& m) noexcept
3039{
3040 *this = *this + m;
3041 return *this;
3042}
3043
3044template<class>
3045constexpr inline
3046year_month_weekday_last&
3047year_month_weekday_last::operator-=(const months& m) noexcept
3048{
3049 *this = *this - m;
3050 return *this;
3051}
3052
3053constexpr inline
3054year_month_weekday_last&
3055year_month_weekday_last::operator+=(const years& y) noexcept
3056{
3057 *this = *this + y;
3058 return *this;
3059}
3060
3061constexpr inline
3062year_month_weekday_last&
3063year_month_weekday_last::operator-=(const years& y) noexcept
3064{
3065 *this = *this - y;
3066 return *this;
3067}
3068
3069constexpr inline year year_month_weekday_last::year() const noexcept {return y_;}
3070constexpr inline month year_month_weekday_last::month() const noexcept {return m_;}
3071
3072constexpr inline
3073weekday
3074year_month_weekday_last::weekday() const noexcept
3075{
3076 return wdl_.weekday();
3077}
3078
3079constexpr inline
3080weekday_last
3081year_month_weekday_last::weekday_last() const noexcept
3082{
3083 return wdl_;
3084}
3085
3086constexpr inline
3087year_month_weekday_last::operator sys_days() const noexcept
3088{
3089 return sys_days{to_days()};
3090}
3091
3092constexpr inline
3093year_month_weekday_last::operator local_days() const noexcept
3094{
3095 return local_days{to_days()};
3096}
3097
3098constexpr inline bool
3099year_month_weekday_last::ok() const noexcept
3100{
3101 return y_.ok() && m_.ok() && wdl_.ok();
3102}
3103
3104constexpr inline
3105days
3106year_month_weekday_last::to_days() const noexcept
3107{
3108 auto const d = sys_days(y_/m_/last);
3109 return (d - (gul17::date::weekday{d} - wdl_.weekday())).time_since_epoch();
3110}
3111
3112constexpr inline bool
3113operator==(const year_month_weekday_last& x, const year_month_weekday_last& y) noexcept
3114{
3115 return x.year() == y.year() && x.month() == y.month() &&
3116 x.weekday_last() == y.weekday_last();
3117}
3118
3119constexpr inline bool
3120operator!=(const year_month_weekday_last& x, const year_month_weekday_last& y) noexcept
3121{
3122 return !(x == y);
3123}
3124
3125template<class CharT, class Traits>
3126inline
3127std::basic_ostream<CharT, Traits>&
3128operator<<(std::basic_ostream<CharT, Traits>& os, const year_month_weekday_last& ymwdl)
3129{
3130 detail::low_level_fmt(os, ymwdl.year()) << '/';
3131 detail::low_level_fmt(os, ymwdl.month()) << '/';
3132 detail::low_level_fmt(os, ymwdl.weekday_last());
3133 if (!ymwdl.ok())
3134 os << " is not a valid year_month_weekday_last";
3135 return os;
3136}
3137
3138template<class>
3139constexpr inline
3140year_month_weekday_last
3141operator+(const year_month_weekday_last& ymwdl, const months& dm) noexcept
3142{
3143 return (ymwdl.year() / ymwdl.month() + dm) / ymwdl.weekday_last();
3144}
3145
3146template<class>
3147constexpr inline
3148year_month_weekday_last
3149operator+(const months& dm, const year_month_weekday_last& ymwdl) noexcept
3150{
3151 return ymwdl + dm;
3152}
3153
3154template<class>
3155constexpr inline
3156year_month_weekday_last
3157operator-(const year_month_weekday_last& ymwdl, const months& dm) noexcept
3158{
3159 return ymwdl + (-dm);
3160}
3161
3162constexpr inline
3163year_month_weekday_last
3164operator+(const year_month_weekday_last& ymwdl, const years& dy) noexcept
3165{
3166 return {ymwdl.year()+dy, ymwdl.month(), ymwdl.weekday_last()};
3167}
3168
3169constexpr inline
3170year_month_weekday_last
3171operator+(const years& dy, const year_month_weekday_last& ymwdl) noexcept
3172{
3173 return ymwdl + dy;
3174}
3175
3176constexpr inline
3177year_month_weekday_last
3178operator-(const year_month_weekday_last& ymwdl, const years& dy) noexcept
3179{
3180 return ymwdl + (-dy);
3181}
3182
3183// year_month from operator/()
3184
3185constexpr inline
3186year_month
3187operator/(const year& y, const month& m) noexcept
3188{
3189 return {y, m};
3190}
3191
3192constexpr inline
3193year_month
3194operator/(const year& y, int m) noexcept
3195{
3196 return y / month(static_cast<unsigned>(m));
3197}
3198
3199// month_day from operator/()
3200
3201constexpr inline
3202month_day
3203operator/(const month& m, const day& d) noexcept
3204{
3205 return {m, d};
3206}
3207
3208constexpr inline
3209month_day
3210operator/(const day& d, const month& m) noexcept
3211{
3212 return m / d;
3213}
3214
3215constexpr inline
3216month_day
3217operator/(const month& m, int d) noexcept
3218{
3219 return m / day(static_cast<unsigned>(d));
3220}
3221
3222constexpr inline
3223month_day
3224operator/(int m, const day& d) noexcept
3225{
3226 return month(static_cast<unsigned>(m)) / d;
3227}
3228
3229constexpr inline month_day operator/(const day& d, int m) noexcept {return m / d;}
3230
3231// month_day_last from operator/()
3232
3233constexpr inline
3234month_day_last
3235operator/(const month& m, last_spec) noexcept
3236{
3237 return month_day_last{m};
3238}
3239
3240constexpr inline
3241month_day_last
3242operator/(last_spec, const month& m) noexcept
3243{
3244 return m/last;
3245}
3246
3247constexpr inline
3248month_day_last
3249operator/(int m, last_spec) noexcept
3250{
3251 return month(static_cast<unsigned>(m))/last;
3252}
3253
3254constexpr inline
3255month_day_last
3256operator/(last_spec, int m) noexcept
3257{
3258 return m/last;
3259}
3260
3261// month_weekday from operator/()
3262
3263constexpr inline
3264month_weekday
3265operator/(const month& m, const weekday_indexed& wdi) noexcept
3266{
3267 return {m, wdi};
3268}
3269
3270constexpr inline
3271month_weekday
3272operator/(const weekday_indexed& wdi, const month& m) noexcept
3273{
3274 return m / wdi;
3275}
3276
3277constexpr inline
3278month_weekday
3279operator/(int m, const weekday_indexed& wdi) noexcept
3280{
3281 return month(static_cast<unsigned>(m)) / wdi;
3282}
3283
3284constexpr inline
3285month_weekday
3286operator/(const weekday_indexed& wdi, int m) noexcept
3287{
3288 return m / wdi;
3289}
3290
3291// month_weekday_last from operator/()
3292
3293constexpr inline
3294month_weekday_last
3295operator/(const month& m, const weekday_last& wdl) noexcept
3296{
3297 return {m, wdl};
3298}
3299
3300constexpr inline
3301month_weekday_last
3302operator/(const weekday_last& wdl, const month& m) noexcept
3303{
3304 return m / wdl;
3305}
3306
3307constexpr inline
3308month_weekday_last
3309operator/(int m, const weekday_last& wdl) noexcept
3310{
3311 return month(static_cast<unsigned>(m)) / wdl;
3312}
3313
3314constexpr inline
3315month_weekday_last
3316operator/(const weekday_last& wdl, int m) noexcept
3317{
3318 return m / wdl;
3319}
3320
3321// year_month_day from operator/()
3322
3323constexpr inline
3324year_month_day
3325operator/(const year_month& ym, const day& d) noexcept
3326{
3327 return {ym.year(), ym.month(), d};
3328}
3329
3330constexpr inline
3331year_month_day
3332operator/(const year_month& ym, int d) noexcept
3333{
3334 return ym / day(static_cast<unsigned>(d));
3335}
3336
3337constexpr inline
3338year_month_day
3339operator/(const year& y, const month_day& md) noexcept
3340{
3341 return y / md.month() / md.day();
3342}
3343
3344constexpr inline
3345year_month_day
3346operator/(int y, const month_day& md) noexcept
3347{
3348 return year(y) / md;
3349}
3350
3351constexpr inline
3352year_month_day
3353operator/(const month_day& md, const year& y) noexcept
3354{
3355 return y / md;
3356}
3357
3358constexpr inline
3359year_month_day
3360operator/(const month_day& md, int y) noexcept
3361{
3362 return year(y) / md;
3363}
3364
3365// year_month_day_last from operator/()
3366
3367constexpr inline
3368year_month_day_last
3369operator/(const year_month& ym, last_spec) noexcept
3370{
3371 return {ym.year(), month_day_last{ym.month()}};
3372}
3373
3374constexpr inline
3375year_month_day_last
3376operator/(const year& y, const month_day_last& mdl) noexcept
3377{
3378 return {y, mdl};
3379}
3380
3381constexpr inline
3382year_month_day_last
3383operator/(int y, const month_day_last& mdl) noexcept
3384{
3385 return year(y) / mdl;
3386}
3387
3388constexpr inline
3389year_month_day_last
3390operator/(const month_day_last& mdl, const year& y) noexcept
3391{
3392 return y / mdl;
3393}
3394
3395constexpr inline
3396year_month_day_last
3397operator/(const month_day_last& mdl, int y) noexcept
3398{
3399 return year(y) / mdl;
3400}
3401
3402// year_month_weekday from operator/()
3403
3404constexpr inline
3405year_month_weekday
3406operator/(const year_month& ym, const weekday_indexed& wdi) noexcept
3407{
3408 return {ym.year(), ym.month(), wdi};
3409}
3410
3411constexpr inline
3412year_month_weekday
3413operator/(const year& y, const month_weekday& mwd) noexcept
3414{
3415 return {y, mwd.month(), mwd.weekday_indexed()};
3416}
3417
3418constexpr inline
3419year_month_weekday
3420operator/(int y, const month_weekday& mwd) noexcept
3421{
3422 return year(y) / mwd;
3423}
3424
3425constexpr inline
3426year_month_weekday
3427operator/(const month_weekday& mwd, const year& y) noexcept
3428{
3429 return y / mwd;
3430}
3431
3432constexpr inline
3433year_month_weekday
3434operator/(const month_weekday& mwd, int y) noexcept
3435{
3436 return year(y) / mwd;
3437}
3438
3439// year_month_weekday_last from operator/()
3440
3441constexpr inline
3442year_month_weekday_last
3443operator/(const year_month& ym, const weekday_last& wdl) noexcept
3444{
3445 return {ym.year(), ym.month(), wdl};
3446}
3447
3448constexpr inline
3449year_month_weekday_last
3450operator/(const year& y, const month_weekday_last& mwdl) noexcept
3451{
3452 return {y, mwdl.month(), mwdl.weekday_last()};
3453}
3454
3455constexpr inline
3456year_month_weekday_last
3457operator/(int y, const month_weekday_last& mwdl) noexcept
3458{
3459 return year(y) / mwdl;
3460}
3461
3462constexpr inline
3463year_month_weekday_last
3464operator/(const month_weekday_last& mwdl, const year& y) noexcept
3465{
3466 return y / mwdl;
3467}
3468
3469constexpr inline
3470year_month_weekday_last
3471operator/(const month_weekday_last& mwdl, int y) noexcept
3472{
3473 return year(y) / mwdl;
3474}
3475
3476template <class Duration>
3477struct fields;
3478
3479template <class CharT, class Traits, class Duration>
3480std::basic_ostream<CharT, Traits>&
3481to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
3482 const fields<Duration>& fds, const std::string* abbrev = nullptr,
3483 const std::chrono::seconds* offset_sec = nullptr);
3484
3485template <class CharT, class Traits, class Duration, class Alloc>
3486std::basic_istream<CharT, Traits>&
3487from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
3488 fields<Duration>& fds, std::basic_string<CharT, Traits, Alloc>* abbrev = nullptr,
3489 std::chrono::minutes* offset = nullptr);
3490
3491// hh_mm_ss
3492
3493namespace detail
3494{
3495
3496struct undocumented {explicit undocumented() = default;};
3497
3498// width<n>::value is the number of fractional decimal digits in 1/n
3499// width<0>::value and width<1>::value are defined to be 0
3500// If 1/n takes more than 18 fractional decimal digits,
3501// the result is truncated to 19.
3502// Example: width<2>::value == 1
3503// Example: width<3>::value == 19
3504// Example: width<4>::value == 2
3505// Example: width<10>::value == 1
3506// Example: width<1000>::value == 3
3507template <std::uint64_t n, std::uint64_t d, unsigned w = 0,
3508 bool should_continue = n%d != 0 && (w < 19)>
3509struct width
3510{
3511 static_assert(d > 0, "width called with zero denominator");
3512 static constexpr const unsigned value = 1 + width<n%d*10, d, w+1>::value;
3513};
3514
3515template <std::uint64_t n, std::uint64_t d, unsigned w>
3516struct width<n, d, w, false>
3517{
3518 static constexpr const unsigned value = 0;
3519};
3520
3521template <unsigned exp>
3522struct static_pow10
3523{
3524private:
3525 static constexpr const std::uint64_t h = static_pow10<exp/2>::value;
3526public:
3527 static constexpr const std::uint64_t value = h * h * (exp % 2 ? 10 : 1);
3528};
3529
3530template <>
3531struct static_pow10<0>
3532{
3533 static constexpr const std::uint64_t value = 1;
3534};
3535
3536template <class Duration>
3537class decimal_format_seconds
3538{
3539 using CT = typename std::common_type<Duration, std::chrono::seconds>::type;
3540 using rep = typename CT::rep;
3541 static unsigned constexpr const trial_width =
3542 detail::width<CT::period::num, CT::period::den>::value;
3543public:
3544 static unsigned constexpr const width = trial_width < 19 ? trial_width : 6u;
3545 using precision = std::chrono::duration<rep,
3546 std::ratio<1, static_pow10<width>::value>>;
3547
3548private:
3549 std::chrono::seconds s_;
3550 precision sub_s_;
3551
3552public:
3553 constexpr decimal_format_seconds()
3554 : s_()
3555 , sub_s_()
3556 {}
3557
3558 constexpr explicit decimal_format_seconds(const Duration& d) noexcept
3559 : s_(std::chrono::duration_cast<std::chrono::seconds>(d))
3560 , sub_s_(std::chrono::duration_cast<precision>(d - s_))
3561 {}
3562
3563 constexpr std::chrono::seconds& seconds() noexcept {return s_;}
3564 constexpr std::chrono::seconds seconds() const noexcept {return s_;}
3565 constexpr precision subseconds() const noexcept {return sub_s_;}
3566
3567 constexpr precision to_duration() const noexcept
3568 {
3569 return s_ + sub_s_;
3570 }
3571
3572 constexpr bool in_conventional_range() const noexcept
3573 {
3574 return sub_s_ < std::chrono::seconds{1} && s_ < std::chrono::minutes{1};
3575 }
3576
3577 template <class CharT, class Traits>
3578 friend
3579 std::basic_ostream<CharT, Traits>&
3580 operator<<(std::basic_ostream<CharT, Traits>& os, const decimal_format_seconds& x)
3581 {
3582 return x.print(os, std::chrono::treat_as_floating_point<rep>{});
3583 }
3584
3585 template <class CharT, class Traits>
3586 std::basic_ostream<CharT, Traits>&
3587 print(std::basic_ostream<CharT, Traits>& os, std::true_type) const
3588 {
3589 gul17::date::detail::save_ostream<CharT, Traits> _(os);
3590 std::chrono::duration<rep> d = s_ + sub_s_;
3591 if (d < std::chrono::seconds{10})
3592 os << '0';
3593 os.precision(width+6);
3594 os << std::fixed << d.count();
3595 return os;
3596 }
3597
3598 template <class CharT, class Traits>
3599 std::basic_ostream<CharT, Traits>&
3600 print(std::basic_ostream<CharT, Traits>& os, std::false_type) const
3601 {
3602 gul17::date::detail::save_ostream<CharT, Traits> _(os);
3603 os.fill('0');
3604 os.flags(std::ios::dec | std::ios::right);
3605 os.width(2);
3606 os << s_.count();
3607 if (width > 0)
3608 {
3609#if !ONLY_C_LOCALE
3610 os << std::use_facet<std::numpunct<CharT>>(os.getloc()).decimal_point();
3611#else
3612 os << '.';
3613#endif
3614 gul17::date::detail::save_ostream<CharT, Traits> _s(os);
3615 os.imbue(std::locale::classic());
3616 os.width(width);
3617 os << sub_s_.count();
3618 }
3619 return os;
3620 }
3621};
3622
3623template <class Rep, class Period>
3624inline constexpr
3625typename std::enable_if
3626 <
3627 std::numeric_limits<Rep>::is_signed,
3628 std::chrono::duration<Rep, Period>
3629 >::type
3630abs(std::chrono::duration<Rep, Period> d)
3631{
3632 return d >= d.zero() ? +d : -d;
3633}
3634
3635template <class Rep, class Period>
3636inline constexpr
3637typename std::enable_if
3638 <
3639 !std::numeric_limits<Rep>::is_signed,
3640 std::chrono::duration<Rep, Period>
3641 >::type
3642abs(std::chrono::duration<Rep, Period> d)
3643{
3644 return d;
3645}
3646
3647} // namespace detail
3648
3649template <class Duration>
3650class hh_mm_ss
3651{
3652 using dfs = detail::decimal_format_seconds<typename std::common_type<Duration,
3653 std::chrono::seconds>::type>;
3654
3655 std::chrono::hours h_;
3656 std::chrono::minutes m_;
3657 dfs s_;
3658 bool neg_;
3659
3660public:
3661 static unsigned constexpr const fractional_width = dfs::width;
3662 using precision = typename dfs::precision;
3663
3664 constexpr hh_mm_ss() noexcept
3665 : hh_mm_ss(Duration::zero())
3666 {}
3667
3668 constexpr explicit hh_mm_ss(Duration d) noexcept
3669 : h_(std::chrono::duration_cast<std::chrono::hours>(detail::abs(d)))
3670 , m_(std::chrono::duration_cast<std::chrono::minutes>(detail::abs(d)) - h_)
3671 , s_(detail::abs(d) - h_ - m_)
3672 , neg_(d < Duration::zero())
3673 {}
3674
3675 constexpr std::chrono::hours hours() const noexcept {return h_;}
3676 constexpr std::chrono::minutes minutes() const noexcept {return m_;}
3677 constexpr std::chrono::seconds seconds() const noexcept {return s_.seconds();}
3678 constexpr std::chrono::seconds&
3679 seconds(detail::undocumented) noexcept {return s_.seconds();}
3680 constexpr precision subseconds() const noexcept {return s_.subseconds();}
3681 constexpr bool is_negative() const noexcept {return neg_;}
3682
3683 constexpr explicit operator precision() const noexcept {return to_duration();}
3684 constexpr precision to_duration() const noexcept
3685 {return (s_.to_duration() + m_ + h_) * (1-2*neg_);}
3686
3687 constexpr bool in_conventional_range() const noexcept
3688 {
3689 return !neg_ && h_ < days{1} && m_ < std::chrono::hours{1} &&
3690 s_.in_conventional_range();
3691 }
3692
3693private:
3694
3695 template <class charT, class traits>
3696 friend
3697 std::basic_ostream<charT, traits>&
3698 operator<<(std::basic_ostream<charT, traits>& os, hh_mm_ss const& tod)
3699 {
3700 if (tod.is_negative())
3701 os << '-';
3702 if (tod.h_ < std::chrono::hours{10})
3703 os << '0';
3704 os << tod.h_.count() << ':';
3705 if (tod.m_ < std::chrono::minutes{10})
3706 os << '0';
3707 os << tod.m_.count() << ':' << tod.s_;
3708 return os;
3709 }
3710
3711 template <class CharT, class Traits, class Duration2>
3712 friend
3713 std::basic_ostream<CharT, Traits>&
3714 gul17::date::to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
3715 const fields<Duration2>& fds, const std::string* abbrev,
3716 const std::chrono::seconds* offset_sec);
3717
3718 template <class CharT, class Traits, class Duration2, class Alloc>
3719 friend
3720 std::basic_istream<CharT, Traits>&
3721 gul17::date::from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
3722 fields<Duration2>& fds,
3723 std::basic_string<CharT, Traits, Alloc>* abbrev, std::chrono::minutes* offset);
3724};
3725
3726inline constexpr bool
3727is_am(std::chrono::hours const& h) noexcept
3728{
3729 using std::chrono::hours;
3730 return hours{0} <= h && h < hours{12};
3731}
3732
3733inline constexpr bool
3734is_pm(std::chrono::hours const& h) noexcept
3735{
3736 using std::chrono::hours;
3737 return hours{12} <= h && h < hours{24};
3738}
3739
3740inline constexpr std::chrono::hours
3741make12(std::chrono::hours h) noexcept
3742{
3743 using std::chrono::hours;
3744 if (h < hours{12})
3745 {
3746 if (h == hours{0})
3747 h = hours{12};
3748 }
3749 else
3750 {
3751 if (h != hours{12})
3752 h = h - hours{12};
3753 }
3754 return h;
3755}
3756
3757inline constexpr std::chrono::hours
3758make24(std::chrono::hours h, bool is_pm) noexcept
3759{
3760 using std::chrono::hours;
3761 if (is_pm)
3762 {
3763 if (h != hours{12})
3764 h = h + hours{12};
3765 }
3766 else if (h == hours{12})
3767 h = hours{0};
3768 return h;
3769}
3770
3771template <class Duration>
3772using time_of_day = hh_mm_ss<Duration>;
3773
3774template <class Rep, class Period>
3775constexpr inline
3776hh_mm_ss<std::chrono::duration<Rep, Period>>
3777make_time(const std::chrono::duration<Rep, Period>& d)
3778{
3779 return hh_mm_ss<std::chrono::duration<Rep, Period>>(d);
3780}
3781
3782template <class CharT, class Traits, class Duration>
3783inline
3784typename std::enable_if
3785<
3786 std::ratio_less<typename Duration::period, days::period>::value
3787 , std::basic_ostream<CharT, Traits>&
3788>::type
3789operator<<(std::basic_ostream<CharT, Traits>& os, const sys_time<Duration>& tp)
3790{
3791 auto const dp = gul17::date::floor<days>(tp);
3792 return os << year_month_day(dp) << ' ' << make_time(tp-dp);
3793}
3794
3795template <class CharT, class Traits>
3796inline
3797std::basic_ostream<CharT, Traits>&
3798operator<<(std::basic_ostream<CharT, Traits>& os, const sys_days& dp)
3799{
3800 return os << year_month_day(dp);
3801}
3802
3803template <class CharT, class Traits, class Duration>
3804inline
3805std::basic_ostream<CharT, Traits>&
3806operator<<(std::basic_ostream<CharT, Traits>& os, const local_time<Duration>& ut)
3807{
3808 return (os << sys_time<Duration>{ut.time_since_epoch()});
3809}
3810
3811namespace detail
3812{
3813
3814template <class CharT, std::size_t N>
3815class string_literal;
3816
3817template <class CharT1, class CharT2, std::size_t N1, std::size_t N2>
3818inline constexpr
3819string_literal<typename std::conditional<sizeof(CharT2) <= sizeof(CharT1), CharT1, CharT2>::type,
3820 N1 + N2 - 1>
3821operator+(const string_literal<CharT1, N1>& x, const string_literal<CharT2, N2>& y) noexcept;
3822
3823template <class CharT, std::size_t N>
3824class string_literal
3825{
3826 CharT p_[N];
3827
3828 constexpr string_literal() noexcept
3829 : p_{}
3830 {}
3831
3832public:
3833 using const_iterator = const CharT*;
3834
3835 string_literal(string_literal const&) = default;
3836 string_literal& operator=(string_literal const&) = delete;
3837
3838 template <std::size_t N1 = 2,
3839 class = typename std::enable_if<N1 == N>::type>
3840 constexpr string_literal(CharT c) noexcept
3841 : p_{c}
3842 {
3843 }
3844
3845 template <std::size_t N1 = 3,
3846 class = typename std::enable_if<N1 == N>::type>
3847 constexpr string_literal(CharT c1, CharT c2) noexcept
3848 : p_{c1, c2}
3849 {
3850 }
3851
3852 template <std::size_t N1 = 4,
3853 class = typename std::enable_if<N1 == N>::type>
3854 constexpr string_literal(CharT c1, CharT c2, CharT c3) noexcept
3855 : p_{c1, c2, c3}
3856 {
3857 }
3858
3859 constexpr string_literal(const CharT(&a)[N]) noexcept
3860 : p_{}
3861 {
3862 for (std::size_t i = 0; i < N; ++i)
3863 p_[i] = a[i];
3864 }
3865
3866 template <class U = CharT,
3867 class = typename std::enable_if<(1 < sizeof(U))>::type>
3868 constexpr string_literal(const char(&a)[N]) noexcept
3869 : p_{}
3870 {
3871 for (std::size_t i = 0; i < N; ++i)
3872 p_[i] = a[i];
3873 }
3874
3875 template <class CharT2,
3876 class = typename std::enable_if<!std::is_same<CharT2, CharT>::value>::type>
3877 constexpr string_literal(string_literal<CharT2, N> const& a) noexcept
3878 : p_{}
3879 {
3880 for (std::size_t i = 0; i < N; ++i)
3881 p_[i] = a[i];
3882 }
3883
3884 constexpr const CharT* data() const noexcept {return p_;}
3885 constexpr std::size_t size() const noexcept {return N-1;}
3886
3887 constexpr const_iterator begin() const noexcept {return p_;}
3888 constexpr const_iterator end() const noexcept {return p_ + N-1;}
3889
3890 constexpr CharT const& operator[](std::size_t n) const noexcept
3891 {
3892 return p_[n];
3893 }
3894
3895 template <class Traits>
3896 friend
3897 std::basic_ostream<CharT, Traits>&
3898 operator<<(std::basic_ostream<CharT, Traits>& os, const string_literal& s)
3899 {
3900 return os << s.p_;
3901 }
3902
3903 template <class CharT1, class CharT2, std::size_t N1, std::size_t N2>
3904 friend
3905 constexpr
3906 string_literal<typename std::conditional<sizeof(CharT2) <= sizeof(CharT1), CharT1, CharT2>::type,
3907 N1 + N2 - 1>
3908 operator+(const string_literal<CharT1, N1>& x, const string_literal<CharT2, N2>& y) noexcept;
3909};
3910
3911template <class CharT>
3912constexpr inline
3913string_literal<CharT, 3>
3914operator+(const string_literal<CharT, 2>& x, const string_literal<CharT, 2>& y) noexcept
3915{
3916 return string_literal<CharT, 3>(x[0], y[0]);
3917}
3918
3919template <class CharT>
3920constexpr inline
3921string_literal<CharT, 4>
3922operator+(const string_literal<CharT, 3>& x, const string_literal<CharT, 2>& y) noexcept
3923{
3924 return string_literal<CharT, 4>(x[0], x[1], y[0]);
3925}
3926
3927template <class CharT1, class CharT2, std::size_t N1, std::size_t N2>
3928constexpr inline
3929string_literal<typename std::conditional<sizeof(CharT2) <= sizeof(CharT1), CharT1, CharT2>::type,
3930 N1 + N2 - 1>
3931operator+(const string_literal<CharT1, N1>& x, const string_literal<CharT2, N2>& y) noexcept
3932{
3933 using CT = typename std::conditional<sizeof(CharT2) <= sizeof(CharT1), CharT1, CharT2>::type;
3934
3935 string_literal<CT, N1 + N2 - 1> r;
3936 std::size_t i = 0;
3937 for (; i < N1-1; ++i)
3938 r.p_[i] = CT(x.p_[i]);
3939 for (std::size_t j = 0; j < N2; ++j, ++i)
3940 r.p_[i] = CT(y.p_[j]);
3941
3942 return r;
3943}
3944
3945
3946template <class CharT, class Traits, class Alloc, std::size_t N>
3947inline
3948std::basic_string<CharT, Traits, Alloc>
3949operator+(std::basic_string<CharT, Traits, Alloc> x, const string_literal<CharT, N>& y)
3950{
3951 x.append(y.data(), y.size());
3952 return x;
3953}
3954
3955#if __cplusplus >= 201402 && (!defined(__EDG_VERSION__) || __EDG_VERSION__ > 411)
3956
3957template <class CharT,
3958 class = std::enable_if_t<std::is_same<CharT, char>::value ||
3959 std::is_same<CharT, wchar_t>::value ||
3960 std::is_same<CharT, char16_t>::value ||
3961 std::is_same<CharT, char32_t>::value>>
3962constexpr inline
3963string_literal<CharT, 2>
3964msl(CharT c) noexcept
3965{
3966 return string_literal<CharT, 2>{c};
3967}
3968
3969constexpr inline
3970std::size_t
3971to_string_len(std::intmax_t i)
3972{
3973 std::size_t r = 0;
3974 do
3975 {
3976 i /= 10;
3977 ++r;
3978 } while (i > 0);
3979 return r;
3980}
3981
3982template <std::intmax_t N>
3983constexpr inline
3984std::enable_if_t
3985<
3986 N < 10,
3987 string_literal<char, to_string_len(N)+1>
3988>
3989msl() noexcept
3990{
3991 return msl(char(N % 10 + '0'));
3992}
3993
3994template <std::intmax_t N>
3995constexpr inline
3996std::enable_if_t
3997<
3998 10 <= N,
3999 string_literal<char, to_string_len(N)+1>
4000>
4001msl() noexcept
4002{
4003 return msl<N/10>() + msl(char(N % 10 + '0'));
4004}
4005
4006template <class CharT, std::intmax_t N, std::intmax_t D>
4007constexpr inline
4008std::enable_if_t
4009<
4010 std::ratio<N, D>::type::den != 1,
4011 string_literal<CharT, to_string_len(std::ratio<N, D>::type::num) +
4012 to_string_len(std::ratio<N, D>::type::den) + 4>
4013>
4014msl(std::ratio<N, D>) noexcept
4015{
4016 using R = typename std::ratio<N, D>::type;
4017 return msl(CharT{'['}) + msl<R::num>() + msl(CharT{'/'}) +
4018 msl<R::den>() + msl(CharT{']'});
4019}
4020
4021template <class CharT, std::intmax_t N, std::intmax_t D>
4022constexpr inline
4023std::enable_if_t
4024<
4025 std::ratio<N, D>::type::den == 1,
4026 string_literal<CharT, to_string_len(std::ratio<N, D>::type::num) + 3>
4027>
4028msl(std::ratio<N, D>) noexcept
4029{
4030 using R = typename std::ratio<N, D>::type;
4031 return msl(CharT{'['}) + msl<R::num>() + msl(CharT{']'});
4032}
4033
4034
4035#else // __cplusplus < 201402 || (defined(__EDG_VERSION__) && __EDG_VERSION__ <= 411)
4036
4037inline
4038std::string
4039to_string(std::uint64_t x)
4040{
4041 return std::to_string(x);
4042}
4043
4044template <class CharT>
4045inline
4046std::basic_string<CharT>
4047to_string(std::uint64_t x)
4048{
4049 auto y = std::to_string(x);
4050 return std::basic_string<CharT>(y.begin(), y.end());
4051}
4052
4053template <class CharT, std::intmax_t N, std::intmax_t D>
4054inline
4055typename std::enable_if
4056<
4057 std::ratio<N, D>::type::den != 1,
4058 std::basic_string<CharT>
4059>::type
4060msl(std::ratio<N, D>)
4061{
4062 using R = typename std::ratio<N, D>::type;
4063 return std::basic_string<CharT>(1, '[') + to_string<CharT>(R::num) + CharT{'/'} +
4064 to_string<CharT>(R::den) + CharT{']'};
4065}
4066
4067template <class CharT, std::intmax_t N, std::intmax_t D>
4068inline
4069typename std::enable_if
4070<
4071 std::ratio<N, D>::type::den == 1,
4072 std::basic_string<CharT>
4073>::type
4074msl(std::ratio<N, D>)
4075{
4076 using R = typename std::ratio<N, D>::type;
4077 return std::basic_string<CharT>(1, '[') + to_string<CharT>(R::num) + CharT{']'};
4078}
4079
4080#endif // __cplusplus < 201402 || (defined(__EDG_VERSION__) && __EDG_VERSION__ <= 411)
4081
4082template <class CharT>
4083constexpr inline
4084string_literal<CharT, 2>
4085msl(std::atto) noexcept
4086{
4087 return string_literal<CharT, 2>{'a'};
4088}
4089
4090template <class CharT>
4091constexpr inline
4092string_literal<CharT, 2>
4093msl(std::femto) noexcept
4094{
4095 return string_literal<CharT, 2>{'f'};
4096}
4097
4098template <class CharT>
4099constexpr inline
4100string_literal<CharT, 2>
4101msl(std::pico) noexcept
4102{
4103 return string_literal<CharT, 2>{'p'};
4104}
4105
4106template <class CharT>
4107constexpr inline
4108string_literal<CharT, 2>
4109msl(std::nano) noexcept
4110{
4111 return string_literal<CharT, 2>{'n'};
4112}
4113
4114template <class CharT>
4115constexpr inline
4116typename std::enable_if
4117<
4118 std::is_same<CharT, char>::value,
4119 string_literal<char, 3>
4120>::type
4121msl(std::micro) noexcept
4122{
4123 return string_literal<char, 3>{'\xC2', '\xB5'};
4124}
4125
4126template <class CharT>
4127constexpr inline
4128typename std::enable_if
4129<
4130 !std::is_same<CharT, char>::value,
4131 string_literal<CharT, 2>
4132>::type
4133msl(std::micro) noexcept
4134{
4135 return string_literal<CharT, 2>{CharT{static_cast<unsigned char>('\xB5')}};
4136}
4137
4138template <class CharT>
4139constexpr inline
4140string_literal<CharT, 2>
4141msl(std::milli) noexcept
4142{
4143 return string_literal<CharT, 2>{'m'};
4144}
4145
4146template <class CharT>
4147constexpr inline
4148string_literal<CharT, 2>
4149msl(std::centi) noexcept
4150{
4151 return string_literal<CharT, 2>{'c'};
4152}
4153
4154template <class CharT>
4155constexpr inline
4156string_literal<CharT, 3>
4157msl(std::deca) noexcept
4158{
4159 return string_literal<CharT, 3>{'d', 'a'};
4160}
4161
4162template <class CharT>
4163constexpr inline
4164string_literal<CharT, 2>
4165msl(std::deci) noexcept
4166{
4167 return string_literal<CharT, 2>{'d'};
4168}
4169
4170template <class CharT>
4171constexpr inline
4172string_literal<CharT, 2>
4173msl(std::hecto) noexcept
4174{
4175 return string_literal<CharT, 2>{'h'};
4176}
4177
4178template <class CharT>
4179constexpr inline
4180string_literal<CharT, 2>
4181msl(std::kilo) noexcept
4182{
4183 return string_literal<CharT, 2>{'k'};
4184}
4185
4186template <class CharT>
4187constexpr inline
4188string_literal<CharT, 2>
4189msl(std::mega) noexcept
4190{
4191 return string_literal<CharT, 2>{'M'};
4192}
4193
4194template <class CharT>
4195constexpr inline
4196string_literal<CharT, 2>
4197msl(std::giga) noexcept
4198{
4199 return string_literal<CharT, 2>{'G'};
4200}
4201
4202template <class CharT>
4203constexpr inline
4204string_literal<CharT, 2>
4205msl(std::tera) noexcept
4206{
4207 return string_literal<CharT, 2>{'T'};
4208}
4209
4210template <class CharT>
4211constexpr inline
4212string_literal<CharT, 2>
4213msl(std::peta) noexcept
4214{
4215 return string_literal<CharT, 2>{'P'};
4216}
4217
4218template <class CharT>
4219constexpr inline
4220string_literal<CharT, 2>
4221msl(std::exa) noexcept
4222{
4223 return string_literal<CharT, 2>{'E'};
4224}
4225
4226template <class CharT, class Period>
4227constexpr inline
4228auto
4229get_units(Period p)
4230 -> decltype(msl<CharT>(p) + string_literal<CharT, 2>{'s'})
4231{
4232 return msl<CharT>(p) + string_literal<CharT, 2>{'s'};
4233}
4234
4235template <class CharT>
4236constexpr inline
4237string_literal<CharT, 2>
4238get_units(std::ratio<1>)
4239{
4240 return string_literal<CharT, 2>{'s'};
4241}
4242
4243template <class CharT>
4244constexpr inline
4245string_literal<CharT, 2>
4246get_units(std::ratio<3600>)
4247{
4248 return string_literal<CharT, 2>{'h'};
4249}
4250
4251template <class CharT>
4252constexpr inline
4253string_literal<CharT, 4>
4254get_units(std::ratio<60>)
4255{
4256 return string_literal<CharT, 4>{'m', 'i', 'n'};
4257}
4258
4259template <class CharT>
4260constexpr inline
4261string_literal<CharT, 2>
4262get_units(std::ratio<86400>)
4263{
4264 return string_literal<CharT, 2>{'d'};
4265}
4266
4267template <class CharT, class Traits = std::char_traits<CharT>>
4268struct make_string;
4269
4270template <>
4271struct make_string<char>
4272{
4273 template <class Rep>
4274 static
4275 std::string
4276 from(Rep n)
4277 {
4278 return std::to_string(n);
4279 }
4280};
4281
4282template <class Traits>
4283struct make_string<char, Traits>
4284{
4285 template <class Rep>
4286 static
4287 std::basic_string<char, Traits>
4288 from(Rep n)
4289 {
4290 auto s = std::to_string(n);
4291 return std::basic_string<char, Traits>(s.begin(), s.end());
4292 }
4293};
4294
4295template <>
4296struct make_string<wchar_t>
4297{
4298 template <class Rep>
4299 static
4300 std::wstring
4301 from(Rep n)
4302 {
4303 return std::to_wstring(n);
4304 }
4305};
4306
4307template <class Traits>
4308struct make_string<wchar_t, Traits>
4309{
4310 template <class Rep>
4311 static
4312 std::basic_string<wchar_t, Traits>
4313 from(Rep n)
4314 {
4315 auto s = std::to_wstring(n);
4316 return std::basic_string<wchar_t, Traits>(s.begin(), s.end());
4317 }
4318};
4319
4320} // namespace detail
4321
4322// to_stream
4323
4324constexpr const year nanyear{-32768};
4325
4326template <class Duration>
4327struct fields
4328{
4329 year_month_day ymd{nanyear/0/0};
4330 weekday wd{8u};
4331 hh_mm_ss<Duration> tod{};
4332 bool has_tod = false;
4333
4334#if !defined(__clang__) && defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ <= 409)
4335 fields() : ymd{nanyear/0/0}, wd{8u}, tod{}, has_tod{false} {}
4336#else
4337 fields() = default;
4338#endif
4339
4340 fields(year_month_day ymd_) : ymd(ymd_) {}
4341 fields(weekday wd_) : wd(wd_) {}
4342 fields(hh_mm_ss<Duration> tod_) : tod(tod_), has_tod(true) {}
4343
4344 fields(year_month_day ymd_, weekday wd_) : ymd(ymd_), wd(wd_) {}
4345 fields(year_month_day ymd_, hh_mm_ss<Duration> tod_) : ymd(ymd_), tod(tod_),
4346 has_tod(true) {}
4347
4348 fields(weekday wd_, hh_mm_ss<Duration> tod_) : wd(wd_), tod(tod_), has_tod(true) {}
4349
4350 fields(year_month_day ymd_, weekday wd_, hh_mm_ss<Duration> tod_)
4351 : ymd(ymd_)
4352 , wd(wd_)
4353 , tod(tod_)
4354 , has_tod(true)
4355 {}
4356};
4357
4358namespace detail
4359{
4360
4361template <class CharT, class Traits, class Duration>
4362unsigned
4363extract_weekday(std::basic_ostream<CharT, Traits>& os, const fields<Duration>& fds)
4364{
4365 if (!fds.ymd.ok() && !fds.wd.ok())
4366 {
4367 // fds does not contain a valid weekday
4368 os.setstate(std::ios::failbit);
4369 return 8;
4370 }
4371 weekday wd;
4372 if (fds.ymd.ok())
4373 {
4374 wd = weekday{sys_days(fds.ymd)};
4375 if (fds.wd.ok() && wd != fds.wd)
4376 {
4377 // fds.ymd and fds.wd are inconsistent
4378 os.setstate(std::ios::failbit);
4379 return 8;
4380 }
4381 }
4382 else
4383 wd = fds.wd;
4384 return static_cast<unsigned>((wd - Sunday).count());
4385}
4386
4387template <class CharT, class Traits, class Duration>
4388unsigned
4389extract_month(std::basic_ostream<CharT, Traits>& os, const fields<Duration>& fds)
4390{
4391 if (!fds.ymd.month().ok())
4392 {
4393 // fds does not contain a valid month
4394 os.setstate(std::ios::failbit);
4395 return 0;
4396 }
4397 return static_cast<unsigned>(fds.ymd.month());
4398}
4399
4400} // namespace detail
4401
4402#if ONLY_C_LOCALE
4403
4404namespace detail
4405{
4406
4407inline
4408std::pair<const std::string*, const std::string*>
4409weekday_names()
4410{
4411 static const std::string nm[] =
4412 {
4413 "Sunday",
4414 "Monday",
4415 "Tuesday",
4416 "Wednesday",
4417 "Thursday",
4418 "Friday",
4419 "Saturday",
4420 "Sun",
4421 "Mon",
4422 "Tue",
4423 "Wed",
4424 "Thu",
4425 "Fri",
4426 "Sat"
4427 };
4428 return std::make_pair(nm, nm+sizeof(nm)/sizeof(nm[0]));
4429}
4430
4431inline
4432std::pair<const std::string*, const std::string*>
4433month_names()
4434{
4435 static const std::string nm[] =
4436 {
4437 "January",
4438 "February",
4439 "March",
4440 "April",
4441 "May",
4442 "June",
4443 "July",
4444 "August",
4445 "September",
4446 "October",
4447 "November",
4448 "December",
4449 "Jan",
4450 "Feb",
4451 "Mar",
4452 "Apr",
4453 "May",
4454 "Jun",
4455 "Jul",
4456 "Aug",
4457 "Sep",
4458 "Oct",
4459 "Nov",
4460 "Dec"
4461 };
4462 return std::make_pair(nm, nm+sizeof(nm)/sizeof(nm[0]));
4463}
4464
4465inline
4466std::pair<const std::string*, const std::string*>
4467ampm_names()
4468{
4469 static const std::string nm[] =
4470 {
4471 "AM",
4472 "PM"
4473 };
4474 return std::make_pair(nm, nm+sizeof(nm)/sizeof(nm[0]));
4475}
4476
4477template <class CharT, class Traits, class FwdIter>
4478FwdIter
4479scan_keyword(std::basic_istream<CharT, Traits>& is, FwdIter kb, FwdIter ke)
4480{
4481 size_t nkw = static_cast<size_t>(std::distance(kb, ke));
4482 const unsigned char doesnt_match = '\0';
4483 const unsigned char might_match = '\1';
4484 const unsigned char does_match = '\2';
4485 unsigned char statbuf[100];
4486 unsigned char* status = statbuf;
4487 std::unique_ptr<unsigned char, void(*)(void*)> stat_hold(0, free);
4488 if (nkw > sizeof(statbuf))
4489 {
4490 status = (unsigned char*)std::malloc(nkw);
4491 if (status == nullptr)
4492 throw std::bad_alloc();
4493 stat_hold.reset(status);
4494 }
4495 size_t n_might_match = nkw; // At this point, any keyword might match
4496 size_t n_does_match = 0; // but none of them definitely do
4497 // Initialize all statuses to might_match, except for "" keywords are does_match
4498 unsigned char* st = status;
4499 for (auto ky = kb; ky != ke; ++ky, ++st)
4500 {
4501 if (!ky->empty())
4502 *st = might_match;
4503 else
4504 {
4505 *st = does_match;
4506 --n_might_match;
4507 ++n_does_match;
4508 }
4509 }
4510 // While there might be a match, test keywords against the next CharT
4511 for (size_t indx = 0; is && n_might_match > 0; ++indx)
4512 {
4513 // Peek at the next CharT but don't consume it
4514 auto ic = is.peek();
4515 if (ic == EOF)
4516 {
4517 is.setstate(std::ios::eofbit);
4518 break;
4519 }
4520 auto c = static_cast<char>(toupper(static_cast<unsigned char>(ic)));
4521 bool consume = false;
4522 // For each keyword which might match, see if the indx character is c
4523 // If a match if found, consume c
4524 // If a match is found, and that is the last character in the keyword,
4525 // then that keyword matches.
4526 // If the keyword doesn't match this character, then change the keyword
4527 // to doesn't match
4528 st = status;
4529 for (auto ky = kb; ky != ke; ++ky, ++st)
4530 {
4531 if (*st == might_match)
4532 {
4533 if (c == static_cast<char>(toupper(static_cast<unsigned char>((*ky)[indx]))))
4534 {
4535 consume = true;
4536 if (ky->size() == indx+1)
4537 {
4538 *st = does_match;
4539 --n_might_match;
4540 ++n_does_match;
4541 }
4542 }
4543 else
4544 {
4545 *st = doesnt_match;
4546 --n_might_match;
4547 }
4548 }
4549 }
4550 // consume if we matched a character
4551 if (consume)
4552 {
4553 (void)is.get();
4554 // If we consumed a character and there might be a matched keyword that
4555 // was marked matched on a previous iteration, then such keywords
4556 // are now marked as not matching.
4557 if (n_might_match + n_does_match > 1)
4558 {
4559 st = status;
4560 for (auto ky = kb; ky != ke; ++ky, ++st)
4561 {
4562 if (*st == does_match && ky->size() != indx+1)
4563 {
4564 *st = doesnt_match;
4565 --n_does_match;
4566 }
4567 }
4568 }
4569 }
4570 }
4571 // We've exited the loop because we hit eof and/or we have no more "might matches".
4572 // Return the first matching result
4573 for (st = status; kb != ke; ++kb, ++st)
4574 if (*st == does_match)
4575 break;
4576 if (kb == ke)
4577 is.setstate(std::ios::failbit);
4578 return kb;
4579}
4580
4581} // namespace detail
4582
4583#endif // ONLY_C_LOCALE
4584
4585template <class CharT, class Traits, class Duration>
4586std::basic_ostream<CharT, Traits>&
4587to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
4588 const fields<Duration>& fds, const std::string* abbrev,
4589 const std::chrono::seconds* offset_sec)
4590{
4591#if ONLY_C_LOCALE
4592 using detail::weekday_names;
4593 using detail::month_names;
4594 using detail::ampm_names;
4595#endif
4596 using detail::save_ostream;
4597 using detail::get_units;
4598 using detail::extract_weekday;
4599 using detail::extract_month;
4600 using std::ios;
4601 using std::chrono::duration_cast;
4602 using std::chrono::seconds;
4603 using std::chrono::minutes;
4604 using std::chrono::hours;
4605 gul17::date::detail::save_ostream<CharT, Traits> ss(os);
4606 os.fill(' ');
4607 os.flags(std::ios::skipws | std::ios::dec);
4608 os.width(0);
4609 tm tm{};
4610 bool insert_negative = fds.has_tod && fds.tod.to_duration() < Duration::zero();
4611#if !ONLY_C_LOCALE
4612 auto& facet = std::use_facet<std::time_put<CharT>>(os.getloc());
4613#endif
4614 const CharT* command = nullptr;
4615 CharT modified = CharT{};
4616 for (; *fmt; ++fmt)
4617 {
4618 switch (*fmt)
4619 {
4620 case 'a':
4621 case 'A':
4622 if (command)
4623 {
4624 if (modified == CharT{})
4625 {
4626 tm.tm_wday = static_cast<int>(extract_weekday(os, fds));
4627 if (os.fail())
4628 return os;
4629#if !ONLY_C_LOCALE
4630 const CharT f[] = {'%', *fmt};
4631 facet.put(os, os, os.fill(), &tm, std::begin(f), std::end(f));
4632#else // ONLY_C_LOCALE
4633 os << weekday_names().first[tm.tm_wday+7*(*fmt == 'a')];
4634#endif // ONLY_C_LOCALE
4635 }
4636 else
4637 {
4638 os << CharT{'%'} << modified << *fmt;
4639 modified = CharT{};
4640 }
4641 command = nullptr;
4642 }
4643 else
4644 os << *fmt;
4645 break;
4646 case 'b':
4647 case 'B':
4648 case 'h':
4649 if (command)
4650 {
4651 if (modified == CharT{})
4652 {
4653 tm.tm_mon = static_cast<int>(extract_month(os, fds)) - 1;
4654#if !ONLY_C_LOCALE
4655 const CharT f[] = {'%', *fmt};
4656 facet.put(os, os, os.fill(), &tm, std::begin(f), std::end(f));
4657#else // ONLY_C_LOCALE
4658 os << month_names().first[tm.tm_mon+12*(*fmt != 'B')];
4659#endif // ONLY_C_LOCALE
4660 }
4661 else
4662 {
4663 os << CharT{'%'} << modified << *fmt;
4664 modified = CharT{};
4665 }
4666 command = nullptr;
4667 }
4668 else
4669 os << *fmt;
4670 break;
4671 case 'c':
4672 case 'x':
4673 if (command)
4674 {
4675 if (modified == CharT{'O'})
4676 os << CharT{'%'} << modified << *fmt;
4677 else
4678 {
4679 if (!fds.ymd.ok())
4680 os.setstate(std::ios::failbit);
4681 if (*fmt == 'c' && !fds.has_tod)
4682 os.setstate(std::ios::failbit);
4683#if !ONLY_C_LOCALE
4684 tm = std::tm{};
4685 auto const& ymd = fds.ymd;
4686 auto ld = local_days(ymd);
4687 if (*fmt == 'c')
4688 {
4689 tm.tm_sec = static_cast<int>(fds.tod.seconds().count());
4690 tm.tm_min = static_cast<int>(fds.tod.minutes().count());
4691 tm.tm_hour = static_cast<int>(fds.tod.hours().count());
4692 }
4693 tm.tm_mday = static_cast<int>(static_cast<unsigned>(ymd.day()));
4694 tm.tm_mon = static_cast<int>(extract_month(os, fds) - 1);
4695 tm.tm_year = static_cast<int>(ymd.year()) - 1900;
4696 tm.tm_wday = static_cast<int>(extract_weekday(os, fds));
4697 if (os.fail())
4698 return os;
4699 tm.tm_yday = static_cast<int>((ld - local_days(ymd.year()/1/1)).count());
4700 CharT f[3] = {'%'};
4701 auto fe = std::begin(f) + 1;
4702 if (modified == CharT{'E'})
4703 *fe++ = modified;
4704 *fe++ = *fmt;
4705 facet.put(os, os, os.fill(), &tm, std::begin(f), fe);
4706#else // ONLY_C_LOCALE
4707 if (*fmt == 'c')
4708 {
4709 auto wd = static_cast<int>(extract_weekday(os, fds));
4710 os << weekday_names().first[static_cast<unsigned>(wd)+7]
4711 << ' ';
4712 os << month_names().first[extract_month(os, fds)-1+12] << ' ';
4713 auto d = static_cast<int>(static_cast<unsigned>(fds.ymd.day()));
4714 if (d < 10)
4715 os << ' ';
4716 os << d << ' '
4717 << make_time(duration_cast<seconds>(fds.tod.to_duration()))
4718 << ' ' << fds.ymd.year();
4719
4720 }
4721 else // *fmt == 'x'
4722 {
4723 auto const& ymd = fds.ymd;
4724 save_ostream<CharT, Traits> _(os);
4725 os.fill('0');
4726 os.flags(std::ios::dec | std::ios::right);
4727 os.width(2);
4728 os << static_cast<unsigned>(ymd.month()) << CharT{'/'};
4729 os.width(2);
4730 os << static_cast<unsigned>(ymd.day()) << CharT{'/'};
4731 os.width(2);
4732 os << static_cast<int>(ymd.year()) % 100;
4733 }
4734#endif // ONLY_C_LOCALE
4735 }
4736 command = nullptr;
4737 modified = CharT{};
4738 }
4739 else
4740 os << *fmt;
4741 break;
4742 case 'C':
4743 if (command)
4744 {
4745 if (modified == CharT{'O'})
4746 os << CharT{'%'} << modified << *fmt;
4747 else
4748 {
4749 if (!fds.ymd.year().ok())
4750 os.setstate(std::ios::failbit);
4751 auto y = static_cast<int>(fds.ymd.year());
4752#if !ONLY_C_LOCALE
4753 if (modified == CharT{})
4754#endif
4755 {
4756 save_ostream<CharT, Traits> _(os);
4757 os.fill('0');
4758 os.flags(std::ios::dec | std::ios::right);
4759 if (y >= 0)
4760 {
4761 os.width(2);
4762 os << y/100;
4763 }
4764 else
4765 {
4766 os << CharT{'-'};
4767 os.width(2);
4768 os << -(y-99)/100;
4769 }
4770 }
4771#if !ONLY_C_LOCALE
4772 else if (modified == CharT{'E'})
4773 {
4774 tm.tm_year = y - 1900;
4775 CharT f[3] = {'%', 'E', 'C'};
4776 facet.put(os, os, os.fill(), &tm, std::begin(f), std::end(f));
4777 }
4778#endif
4779 }
4780 command = nullptr;
4781 modified = CharT{};
4782 }
4783 else
4784 os << *fmt;
4785 break;
4786 case 'd':
4787 case 'e':
4788 if (command)
4789 {
4790 if (modified == CharT{'E'})
4791 os << CharT{'%'} << modified << *fmt;
4792 else
4793 {
4794 if (!fds.ymd.day().ok())
4795 os.setstate(std::ios::failbit);
4796 auto d = static_cast<int>(static_cast<unsigned>(fds.ymd.day()));
4797#if !ONLY_C_LOCALE
4798 if (modified == CharT{})
4799#endif
4800 {
4801 save_ostream<CharT, Traits> _(os);
4802 if (*fmt == CharT{'d'})
4803 os.fill('0');
4804 else
4805 os.fill(' ');
4806 os.flags(std::ios::dec | std::ios::right);
4807 os.width(2);
4808 os << d;
4809 }
4810#if !ONLY_C_LOCALE
4811 else if (modified == CharT{'O'})
4812 {
4813 tm.tm_mday = d;
4814 CharT f[3] = {'%', 'O', *fmt};
4815 facet.put(os, os, os.fill(), &tm, std::begin(f), std::end(f));
4816 }
4817#endif
4818 }
4819 command = nullptr;
4820 modified = CharT{};
4821 }
4822 else
4823 os << *fmt;
4824 break;
4825 case 'D':
4826 if (command)
4827 {
4828 if (modified == CharT{})
4829 {
4830 if (!fds.ymd.ok())
4831 os.setstate(std::ios::failbit);
4832 auto const& ymd = fds.ymd;
4833 save_ostream<CharT, Traits> _(os);
4834 os.fill('0');
4835 os.flags(std::ios::dec | std::ios::right);
4836 os.width(2);
4837 os << static_cast<unsigned>(ymd.month()) << CharT{'/'};
4838 os.width(2);
4839 os << static_cast<unsigned>(ymd.day()) << CharT{'/'};
4840 os.width(2);
4841 os << static_cast<int>(ymd.year()) % 100;
4842 }
4843 else
4844 {
4845 os << CharT{'%'} << modified << *fmt;
4846 modified = CharT{};
4847 }
4848 command = nullptr;
4849 }
4850 else
4851 os << *fmt;
4852 break;
4853 case 'F':
4854 if (command)
4855 {
4856 if (modified == CharT{})
4857 {
4858 if (!fds.ymd.ok())
4859 os.setstate(std::ios::failbit);
4860 auto const& ymd = fds.ymd;
4861 save_ostream<CharT, Traits> _(os);
4862 os.imbue(std::locale::classic());
4863 os.fill('0');
4864 os.flags(std::ios::dec | std::ios::right);
4865 os.width(4);
4866 os << static_cast<int>(ymd.year()) << CharT{'-'};
4867 os.width(2);
4868 os << static_cast<unsigned>(ymd.month()) << CharT{'-'};
4869 os.width(2);
4870 os << static_cast<unsigned>(ymd.day());
4871 }
4872 else
4873 {
4874 os << CharT{'%'} << modified << *fmt;
4875 modified = CharT{};
4876 }
4877 command = nullptr;
4878 }
4879 else
4880 os << *fmt;
4881 break;
4882 case 'g':
4883 case 'G':
4884 if (command)
4885 {
4886 if (modified == CharT{})
4887 {
4888 if (!fds.ymd.ok())
4889 os.setstate(std::ios::failbit);
4890 auto ld = local_days(fds.ymd);
4891 auto y = year_month_day{ld + days{3}}.year();
4892 auto start = local_days((y-years{1})/December/Thursday[last]) +
4893 (Monday-Thursday);
4894 if (ld < start)
4895 --y;
4896 if (*fmt == CharT{'G'})
4897 os << y;
4898 else
4899 {
4900 save_ostream<CharT, Traits> _(os);
4901 os.fill('0');
4902 os.flags(std::ios::dec | std::ios::right);
4903 os.width(2);
4904 os << std::abs(static_cast<int>(y)) % 100;
4905 }
4906 }
4907 else
4908 {
4909 os << CharT{'%'} << modified << *fmt;
4910 modified = CharT{};
4911 }
4912 command = nullptr;
4913 }
4914 else
4915 os << *fmt;
4916 break;
4917 case 'H':
4918 case 'I':
4919 if (command)
4920 {
4921 if (modified == CharT{'E'})
4922 os << CharT{'%'} << modified << *fmt;
4923 else
4924 {
4925 if (!fds.has_tod)
4926 os.setstate(std::ios::failbit);
4927 if (insert_negative)
4928 {
4929 os << '-';
4930 insert_negative = false;
4931 }
4932 auto hms = fds.tod;
4933#if !ONLY_C_LOCALE
4934 if (modified == CharT{})
4935#endif
4936 {
4937 auto h = *fmt == CharT{'I'} ? gul17::date::make12(hms.hours()) : hms.hours();
4938 if (h < hours{10})
4939 os << CharT{'0'};
4940 os << h.count();
4941 }
4942#if !ONLY_C_LOCALE
4943 else if (modified == CharT{'O'})
4944 {
4945 const CharT f[] = {'%', modified, *fmt};
4946 tm.tm_hour = static_cast<int>(hms.hours().count());
4947 facet.put(os, os, os.fill(), &tm, std::begin(f), std::end(f));
4948 }
4949#endif
4950 }
4951 modified = CharT{};
4952 command = nullptr;
4953 }
4954 else
4955 os << *fmt;
4956 break;
4957 case 'j':
4958 if (command)
4959 {
4960 if (modified == CharT{})
4961 {
4962 if (fds.ymd.ok() || fds.has_tod)
4963 {
4964 days doy;
4965 if (fds.ymd.ok())
4966 {
4967 auto ld = local_days(fds.ymd);
4968 auto y = fds.ymd.year();
4969 doy = ld - local_days(y/January/1) + days{1};
4970 }
4971 else
4972 {
4973 doy = duration_cast<days>(fds.tod.to_duration());
4974 }
4975 save_ostream<CharT, Traits> _(os);
4976 os.fill('0');
4977 os.flags(std::ios::dec | std::ios::right);
4978 os.width(3);
4979 os << doy.count();
4980 }
4981 else
4982 {
4983 os.setstate(std::ios::failbit);
4984 }
4985 }
4986 else
4987 {
4988 os << CharT{'%'} << modified << *fmt;
4989 modified = CharT{};
4990 }
4991 command = nullptr;
4992 }
4993 else
4994 os << *fmt;
4995 break;
4996 case 'm':
4997 if (command)
4998 {
4999 if (modified == CharT{'E'})
5000 os << CharT{'%'} << modified << *fmt;
5001 else
5002 {
5003 if (!fds.ymd.month().ok())
5004 os.setstate(std::ios::failbit);
5005 auto m = static_cast<unsigned>(fds.ymd.month());
5006#if !ONLY_C_LOCALE
5007 if (modified == CharT{})
5008#endif
5009 {
5010 if (m < 10)
5011 os << CharT{'0'};
5012 os << m;
5013 }
5014#if !ONLY_C_LOCALE
5015 else if (modified == CharT{'O'})
5016 {
5017 const CharT f[] = {'%', modified, *fmt};
5018 tm.tm_mon = static_cast<int>(m-1);
5019 facet.put(os, os, os.fill(), &tm, std::begin(f), std::end(f));
5020 }
5021#endif
5022 }
5023 modified = CharT{};
5024 command = nullptr;
5025 }
5026 else
5027 os << *fmt;
5028 break;
5029 case 'M':
5030 if (command)
5031 {
5032 if (modified == CharT{'E'})
5033 os << CharT{'%'} << modified << *fmt;
5034 else
5035 {
5036 if (!fds.has_tod)
5037 os.setstate(std::ios::failbit);
5038 if (insert_negative)
5039 {
5040 os << '-';
5041 insert_negative = false;
5042 }
5043#if !ONLY_C_LOCALE
5044 if (modified == CharT{})
5045#endif
5046 {
5047 if (fds.tod.minutes() < minutes{10})
5048 os << CharT{'0'};
5049 os << fds.tod.minutes().count();
5050 }
5051#if !ONLY_C_LOCALE
5052 else if (modified == CharT{'O'})
5053 {
5054 const CharT f[] = {'%', modified, *fmt};
5055 tm.tm_min = static_cast<int>(fds.tod.minutes().count());
5056 facet.put(os, os, os.fill(), &tm, std::begin(f), std::end(f));
5057 }
5058#endif
5059 }
5060 modified = CharT{};
5061 command = nullptr;
5062 }
5063 else
5064 os << *fmt;
5065 break;
5066 case 'n':
5067 if (command)
5068 {
5069 if (modified == CharT{})
5070 os << CharT{'\n'};
5071 else
5072 {
5073 os << CharT{'%'} << modified << *fmt;
5074 modified = CharT{};
5075 }
5076 command = nullptr;
5077 }
5078 else
5079 os << *fmt;
5080 break;
5081 case 'p':
5082 if (command)
5083 {
5084 if (modified == CharT{})
5085 {
5086 if (!fds.has_tod)
5087 os.setstate(std::ios::failbit);
5088#if !ONLY_C_LOCALE
5089 const CharT f[] = {'%', *fmt};
5090 tm.tm_hour = static_cast<int>(fds.tod.hours().count());
5091 facet.put(os, os, os.fill(), &tm, std::begin(f), std::end(f));
5092#else
5093 if (gul17::date::is_am(fds.tod.hours()))
5094 os << ampm_names().first[0];
5095 else
5096 os << ampm_names().first[1];
5097#endif
5098 }
5099 else
5100 {
5101 os << CharT{'%'} << modified << *fmt;
5102 }
5103 modified = CharT{};
5104 command = nullptr;
5105 }
5106 else
5107 os << *fmt;
5108 break;
5109 case 'Q':
5110 case 'q':
5111 if (command)
5112 {
5113 if (modified == CharT{})
5114 {
5115 if (!fds.has_tod)
5116 os.setstate(std::ios::failbit);
5117 auto d = fds.tod.to_duration();
5118 if (*fmt == 'q')
5119 os << get_units<CharT>(typename decltype(d)::period::type{});
5120 else
5121 os << d.count();
5122 }
5123 else
5124 {
5125 os << CharT{'%'} << modified << *fmt;
5126 }
5127 modified = CharT{};
5128 command = nullptr;
5129 }
5130 else
5131 os << *fmt;
5132 break;
5133 case 'r':
5134 if (command)
5135 {
5136 if (modified == CharT{})
5137 {
5138 if (!fds.has_tod)
5139 os.setstate(std::ios::failbit);
5140#if !ONLY_C_LOCALE
5141 const CharT f[] = {'%', *fmt};
5142 tm.tm_hour = static_cast<int>(fds.tod.hours().count());
5143 tm.tm_min = static_cast<int>(fds.tod.minutes().count());
5144 tm.tm_sec = static_cast<int>(fds.tod.seconds().count());
5145 facet.put(os, os, os.fill(), &tm, std::begin(f), std::end(f));
5146#else
5147 hh_mm_ss<seconds> tod(duration_cast<seconds>(fds.tod.to_duration()));
5148 save_ostream<CharT, Traits> _(os);
5149 os.fill('0');
5150 os.width(2);
5151 os << gul17::date::make12(tod.hours()).count() << CharT{':'};
5152 os.width(2);
5153 os << tod.minutes().count() << CharT{':'};
5154 os.width(2);
5155 os << tod.seconds().count() << CharT{' '};
5156 if (gul17::date::is_am(tod.hours()))
5157 os << ampm_names().first[0];
5158 else
5159 os << ampm_names().first[1];
5160#endif
5161 }
5162 else
5163 {
5164 os << CharT{'%'} << modified << *fmt;
5165 }
5166 modified = CharT{};
5167 command = nullptr;
5168 }
5169 else
5170 os << *fmt;
5171 break;
5172 case 'R':
5173 if (command)
5174 {
5175 if (modified == CharT{})
5176 {
5177 if (!fds.has_tod)
5178 os.setstate(std::ios::failbit);
5179 if (fds.tod.hours() < hours{10})
5180 os << CharT{'0'};
5181 os << fds.tod.hours().count() << CharT{':'};
5182 if (fds.tod.minutes() < minutes{10})
5183 os << CharT{'0'};
5184 os << fds.tod.minutes().count();
5185 }
5186 else
5187 {
5188 os << CharT{'%'} << modified << *fmt;
5189 modified = CharT{};
5190 }
5191 command = nullptr;
5192 }
5193 else
5194 os << *fmt;
5195 break;
5196 case 'S':
5197 if (command)
5198 {
5199 if (modified == CharT{'E'})
5200 os << CharT{'%'} << modified << *fmt;
5201 else
5202 {
5203 if (!fds.has_tod)
5204 os.setstate(std::ios::failbit);
5205 if (insert_negative)
5206 {
5207 os << '-';
5208 insert_negative = false;
5209 }
5210#if !ONLY_C_LOCALE
5211 if (modified == CharT{})
5212#endif
5213 {
5214 os << fds.tod.s_;
5215 }
5216#if !ONLY_C_LOCALE
5217 else if (modified == CharT{'O'})
5218 {
5219 const CharT f[] = {'%', modified, *fmt};
5220 tm.tm_sec = static_cast<int>(fds.tod.s_.seconds().count());
5221 facet.put(os, os, os.fill(), &tm, std::begin(f), std::end(f));
5222 }
5223#endif
5224 }
5225 modified = CharT{};
5226 command = nullptr;
5227 }
5228 else
5229 os << *fmt;
5230 break;
5231 case 't':
5232 if (command)
5233 {
5234 if (modified == CharT{})
5235 os << CharT{'\t'};
5236 else
5237 {
5238 os << CharT{'%'} << modified << *fmt;
5239 modified = CharT{};
5240 }
5241 command = nullptr;
5242 }
5243 else
5244 os << *fmt;
5245 break;
5246 case 'T':
5247 if (command)
5248 {
5249 if (modified == CharT{})
5250 {
5251 if (!fds.has_tod)
5252 os.setstate(std::ios::failbit);
5253 os << fds.tod;
5254 }
5255 else
5256 {
5257 os << CharT{'%'} << modified << *fmt;
5258 modified = CharT{};
5259 }
5260 command = nullptr;
5261 }
5262 else
5263 os << *fmt;
5264 break;
5265 case 'u':
5266 if (command)
5267 {
5268 if (modified == CharT{'E'})
5269 os << CharT{'%'} << modified << *fmt;
5270 else
5271 {
5272 auto wd = extract_weekday(os, fds);
5273#if !ONLY_C_LOCALE
5274 if (modified == CharT{})
5275#endif
5276 {
5277 os << (wd != 0 ? wd : 7u);
5278 }
5279#if !ONLY_C_LOCALE
5280 else if (modified == CharT{'O'})
5281 {
5282 const CharT f[] = {'%', modified, *fmt};
5283 tm.tm_wday = static_cast<int>(wd);
5284 facet.put(os, os, os.fill(), &tm, std::begin(f), std::end(f));
5285 }
5286#endif
5287 }
5288 modified = CharT{};
5289 command = nullptr;
5290 }
5291 else
5292 os << *fmt;
5293 break;
5294 case 'U':
5295 if (command)
5296 {
5297 if (modified == CharT{'E'})
5298 os << CharT{'%'} << modified << *fmt;
5299 else
5300 {
5301 auto const& ymd = fds.ymd;
5302 if (!ymd.ok())
5303 os.setstate(std::ios::failbit);
5304 auto ld = local_days(ymd);
5305#if !ONLY_C_LOCALE
5306 if (modified == CharT{})
5307#endif
5308 {
5309 auto st = local_days(Sunday[1]/January/ymd.year());
5310 if (ld < st)
5311 os << CharT{'0'} << CharT{'0'};
5312 else
5313 {
5314 auto wn = duration_cast<weeks>(ld - st).count() + 1;
5315 if (wn < 10)
5316 os << CharT{'0'};
5317 os << wn;
5318 }
5319 }
5320 #if !ONLY_C_LOCALE
5321 else if (modified == CharT{'O'})
5322 {
5323 const CharT f[] = {'%', modified, *fmt};
5324 tm.tm_year = static_cast<int>(ymd.year()) - 1900;
5325 tm.tm_wday = static_cast<int>(extract_weekday(os, fds));
5326 if (os.fail())
5327 return os;
5328 tm.tm_yday = static_cast<int>((ld - local_days(ymd.year()/1/1)).count());
5329 facet.put(os, os, os.fill(), &tm, std::begin(f), std::end(f));
5330 }
5331#endif
5332 }
5333 modified = CharT{};
5334 command = nullptr;
5335 }
5336 else
5337 os << *fmt;
5338 break;
5339 case 'V':
5340 if (command)
5341 {
5342 if (modified == CharT{'E'})
5343 os << CharT{'%'} << modified << *fmt;
5344 else
5345 {
5346 if (!fds.ymd.ok())
5347 os.setstate(std::ios::failbit);
5348 auto ld = local_days(fds.ymd);
5349#if !ONLY_C_LOCALE
5350 if (modified == CharT{})
5351#endif
5352 {
5353 auto y = year_month_day{ld + days{3}}.year();
5354 auto st = local_days((y-years{1})/12/Thursday[last]) +
5355 (Monday-Thursday);
5356 if (ld < st)
5357 {
5358 --y;
5359 st = local_days((y - years{1})/12/Thursday[last]) +
5360 (Monday-Thursday);
5361 }
5362 auto wn = duration_cast<weeks>(ld - st).count() + 1;
5363 if (wn < 10)
5364 os << CharT{'0'};
5365 os << wn;
5366 }
5367#if !ONLY_C_LOCALE
5368 else if (modified == CharT{'O'})
5369 {
5370 const CharT f[] = {'%', modified, *fmt};
5371 auto const& ymd = fds.ymd;
5372 tm.tm_year = static_cast<int>(ymd.year()) - 1900;
5373 tm.tm_wday = static_cast<int>(extract_weekday(os, fds));
5374 if (os.fail())
5375 return os;
5376 tm.tm_yday = static_cast<int>((ld - local_days(ymd.year()/1/1)).count());
5377 facet.put(os, os, os.fill(), &tm, std::begin(f), std::end(f));
5378 }
5379#endif
5380 }
5381 modified = CharT{};
5382 command = nullptr;
5383 }
5384 else
5385 os << *fmt;
5386 break;
5387 case 'w':
5388 if (command)
5389 {
5390 auto wd = extract_weekday(os, fds);
5391 if (os.fail())
5392 return os;
5393#if !ONLY_C_LOCALE
5394 if (modified == CharT{})
5395#else
5396 if (modified != CharT{'E'})
5397#endif
5398 {
5399 os << wd;
5400 }
5401#if !ONLY_C_LOCALE
5402 else if (modified == CharT{'O'})
5403 {
5404 const CharT f[] = {'%', modified, *fmt};
5405 tm.tm_wday = static_cast<int>(wd);
5406 facet.put(os, os, os.fill(), &tm, std::begin(f), std::end(f));
5407 }
5408#endif
5409 else
5410 {
5411 os << CharT{'%'} << modified << *fmt;
5412 }
5413 modified = CharT{};
5414 command = nullptr;
5415 }
5416 else
5417 os << *fmt;
5418 break;
5419 case 'W':
5420 if (command)
5421 {
5422 if (modified == CharT{'E'})
5423 os << CharT{'%'} << modified << *fmt;
5424 else
5425 {
5426 auto const& ymd = fds.ymd;
5427 if (!ymd.ok())
5428 os.setstate(std::ios::failbit);
5429 auto ld = local_days(ymd);
5430#if !ONLY_C_LOCALE
5431 if (modified == CharT{})
5432#endif
5433 {
5434 auto st = local_days(Monday[1]/January/ymd.year());
5435 if (ld < st)
5436 os << CharT{'0'} << CharT{'0'};
5437 else
5438 {
5439 auto wn = duration_cast<weeks>(ld - st).count() + 1;
5440 if (wn < 10)
5441 os << CharT{'0'};
5442 os << wn;
5443 }
5444 }
5445#if !ONLY_C_LOCALE
5446 else if (modified == CharT{'O'})
5447 {
5448 const CharT f[] = {'%', modified, *fmt};
5449 tm.tm_year = static_cast<int>(ymd.year()) - 1900;
5450 tm.tm_wday = static_cast<int>(extract_weekday(os, fds));
5451 if (os.fail())
5452 return os;
5453 tm.tm_yday = static_cast<int>((ld - local_days(ymd.year()/1/1)).count());
5454 facet.put(os, os, os.fill(), &tm, std::begin(f), std::end(f));
5455 }
5456#endif
5457 }
5458 modified = CharT{};
5459 command = nullptr;
5460 }
5461 else
5462 os << *fmt;
5463 break;
5464 case 'X':
5465 if (command)
5466 {
5467 if (modified == CharT{'O'})
5468 os << CharT{'%'} << modified << *fmt;
5469 else
5470 {
5471 if (!fds.has_tod)
5472 os.setstate(std::ios::failbit);
5473#if !ONLY_C_LOCALE
5474 tm = std::tm{};
5475 tm.tm_sec = static_cast<int>(fds.tod.seconds().count());
5476 tm.tm_min = static_cast<int>(fds.tod.minutes().count());
5477 tm.tm_hour = static_cast<int>(fds.tod.hours().count());
5478 CharT f[3] = {'%'};
5479 auto fe = std::begin(f) + 1;
5480 if (modified == CharT{'E'})
5481 *fe++ = modified;
5482 *fe++ = *fmt;
5483 facet.put(os, os, os.fill(), &tm, std::begin(f), fe);
5484#else
5485 os << fds.tod;
5486#endif
5487 }
5488 command = nullptr;
5489 modified = CharT{};
5490 }
5491 else
5492 os << *fmt;
5493 break;
5494 case 'y':
5495 if (command)
5496 {
5497 if (!fds.ymd.year().ok())
5498 os.setstate(std::ios::failbit);
5499 auto y = static_cast<int>(fds.ymd.year());
5500#if !ONLY_C_LOCALE
5501 if (modified == CharT{})
5502 {
5503#endif
5504 y = std::abs(y) % 100;
5505 if (y < 10)
5506 os << CharT{'0'};
5507 os << y;
5508#if !ONLY_C_LOCALE
5509 }
5510 else
5511 {
5512 const CharT f[] = {'%', modified, *fmt};
5513 tm.tm_year = y - 1900;
5514 facet.put(os, os, os.fill(), &tm, std::begin(f), std::end(f));
5515 }
5516#endif
5517 modified = CharT{};
5518 command = nullptr;
5519 }
5520 else
5521 os << *fmt;
5522 break;
5523 case 'Y':
5524 if (command)
5525 {
5526 if (modified == CharT{'O'})
5527 os << CharT{'%'} << modified << *fmt;
5528 else
5529 {
5530 if (!fds.ymd.year().ok())
5531 os.setstate(std::ios::failbit);
5532 auto y = fds.ymd.year();
5533#if !ONLY_C_LOCALE
5534 if (modified == CharT{})
5535#endif
5536 {
5537 save_ostream<CharT, Traits> _(os);
5538 os.imbue(std::locale::classic());
5539 os << y;
5540 }
5541#if !ONLY_C_LOCALE
5542 else if (modified == CharT{'E'})
5543 {
5544 const CharT f[] = {'%', modified, *fmt};
5545 tm.tm_year = static_cast<int>(y) - 1900;
5546 facet.put(os, os, os.fill(), &tm, std::begin(f), std::end(f));
5547 }
5548#endif
5549 }
5550 modified = CharT{};
5551 command = nullptr;
5552 }
5553 else
5554 os << *fmt;
5555 break;
5556 case 'z':
5557 if (command)
5558 {
5559 if (offset_sec == nullptr)
5560 {
5561 // Can not format %z with unknown offset
5562 os.setstate(ios::failbit);
5563 return os;
5564 }
5565 auto m = duration_cast<minutes>(*offset_sec);
5566 auto neg = m < minutes{0};
5567 m = gul17::date::abs(m);
5568 auto h = duration_cast<hours>(m);
5569 m -= h;
5570 if (neg)
5571 os << CharT{'-'};
5572 else
5573 os << CharT{'+'};
5574 if (h < hours{10})
5575 os << CharT{'0'};
5576 os << h.count();
5577 if (modified != CharT{})
5578 os << CharT{':'};
5579 if (m < minutes{10})
5580 os << CharT{'0'};
5581 os << m.count();
5582 command = nullptr;
5583 modified = CharT{};
5584 }
5585 else
5586 os << *fmt;
5587 break;
5588 case 'Z':
5589 if (command)
5590 {
5591 if (modified == CharT{})
5592 {
5593 if (abbrev == nullptr)
5594 {
5595 // Can not format %Z with unknown time_zone
5596 os.setstate(ios::failbit);
5597 return os;
5598 }
5599 for (auto c : *abbrev)
5600 os << CharT(c);
5601 }
5602 else
5603 {
5604 os << CharT{'%'} << modified << *fmt;
5605 modified = CharT{};
5606 }
5607 command = nullptr;
5608 }
5609 else
5610 os << *fmt;
5611 break;
5612 case 'E':
5613 case 'O':
5614 if (command)
5615 {
5616 if (modified == CharT{})
5617 {
5618 modified = *fmt;
5619 }
5620 else
5621 {
5622 os << CharT{'%'} << modified << *fmt;
5623 command = nullptr;
5624 modified = CharT{};
5625 }
5626 }
5627 else
5628 os << *fmt;
5629 break;
5630 case '%':
5631 if (command)
5632 {
5633 if (modified == CharT{})
5634 {
5635 os << CharT{'%'};
5636 command = nullptr;
5637 }
5638 else
5639 {
5640 os << CharT{'%'} << modified << CharT{'%'};
5641 command = nullptr;
5642 modified = CharT{};
5643 }
5644 }
5645 else
5646 command = fmt;
5647 break;
5648 default:
5649 if (command)
5650 {
5651 os << CharT{'%'};
5652 command = nullptr;
5653 }
5654 if (modified != CharT{})
5655 {
5656 os << modified;
5657 modified = CharT{};
5658 }
5659 os << *fmt;
5660 break;
5661 }
5662 }
5663 if (command)
5664 os << CharT{'%'};
5665 if (modified != CharT{})
5666 os << modified;
5667 return os;
5668}
5669
5670template <class CharT, class Traits>
5671inline
5672std::basic_ostream<CharT, Traits>&
5673to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt, const year& y)
5674{
5675 using CT = std::chrono::seconds;
5676 fields<CT> fds{y/0/0};
5677 return to_stream(os, fmt, fds);
5678}
5679
5680template <class CharT, class Traits>
5681inline
5682std::basic_ostream<CharT, Traits>&
5683to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt, const month& m)
5684{
5685 using CT = std::chrono::seconds;
5686 fields<CT> fds{m/0/nanyear};
5687 return to_stream(os, fmt, fds);
5688}
5689
5690template <class CharT, class Traits>
5691inline
5692std::basic_ostream<CharT, Traits>&
5693to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt, const day& d)
5694{
5695 using CT = std::chrono::seconds;
5696 fields<CT> fds{d/0/nanyear};
5697 return to_stream(os, fmt, fds);
5698}
5699
5700template <class CharT, class Traits>
5701inline
5702std::basic_ostream<CharT, Traits>&
5703to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt, const weekday& wd)
5704{
5705 using CT = std::chrono::seconds;
5706 fields<CT> fds{wd};
5707 return to_stream(os, fmt, fds);
5708}
5709
5710template <class CharT, class Traits>
5711inline
5712std::basic_ostream<CharT, Traits>&
5713to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt, const year_month& ym)
5714{
5715 using CT = std::chrono::seconds;
5716 fields<CT> fds{ym/0};
5717 return to_stream(os, fmt, fds);
5718}
5719
5720template <class CharT, class Traits>
5721inline
5722std::basic_ostream<CharT, Traits>&
5723to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt, const month_day& md)
5724{
5725 using CT = std::chrono::seconds;
5726 fields<CT> fds{md/nanyear};
5727 return to_stream(os, fmt, fds);
5728}
5729
5730template <class CharT, class Traits>
5731inline
5732std::basic_ostream<CharT, Traits>&
5733to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
5734 const year_month_day& ymd)
5735{
5736 using CT = std::chrono::seconds;
5737 fields<CT> fds{ymd};
5738 return to_stream(os, fmt, fds);
5739}
5740
5741template <class CharT, class Traits, class Rep, class Period>
5742inline
5743std::basic_ostream<CharT, Traits>&
5744to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
5745 const std::chrono::duration<Rep, Period>& d)
5746{
5747 using Duration = std::chrono::duration<Rep, Period>;
5748 using CT = typename std::common_type<Duration, std::chrono::seconds>::type;
5749 fields<CT> fds{hh_mm_ss<CT>{d}};
5750 return to_stream(os, fmt, fds);
5751}
5752
5753template <class CharT, class Traits, class Duration>
5754std::basic_ostream<CharT, Traits>&
5755to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
5756 const local_time<Duration>& tp, const std::string* abbrev = nullptr,
5757 const std::chrono::seconds* offset_sec = nullptr)
5758{
5759 using CT = typename std::common_type<Duration, std::chrono::seconds>::type;
5760 auto ld = std::chrono::time_point_cast<days>(tp);
5761 fields<CT> fds;
5762 if (ld <= tp)
5763 fds = fields<CT>{year_month_day{ld}, hh_mm_ss<CT>{tp-local_seconds{ld}}};
5764 else
5765 fds = fields<CT>{year_month_day{ld - days{1}},
5766 hh_mm_ss<CT>{days{1} - (local_seconds{ld} - tp)}};
5767 return to_stream(os, fmt, fds, abbrev, offset_sec);
5768}
5769
5770template <class CharT, class Traits, class Duration>
5771std::basic_ostream<CharT, Traits>&
5772to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
5773 const sys_time<Duration>& tp)
5774{
5775 using std::chrono::seconds;
5776 using CT = typename std::common_type<Duration, seconds>::type;
5777 const std::string abbrev("UTC");
5778 constexpr const seconds offset{0};
5779 auto sd = std::chrono::time_point_cast<days>(tp);
5780 fields<CT> fds;
5781 if (sd <= tp)
5782 fds = fields<CT>{year_month_day{sd}, hh_mm_ss<CT>{tp-sys_seconds{sd}}};
5783 else
5784 fds = fields<CT>{year_month_day{sd - days{1}},
5785 hh_mm_ss<CT>{days{1} - (sys_seconds{sd} - tp)}};
5786 return to_stream(os, fmt, fds, &abbrev, &offset);
5787}
5788
5789// format
5790
5791template <class CharT, class Streamable>
5792auto
5793format(const std::locale& loc, const CharT* fmt, const Streamable& tp)
5794 -> decltype(to_stream(std::declval<std::basic_ostream<CharT>&>(), fmt, tp),
5795 std::basic_string<CharT>{})
5796{
5797 std::basic_ostringstream<CharT> os;
5798 os.exceptions(std::ios::failbit | std::ios::badbit);
5799 os.imbue(loc);
5800 to_stream(os, fmt, tp);
5801 return os.str();
5802}
5803
5804template <class CharT, class Streamable>
5805auto
5806format(const CharT* fmt, const Streamable& tp)
5807 -> decltype(to_stream(std::declval<std::basic_ostream<CharT>&>(), fmt, tp),
5808 std::basic_string<CharT>{})
5809{
5810 std::basic_ostringstream<CharT> os;
5811 os.exceptions(std::ios::failbit | std::ios::badbit);
5812 to_stream(os, fmt, tp);
5813 return os.str();
5814}
5815
5816template <class CharT, class Traits, class Alloc, class Streamable>
5817auto
5818format(const std::locale& loc, const std::basic_string<CharT, Traits, Alloc>& fmt,
5819 const Streamable& tp)
5820 -> decltype(to_stream(std::declval<std::basic_ostream<CharT, Traits>&>(), fmt.c_str(), tp),
5821 std::basic_string<CharT, Traits, Alloc>{})
5822{
5823 std::basic_ostringstream<CharT, Traits, Alloc> os;
5824 os.exceptions(std::ios::failbit | std::ios::badbit);
5825 os.imbue(loc);
5826 to_stream(os, fmt.c_str(), tp);
5827 return os.str();
5828}
5829
5830template <class CharT, class Traits, class Alloc, class Streamable>
5831auto
5832format(const std::basic_string<CharT, Traits, Alloc>& fmt, const Streamable& tp)
5833 -> decltype(to_stream(std::declval<std::basic_ostream<CharT, Traits>&>(), fmt.c_str(), tp),
5834 std::basic_string<CharT, Traits, Alloc>{})
5835{
5836 std::basic_ostringstream<CharT, Traits, Alloc> os;
5837 os.exceptions(std::ios::failbit | std::ios::badbit);
5838 to_stream(os, fmt.c_str(), tp);
5839 return os.str();
5840}
5841
5842// parse
5843
5844namespace detail
5845{
5846
5847template <class CharT, class Traits>
5848bool
5849read_char(std::basic_istream<CharT, Traits>& is, CharT fmt, std::ios::iostate& err)
5850{
5851 auto ic = is.get();
5852 if (Traits::eq_int_type(ic, Traits::eof()) ||
5853 !Traits::eq(Traits::to_char_type(ic), fmt))
5854 {
5855 err |= std::ios::failbit;
5856 is.setstate(std::ios::failbit);
5857 return false;
5858 }
5859 return true;
5860}
5861
5862template <class CharT, class Traits>
5863unsigned
5864read_unsigned(std::basic_istream<CharT, Traits>& is, unsigned m = 1, unsigned M = 10)
5865{
5866 unsigned x = 0;
5867 unsigned count = 0;
5868 while (true)
5869 {
5870 auto ic = is.peek();
5871 if (Traits::eq_int_type(ic, Traits::eof()))
5872 break;
5873 auto c = static_cast<char>(Traits::to_char_type(ic));
5874 if (!('0' <= c && c <= '9'))
5875 break;
5876 (void)is.get();
5877 ++count;
5878 x = 10*x + static_cast<unsigned>(c - '0');
5879 if (count == M)
5880 break;
5881 }
5882 if (count < m)
5883 is.setstate(std::ios::failbit);
5884 return x;
5885}
5886
5887template <class CharT, class Traits>
5888int
5889read_signed(std::basic_istream<CharT, Traits>& is, unsigned m = 1, unsigned M = 10)
5890{
5891 auto ic = is.peek();
5892 if (!Traits::eq_int_type(ic, Traits::eof()))
5893 {
5894 auto c = static_cast<char>(Traits::to_char_type(ic));
5895 if (('0' <= c && c <= '9') || c == '-' || c == '+')
5896 {
5897 if (c == '-' || c == '+')
5898 (void)is.get();
5899 auto x = static_cast<int>(read_unsigned(is, std::max(m, 1u), M));
5900 if (!is.fail())
5901 {
5902 if (c == '-')
5903 x = -x;
5904 return x;
5905 }
5906 }
5907 }
5908 if (m > 0)
5909 is.setstate(std::ios::failbit);
5910 return 0;
5911}
5912
5913template <class CharT, class Traits>
5914long double
5915read_long_double(std::basic_istream<CharT, Traits>& is, unsigned m = 1, unsigned M = 10)
5916{
5917 unsigned count = 0;
5918 unsigned fcount = 0;
5919 unsigned long long i = 0;
5920 unsigned long long f = 0;
5921 bool parsing_fraction = false;
5922#if ONLY_C_LOCALE
5923 typename Traits::int_type decimal_point = '.';
5924#else
5925 auto decimal_point = Traits::to_int_type(
5926 std::use_facet<std::numpunct<CharT>>(is.getloc()).decimal_point());
5927#endif
5928 while (true)
5929 {
5930 auto ic = is.peek();
5931 if (Traits::eq_int_type(ic, Traits::eof()))
5932 break;
5933 if (Traits::eq_int_type(ic, decimal_point))
5934 {
5935 decimal_point = Traits::eof();
5936 parsing_fraction = true;
5937 }
5938 else
5939 {
5940 auto c = static_cast<char>(Traits::to_char_type(ic));
5941 if (!('0' <= c && c <= '9'))
5942 break;
5943 if (!parsing_fraction)
5944 {
5945 i = 10*i + static_cast<unsigned>(c - '0');
5946 }
5947 else
5948 {
5949 f = 10*f + static_cast<unsigned>(c - '0');
5950 ++fcount;
5951 }
5952 }
5953 (void)is.get();
5954 if (++count == M)
5955 break;
5956 }
5957 if (count < m)
5958 {
5959 is.setstate(std::ios::failbit);
5960 return 0;
5961 }
5962 return static_cast<long double>(i) + static_cast<long double>(f)/std::pow(10.L, fcount);
5963}
5964
5965struct rs
5966{
5967 int& i;
5968 unsigned m;
5969 unsigned M;
5970};
5971
5972struct ru
5973{
5974 int& i;
5975 unsigned m;
5976 unsigned M;
5977};
5978
5979struct rld
5980{
5981 long double& i;
5982 unsigned m;
5983 unsigned M;
5984};
5985
5986template <class CharT, class Traits>
5987void
5988read(std::basic_istream<CharT, Traits>&)
5989{
5990}
5991
5992template <class CharT, class Traits, class ...Args>
5993void
5994read(std::basic_istream<CharT, Traits>& is, CharT a0, Args&& ...args);
5995
5996template <class CharT, class Traits, class ...Args>
5997void
5998read(std::basic_istream<CharT, Traits>& is, rs a0, Args&& ...args);
5999
6000template <class CharT, class Traits, class ...Args>
6001void
6002read(std::basic_istream<CharT, Traits>& is, ru a0, Args&& ...args);
6003
6004template <class CharT, class Traits, class ...Args>
6005void
6006read(std::basic_istream<CharT, Traits>& is, int a0, Args&& ...args);
6007
6008template <class CharT, class Traits, class ...Args>
6009void
6010read(std::basic_istream<CharT, Traits>& is, rld a0, Args&& ...args);
6011
6012template <class CharT, class Traits, class ...Args>
6013void
6014read(std::basic_istream<CharT, Traits>& is, CharT a0, Args&& ...args)
6015{
6016 // No-op if a0 == CharT{}
6017 if (a0 != CharT{})
6018 {
6019 auto ic = is.peek();
6020 if (Traits::eq_int_type(ic, Traits::eof()))
6021 {
6022 is.setstate(std::ios::failbit | std::ios::eofbit);
6023 return;
6024 }
6025 if (!Traits::eq(Traits::to_char_type(ic), a0))
6026 {
6027 is.setstate(std::ios::failbit);
6028 return;
6029 }
6030 (void)is.get();
6031 }
6032 read(is, std::forward<Args>(args)...);
6033}
6034
6035template <class CharT, class Traits, class ...Args>
6036void
6037read(std::basic_istream<CharT, Traits>& is, rs a0, Args&& ...args)
6038{
6039 auto x = read_signed(is, a0.m, a0.M);
6040 if (is.fail())
6041 return;
6042 a0.i = x;
6043 read(is, std::forward<Args>(args)...);
6044}
6045
6046template <class CharT, class Traits, class ...Args>
6047void
6048read(std::basic_istream<CharT, Traits>& is, ru a0, Args&& ...args)
6049{
6050 auto x = read_unsigned(is, a0.m, a0.M);
6051 if (is.fail())
6052 return;
6053 a0.i = static_cast<int>(x);
6054 read(is, std::forward<Args>(args)...);
6055}
6056
6057template <class CharT, class Traits, class ...Args>
6058void
6059read(std::basic_istream<CharT, Traits>& is, int a0, Args&& ...args)
6060{
6061 if (a0 != -1)
6062 {
6063 auto u = static_cast<unsigned>(a0);
6064 CharT buf[std::numeric_limits<unsigned>::digits10+2u] = {};
6065 auto e = buf;
6066 do
6067 {
6068 *e++ = static_cast<CharT>(CharT(u % 10) + CharT{'0'});
6069 u /= 10;
6070 } while (u > 0);
6071 std::reverse(buf, e);
6072 for (auto p = buf; p != e && is.rdstate() == std::ios::goodbit; ++p)
6073 read(is, *p);
6074 }
6075 if (is.rdstate() == std::ios::goodbit)
6076 read(is, std::forward<Args>(args)...);
6077}
6078
6079template <class CharT, class Traits, class ...Args>
6080void
6081read(std::basic_istream<CharT, Traits>& is, rld a0, Args&& ...args)
6082{
6083 auto x = read_long_double(is, a0.m, a0.M);
6084 if (is.fail())
6085 return;
6086 a0.i = x;
6087 read(is, std::forward<Args>(args)...);
6088}
6089
6090template <class T, class CharT, class Traits>
6091inline
6092void
6093checked_set(T& value, T from, T not_a_value, std::basic_ios<CharT, Traits>& is)
6094{
6095 if (!is.fail())
6096 {
6097 if (value == not_a_value)
6098 value = std::move(from);
6099 else if (value != from)
6100 is.setstate(std::ios::failbit);
6101 }
6102}
6103
6104} // namespace detail;
6105
6106template <class CharT, class Traits, class Duration, class Alloc = std::allocator<CharT>>
6107std::basic_istream<CharT, Traits>&
6108from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
6109 fields<Duration>& fds, std::basic_string<CharT, Traits, Alloc>* abbrev,
6110 std::chrono::minutes* offset)
6111{
6112 using std::numeric_limits;
6113 using std::ios;
6114 using std::chrono::duration;
6115 using std::chrono::duration_cast;
6116 using std::chrono::seconds;
6117 using std::chrono::minutes;
6118 using std::chrono::hours;
6119 using detail::round_i;
6120 typename std::basic_istream<CharT, Traits>::sentry ok{is, true};
6121 if (ok)
6122 {
6123 gul17::date::detail::save_istream<CharT, Traits> ss(is);
6124 is.fill(' ');
6125 is.flags(std::ios::skipws | std::ios::dec);
6126 is.width(0);
6127#if !ONLY_C_LOCALE
6128 auto& f = std::use_facet<std::time_get<CharT>>(is.getloc());
6129 std::tm tm{};
6130#endif
6131 const CharT* command = nullptr;
6132 auto modified = CharT{};
6133 auto width = -1;
6134
6135 constexpr const int not_a_year = numeric_limits<short>::min();
6136 constexpr const int not_a_2digit_year = 100;
6137 constexpr const int not_a_century = not_a_year / 100;
6138 constexpr const int not_a_month = 0;
6139 constexpr const int not_a_day = 0;
6140 constexpr const int not_a_hour = numeric_limits<int>::min();
6141 constexpr const int not_a_hour_12_value = 0;
6142 constexpr const int not_a_minute = not_a_hour;
6143 constexpr const Duration not_a_second = Duration::min();
6144 constexpr const int not_a_doy = -1;
6145 constexpr const int not_a_weekday = 8;
6146 constexpr const int not_a_week_num = 100;
6147 constexpr const int not_a_ampm = -1;
6148 constexpr const minutes not_a_offset = minutes::min();
6149
6150 int Y = not_a_year; // c, F, Y *
6151 int y = not_a_2digit_year; // D, x, y *
6152 int g = not_a_2digit_year; // g *
6153 int G = not_a_year; // G *
6154 int C = not_a_century; // C *
6155 int m = not_a_month; // b, B, h, m, c, D, F, x *
6156 int d = not_a_day; // c, d, D, e, F, x *
6157 int j = not_a_doy; // j *
6158 int wd = not_a_weekday; // a, A, u, w *
6159 int H = not_a_hour; // c, H, R, T, X *
6160 int I = not_a_hour_12_value; // I, r *
6161 int p = not_a_ampm; // p, r *
6162 int M = not_a_minute; // c, M, r, R, T, X *
6163 Duration s = not_a_second; // c, r, S, T, X *
6164 int U = not_a_week_num; // U *
6165 int V = not_a_week_num; // V *
6166 int W = not_a_week_num; // W *
6167 std::basic_string<CharT, Traits, Alloc> temp_abbrev; // Z *
6168 minutes temp_offset = not_a_offset; // z *
6169
6170 using detail::read;
6171 using detail::rs;
6172 using detail::ru;
6173 using detail::rld;
6174 using detail::checked_set;
6175 for (; *fmt != CharT{} && !is.fail(); ++fmt)
6176 {
6177 switch (*fmt)
6178 {
6179 case 'a':
6180 case 'A':
6181 case 'u':
6182 case 'w': // wd: a, A, u, w
6183 if (command)
6184 {
6185 int trial_wd = not_a_weekday;
6186 if (*fmt == 'a' || *fmt == 'A')
6187 {
6188 if (modified == CharT{})
6189 {
6190#if !ONLY_C_LOCALE
6191 ios::iostate err = ios::goodbit;
6192 f.get(is, nullptr, is, err, &tm, command, fmt+1);
6193 is.setstate(err);
6194 if (!is.fail())
6195 trial_wd = tm.tm_wday;
6196#else
6197 auto nm = detail::weekday_names();
6198 auto i = detail::scan_keyword(is, nm.first, nm.second) - nm.first;
6199 if (!is.fail())
6200 trial_wd = i % 7;
6201#endif
6202 }
6203 else
6204 read(is, CharT{'%'}, width, modified, *fmt);
6205 }
6206 else // *fmt == 'u' || *fmt == 'w'
6207 {
6208#if !ONLY_C_LOCALE
6209 if (modified == CharT{})
6210#else
6211 if (modified != CharT{'E'})
6212#endif
6213 {
6214 read(is, ru{trial_wd, 1, width == -1 ?
6215 1u : static_cast<unsigned>(width)});
6216 if (!is.fail())
6217 {
6218 if (*fmt == 'u')
6219 {
6220 if (!(1 <= trial_wd && trial_wd <= 7))
6221 {
6222 trial_wd = not_a_weekday;
6223 is.setstate(ios::failbit);
6224 }
6225 else if (trial_wd == 7)
6226 trial_wd = 0;
6227 }
6228 else // *fmt == 'w'
6229 {
6230 if (!(0 <= trial_wd && trial_wd <= 6))
6231 {
6232 trial_wd = not_a_weekday;
6233 is.setstate(ios::failbit);
6234 }
6235 }
6236 }
6237 }
6238#if !ONLY_C_LOCALE
6239 else if (modified == CharT{'O'})
6240 {
6241 ios::iostate err = ios::goodbit;
6242 f.get(is, nullptr, is, err, &tm, command, fmt+1);
6243 is.setstate(err);
6244 if (!is.fail())
6245 trial_wd = tm.tm_wday;
6246 }
6247#endif
6248 else
6249 read(is, CharT{'%'}, width, modified, *fmt);
6250 }
6251 if (trial_wd != not_a_weekday)
6252 checked_set(wd, trial_wd, not_a_weekday, is);
6253 }
6254 else // !command
6255 read(is, *fmt);
6256 command = nullptr;
6257 width = -1;
6258 modified = CharT{};
6259 break;
6260 case 'b':
6261 case 'B':
6262 case 'h':
6263 if (command)
6264 {
6265 if (modified == CharT{})
6266 {
6267 int ttm = not_a_month;
6268#if !ONLY_C_LOCALE
6269 ios::iostate err = ios::goodbit;
6270 f.get(is, nullptr, is, err, &tm, command, fmt+1);
6271 if ((err & ios::failbit) == 0)
6272 ttm = tm.tm_mon + 1;
6273 is.setstate(err);
6274#else
6275 auto nm = detail::month_names();
6276 auto i = detail::scan_keyword(is, nm.first, nm.second) - nm.first;
6277 if (!is.fail())
6278 ttm = i % 12 + 1;
6279#endif
6280 checked_set(m, ttm, not_a_month, is);
6281 }
6282 else
6283 read(is, CharT{'%'}, width, modified, *fmt);
6284 command = nullptr;
6285 width = -1;
6286 modified = CharT{};
6287 }
6288 else
6289 read(is, *fmt);
6290 break;
6291 case 'c':
6292 if (command)
6293 {
6294 if (modified != CharT{'O'})
6295 {
6296#if !ONLY_C_LOCALE
6297 ios::iostate err = ios::goodbit;
6298 f.get(is, nullptr, is, err, &tm, command, fmt+1);
6299 if ((err & ios::failbit) == 0)
6300 {
6301 checked_set(Y, tm.tm_year + 1900, not_a_year, is);
6302 checked_set(m, tm.tm_mon + 1, not_a_month, is);
6303 checked_set(d, tm.tm_mday, not_a_day, is);
6304 checked_set(H, tm.tm_hour, not_a_hour, is);
6305 checked_set(M, tm.tm_min, not_a_minute, is);
6306 checked_set(s, duration_cast<Duration>(seconds{tm.tm_sec}),
6307 not_a_second, is);
6308 }
6309 is.setstate(err);
6310#else
6311 // "%a %b %e %T %Y"
6312 auto nm = detail::weekday_names();
6313 auto i = detail::scan_keyword(is, nm.first, nm.second) - nm.first;
6314 checked_set(wd, static_cast<int>(i % 7), not_a_weekday, is);
6315 ws(is);
6316 nm = detail::month_names();
6317 i = detail::scan_keyword(is, nm.first, nm.second) - nm.first;
6318 checked_set(m, static_cast<int>(i % 12 + 1), not_a_month, is);
6319 ws(is);
6320 int td = not_a_day;
6321 read(is, rs{td, 1, 2});
6322 checked_set(d, td, not_a_day, is);
6323 ws(is);
6324 using dfs = detail::decimal_format_seconds<Duration>;
6325 constexpr const auto w = Duration::period::den == 1 ? 2 : 3 + dfs::width;
6326 int tH;
6327 int tM;
6328 long double S{};
6329 read(is, ru{tH, 1, 2}, CharT{':'}, ru{tM, 1, 2},
6330 CharT{':'}, rld{S, 1, w});
6331 checked_set(H, tH, not_a_hour, is);
6332 checked_set(M, tM, not_a_minute, is);
6333 checked_set(s, round_i<Duration>(duration<long double>{S}),
6334 not_a_second, is);
6335 ws(is);
6336 int tY = not_a_year;
6337 read(is, rs{tY, 1, 4u});
6338 checked_set(Y, tY, not_a_year, is);
6339#endif
6340 }
6341 else
6342 read(is, CharT{'%'}, width, modified, *fmt);
6343 command = nullptr;
6344 width = -1;
6345 modified = CharT{};
6346 }
6347 else
6348 read(is, *fmt);
6349 break;
6350 case 'x':
6351 if (command)
6352 {
6353 if (modified != CharT{'O'})
6354 {
6355#if !ONLY_C_LOCALE
6356 ios::iostate err = ios::goodbit;
6357 f.get(is, nullptr, is, err, &tm, command, fmt+1);
6358 if ((err & ios::failbit) == 0)
6359 {
6360 checked_set(Y, tm.tm_year + 1900, not_a_year, is);
6361 checked_set(m, tm.tm_mon + 1, not_a_month, is);
6362 checked_set(d, tm.tm_mday, not_a_day, is);
6363 }
6364 is.setstate(err);
6365#else
6366 // "%m/%d/%y"
6367 int ty = not_a_2digit_year;
6368 int tm = not_a_month;
6369 int td = not_a_day;
6370 read(is, ru{tm, 1, 2}, CharT{'/'}, ru{td, 1, 2}, CharT{'/'},
6371 rs{ty, 1, 2});
6372 checked_set(y, ty, not_a_2digit_year, is);
6373 checked_set(m, tm, not_a_month, is);
6374 checked_set(d, td, not_a_day, is);
6375#endif
6376 }
6377 else
6378 read(is, CharT{'%'}, width, modified, *fmt);
6379 command = nullptr;
6380 width = -1;
6381 modified = CharT{};
6382 }
6383 else
6384 read(is, *fmt);
6385 break;
6386 case 'X':
6387 if (command)
6388 {
6389 if (modified != CharT{'O'})
6390 {
6391#if !ONLY_C_LOCALE
6392 ios::iostate err = ios::goodbit;
6393 f.get(is, nullptr, is, err, &tm, command, fmt+1);
6394 if ((err & ios::failbit) == 0)
6395 {
6396 checked_set(H, tm.tm_hour, not_a_hour, is);
6397 checked_set(M, tm.tm_min, not_a_minute, is);
6398 checked_set(s, duration_cast<Duration>(seconds{tm.tm_sec}),
6399 not_a_second, is);
6400 }
6401 is.setstate(err);
6402#else
6403 // "%T"
6404 using dfs = detail::decimal_format_seconds<Duration>;
6405 constexpr const auto w = Duration::period::den == 1 ? 2 : 3 + dfs::width;
6406 int tH = not_a_hour;
6407 int tM = not_a_minute;
6408 long double S{};
6409 read(is, ru{tH, 1, 2}, CharT{':'}, ru{tM, 1, 2},
6410 CharT{':'}, rld{S, 1, w});
6411 checked_set(H, tH, not_a_hour, is);
6412 checked_set(M, tM, not_a_minute, is);
6413 checked_set(s, round_i<Duration>(duration<long double>{S}),
6414 not_a_second, is);
6415#endif
6416 }
6417 else
6418 read(is, CharT{'%'}, width, modified, *fmt);
6419 command = nullptr;
6420 width = -1;
6421 modified = CharT{};
6422 }
6423 else
6424 read(is, *fmt);
6425 break;
6426 case 'C':
6427 if (command)
6428 {
6429 int tC = not_a_century;
6430#if !ONLY_C_LOCALE
6431 if (modified == CharT{})
6432 {
6433#endif
6434 read(is, rs{tC, 1, width == -1 ? 2u : static_cast<unsigned>(width)});
6435#if !ONLY_C_LOCALE
6436 }
6437 else
6438 {
6439 ios::iostate err = ios::goodbit;
6440 f.get(is, nullptr, is, err, &tm, command, fmt+1);
6441 if ((err & ios::failbit) == 0)
6442 {
6443 auto tY = tm.tm_year + 1900;
6444 tC = (tY >= 0 ? tY : tY-99) / 100;
6445 }
6446 is.setstate(err);
6447 }
6448#endif
6449 checked_set(C, tC, not_a_century, is);
6450 command = nullptr;
6451 width = -1;
6452 modified = CharT{};
6453 }
6454 else
6455 read(is, *fmt);
6456 break;
6457 case 'D':
6458 if (command)
6459 {
6460 if (modified == CharT{})
6461 {
6462 int tn = not_a_month;
6463 int td = not_a_day;
6464 int ty = not_a_2digit_year;
6465 read(is, ru{tn, 1, 2}, CharT{'\0'}, CharT{'/'}, CharT{'\0'},
6466 ru{td, 1, 2}, CharT{'\0'}, CharT{'/'}, CharT{'\0'},
6467 rs{ty, 1, 2});
6468 checked_set(y, ty, not_a_2digit_year, is);
6469 checked_set(m, tn, not_a_month, is);
6470 checked_set(d, td, not_a_day, is);
6471 }
6472 else
6473 read(is, CharT{'%'}, width, modified, *fmt);
6474 command = nullptr;
6475 width = -1;
6476 modified = CharT{};
6477 }
6478 else
6479 read(is, *fmt);
6480 break;
6481 case 'F':
6482 if (command)
6483 {
6484 if (modified == CharT{})
6485 {
6486 int tY = not_a_year;
6487 int tn = not_a_month;
6488 int td = not_a_day;
6489 read(is, rs{tY, 1, width == -1 ? 4u : static_cast<unsigned>(width)},
6490 CharT{'-'}, ru{tn, 1, 2}, CharT{'-'}, ru{td, 1, 2});
6491 checked_set(Y, tY, not_a_year, is);
6492 checked_set(m, tn, not_a_month, is);
6493 checked_set(d, td, not_a_day, is);
6494 }
6495 else
6496 read(is, CharT{'%'}, width, modified, *fmt);
6497 command = nullptr;
6498 width = -1;
6499 modified = CharT{};
6500 }
6501 else
6502 read(is, *fmt);
6503 break;
6504 case 'd':
6505 case 'e':
6506 if (command)
6507 {
6508#if !ONLY_C_LOCALE
6509 if (modified == CharT{})
6510#else
6511 if (modified != CharT{'E'})
6512#endif
6513 {
6514 int td = not_a_day;
6515 read(is, rs{td, 1, width == -1 ? 2u : static_cast<unsigned>(width)});
6516 checked_set(d, td, not_a_day, is);
6517 }
6518#if !ONLY_C_LOCALE
6519 else if (modified == CharT{'O'})
6520 {
6521 ios::iostate err = ios::goodbit;
6522 f.get(is, nullptr, is, err, &tm, command, fmt+1);
6523 command = nullptr;
6524 width = -1;
6525 modified = CharT{};
6526 if ((err & ios::failbit) == 0)
6527 checked_set(d, tm.tm_mday, not_a_day, is);
6528 is.setstate(err);
6529 }
6530#endif
6531 else
6532 read(is, CharT{'%'}, width, modified, *fmt);
6533 command = nullptr;
6534 width = -1;
6535 modified = CharT{};
6536 }
6537 else
6538 read(is, *fmt);
6539 break;
6540 case 'H':
6541 if (command)
6542 {
6543#if !ONLY_C_LOCALE
6544 if (modified == CharT{})
6545#else
6546 if (modified != CharT{'E'})
6547#endif
6548 {
6549 int tH = not_a_hour;
6550 read(is, ru{tH, 1, width == -1 ? 2u : static_cast<unsigned>(width)});
6551 checked_set(H, tH, not_a_hour, is);
6552 }
6553#if !ONLY_C_LOCALE
6554 else if (modified == CharT{'O'})
6555 {
6556 ios::iostate err = ios::goodbit;
6557 f.get(is, nullptr, is, err, &tm, command, fmt+1);
6558 if ((err & ios::failbit) == 0)
6559 checked_set(H, tm.tm_hour, not_a_hour, is);
6560 is.setstate(err);
6561 }
6562#endif
6563 else
6564 read(is, CharT{'%'}, width, modified, *fmt);
6565 command = nullptr;
6566 width = -1;
6567 modified = CharT{};
6568 }
6569 else
6570 read(is, *fmt);
6571 break;
6572 case 'I':
6573 if (command)
6574 {
6575 if (modified == CharT{})
6576 {
6577 int tI = not_a_hour_12_value;
6578 // reads in an hour into I, but most be in [1, 12]
6579 read(is, rs{tI, 1, width == -1 ? 2u : static_cast<unsigned>(width)});
6580 if (!(1 <= tI && tI <= 12))
6581 is.setstate(ios::failbit);
6582 checked_set(I, tI, not_a_hour_12_value, is);
6583 }
6584 else
6585 read(is, CharT{'%'}, width, modified, *fmt);
6586 command = nullptr;
6587 width = -1;
6588 modified = CharT{};
6589 }
6590 else
6591 read(is, *fmt);
6592 break;
6593 case 'j':
6594 if (command)
6595 {
6596 if (modified == CharT{})
6597 {
6598 int tj = not_a_doy;
6599 read(is, ru{tj, 1, width == -1 ? 3u : static_cast<unsigned>(width)});
6600 checked_set(j, tj, not_a_doy, is);
6601 }
6602 else
6603 read(is, CharT{'%'}, width, modified, *fmt);
6604 command = nullptr;
6605 width = -1;
6606 modified = CharT{};
6607 }
6608 else
6609 read(is, *fmt);
6610 break;
6611 case 'M':
6612 if (command)
6613 {
6614#if !ONLY_C_LOCALE
6615 if (modified == CharT{})
6616#else
6617 if (modified != CharT{'E'})
6618#endif
6619 {
6620 int tM = not_a_minute;
6621 read(is, ru{tM, 1, width == -1 ? 2u : static_cast<unsigned>(width)});
6622 checked_set(M, tM, not_a_minute, is);
6623 }
6624#if !ONLY_C_LOCALE
6625 else if (modified == CharT{'O'})
6626 {
6627 ios::iostate err = ios::goodbit;
6628 f.get(is, nullptr, is, err, &tm, command, fmt+1);
6629 if ((err & ios::failbit) == 0)
6630 checked_set(M, tm.tm_min, not_a_minute, is);
6631 is.setstate(err);
6632 }
6633#endif
6634 else
6635 read(is, CharT{'%'}, width, modified, *fmt);
6636 command = nullptr;
6637 width = -1;
6638 modified = CharT{};
6639 }
6640 else
6641 read(is, *fmt);
6642 break;
6643 case 'm':
6644 if (command)
6645 {
6646#if !ONLY_C_LOCALE
6647 if (modified == CharT{})
6648#else
6649 if (modified != CharT{'E'})
6650#endif
6651 {
6652 int tn = not_a_month;
6653 read(is, rs{tn, 1, width == -1 ? 2u : static_cast<unsigned>(width)});
6654 checked_set(m, tn, not_a_month, is);
6655 }
6656#if !ONLY_C_LOCALE
6657 else if (modified == CharT{'O'})
6658 {
6659 ios::iostate err = ios::goodbit;
6660 f.get(is, nullptr, is, err, &tm, command, fmt+1);
6661 if ((err & ios::failbit) == 0)
6662 checked_set(m, tm.tm_mon + 1, not_a_month, is);
6663 is.setstate(err);
6664 }
6665#endif
6666 else
6667 read(is, CharT{'%'}, width, modified, *fmt);
6668 command = nullptr;
6669 width = -1;
6670 modified = CharT{};
6671 }
6672 else
6673 read(is, *fmt);
6674 break;
6675 case 'n':
6676 case 't':
6677 if (command)
6678 {
6679 if (modified == CharT{})
6680 {
6681 // %n matches a single white space character
6682 // %t matches 0 or 1 white space characters
6683 auto ic = is.peek();
6684 if (Traits::eq_int_type(ic, Traits::eof()))
6685 {
6686 ios::iostate err = ios::eofbit;
6687 if (*fmt == 'n')
6688 err |= ios::failbit;
6689 is.setstate(err);
6690 break;
6691 }
6692 if (isspace(ic))
6693 {
6694 (void)is.get();
6695 }
6696 else if (*fmt == 'n')
6697 is.setstate(ios::failbit);
6698 }
6699 else
6700 read(is, CharT{'%'}, width, modified, *fmt);
6701 command = nullptr;
6702 width = -1;
6703 modified = CharT{};
6704 }
6705 else
6706 read(is, *fmt);
6707 break;
6708 case 'p':
6709 if (command)
6710 {
6711 if (modified == CharT{})
6712 {
6713 int tp = not_a_ampm;
6714#if !ONLY_C_LOCALE
6715 tm = std::tm{};
6716 tm.tm_hour = 1;
6717 ios::iostate err = ios::goodbit;
6718 f.get(is, nullptr, is, err, &tm, command, fmt+1);
6719 is.setstate(err);
6720 if (tm.tm_hour == 1)
6721 tp = 0;
6722 else if (tm.tm_hour == 13)
6723 tp = 1;
6724 else
6725 is.setstate(err);
6726#else
6727 auto nm = detail::ampm_names();
6728 auto i = detail::scan_keyword(is, nm.first, nm.second) - nm.first;
6729 tp = static_cast<decltype(tp)>(i);
6730#endif
6731 checked_set(p, tp, not_a_ampm, is);
6732 }
6733 else
6734 read(is, CharT{'%'}, width, modified, *fmt);
6735 command = nullptr;
6736 width = -1;
6737 modified = CharT{};
6738 }
6739 else
6740 read(is, *fmt);
6741
6742 break;
6743 case 'r':
6744 if (command)
6745 {
6746 if (modified == CharT{})
6747 {
6748#if !ONLY_C_LOCALE
6749 ios::iostate err = ios::goodbit;
6750 f.get(is, nullptr, is, err, &tm, command, fmt+1);
6751 if ((err & ios::failbit) == 0)
6752 {
6753 checked_set(H, tm.tm_hour, not_a_hour, is);
6754 checked_set(M, tm.tm_min, not_a_hour, is);
6755 checked_set(s, duration_cast<Duration>(seconds{tm.tm_sec}),
6756 not_a_second, is);
6757 }
6758 is.setstate(err);
6759#else
6760 // "%I:%M:%S %p"
6761 using dfs = detail::decimal_format_seconds<Duration>;
6762 constexpr const auto w = Duration::period::den == 1 ? 2 : 3 + dfs::width;
6763 long double S{};
6764 int tI = not_a_hour_12_value;
6765 int tM = not_a_minute;
6766 read(is, ru{tI, 1, 2}, CharT{':'}, ru{tM, 1, 2},
6767 CharT{':'}, rld{S, 1, w});
6768 checked_set(I, tI, not_a_hour_12_value, is);
6769 checked_set(M, tM, not_a_minute, is);
6770 checked_set(s, round_i<Duration>(duration<long double>{S}),
6771 not_a_second, is);
6772 ws(is);
6773 auto nm = detail::ampm_names();
6774 auto i = detail::scan_keyword(is, nm.first, nm.second) - nm.first;
6775 checked_set(p, static_cast<int>(i), not_a_ampm, is);
6776#endif
6777 }
6778 else
6779 read(is, CharT{'%'}, width, modified, *fmt);
6780 command = nullptr;
6781 width = -1;
6782 modified = CharT{};
6783 }
6784 else
6785 read(is, *fmt);
6786 break;
6787 case 'R':
6788 if (command)
6789 {
6790 if (modified == CharT{})
6791 {
6792 int tH = not_a_hour;
6793 int tM = not_a_minute;
6794 read(is, ru{tH, 1, 2}, CharT{'\0'}, CharT{':'}, CharT{'\0'},
6795 ru{tM, 1, 2}, CharT{'\0'});
6796 checked_set(H, tH, not_a_hour, is);
6797 checked_set(M, tM, not_a_minute, is);
6798 }
6799 else
6800 read(is, CharT{'%'}, width, modified, *fmt);
6801 command = nullptr;
6802 width = -1;
6803 modified = CharT{};
6804 }
6805 else
6806 read(is, *fmt);
6807 break;
6808 case 'S':
6809 if (command)
6810 {
6811 #if !ONLY_C_LOCALE
6812 if (modified == CharT{})
6813#else
6814 if (modified != CharT{'E'})
6815#endif
6816 {
6817 using dfs = detail::decimal_format_seconds<Duration>;
6818 constexpr const auto w = Duration::period::den == 1 ? 2 : 3 + dfs::width;
6819 long double S{};
6820 read(is, rld{S, 1, width == -1 ? w : static_cast<unsigned>(width)});
6821 checked_set(s, round_i<Duration>(duration<long double>{S}),
6822 not_a_second, is);
6823 }
6824#if !ONLY_C_LOCALE
6825 else if (modified == CharT{'O'})
6826 {
6827 ios::iostate err = ios::goodbit;
6828 f.get(is, nullptr, is, err, &tm, command, fmt+1);
6829 if ((err & ios::failbit) == 0)
6830 checked_set(s, duration_cast<Duration>(seconds{tm.tm_sec}),
6831 not_a_second, is);
6832 is.setstate(err);
6833 }
6834#endif
6835 else
6836 read(is, CharT{'%'}, width, modified, *fmt);
6837 command = nullptr;
6838 width = -1;
6839 modified = CharT{};
6840 }
6841 else
6842 read(is, *fmt);
6843 break;
6844 case 'T':
6845 if (command)
6846 {
6847 if (modified == CharT{})
6848 {
6849 using dfs = detail::decimal_format_seconds<Duration>;
6850 constexpr const auto w = Duration::period::den == 1 ? 2 : 3 + dfs::width;
6851 int tH = not_a_hour;
6852 int tM = not_a_minute;
6853 long double S{};
6854 read(is, ru{tH, 1, 2}, CharT{':'}, ru{tM, 1, 2},
6855 CharT{':'}, rld{S, 1, w});
6856 checked_set(H, tH, not_a_hour, is);
6857 checked_set(M, tM, not_a_minute, is);
6858 checked_set(s, round_i<Duration>(duration<long double>{S}),
6859 not_a_second, is);
6860 }
6861 else
6862 read(is, CharT{'%'}, width, modified, *fmt);
6863 command = nullptr;
6864 width = -1;
6865 modified = CharT{};
6866 }
6867 else
6868 read(is, *fmt);
6869 break;
6870 case 'Y':
6871 if (command)
6872 {
6873#if !ONLY_C_LOCALE
6874 if (modified == CharT{})
6875#else
6876 if (modified != CharT{'O'})
6877#endif
6878 {
6879 int tY = not_a_year;
6880 read(is, rs{tY, 1, width == -1 ? 4u : static_cast<unsigned>(width)});
6881 checked_set(Y, tY, not_a_year, is);
6882 }
6883#if !ONLY_C_LOCALE
6884 else if (modified == CharT{'E'})
6885 {
6886 ios::iostate err = ios::goodbit;
6887 f.get(is, nullptr, is, err, &tm, command, fmt+1);
6888 if ((err & ios::failbit) == 0)
6889 checked_set(Y, tm.tm_year + 1900, not_a_year, is);
6890 is.setstate(err);
6891 }
6892#endif
6893 else
6894 read(is, CharT{'%'}, width, modified, *fmt);
6895 command = nullptr;
6896 width = -1;
6897 modified = CharT{};
6898 }
6899 else
6900 read(is, *fmt);
6901 break;
6902 case 'y':
6903 if (command)
6904 {
6905#if !ONLY_C_LOCALE
6906 if (modified == CharT{})
6907#endif
6908 {
6909 int ty = not_a_2digit_year;
6910 read(is, ru{ty, 1, width == -1 ? 2u : static_cast<unsigned>(width)});
6911 checked_set(y, ty, not_a_2digit_year, is);
6912 }
6913#if !ONLY_C_LOCALE
6914 else
6915 {
6916 ios::iostate err = ios::goodbit;
6917 f.get(is, nullptr, is, err, &tm, command, fmt+1);
6918 if ((err & ios::failbit) == 0)
6919 checked_set(Y, tm.tm_year + 1900, not_a_year, is);
6920 is.setstate(err);
6921 }
6922#endif
6923 command = nullptr;
6924 width = -1;
6925 modified = CharT{};
6926 }
6927 else
6928 read(is, *fmt);
6929 break;
6930 case 'g':
6931 if (command)
6932 {
6933 if (modified == CharT{})
6934 {
6935 int tg = not_a_2digit_year;
6936 read(is, ru{tg, 1, width == -1 ? 2u : static_cast<unsigned>(width)});
6937 checked_set(g, tg, not_a_2digit_year, is);
6938 }
6939 else
6940 read(is, CharT{'%'}, width, modified, *fmt);
6941 command = nullptr;
6942 width = -1;
6943 modified = CharT{};
6944 }
6945 else
6946 read(is, *fmt);
6947 break;
6948 case 'G':
6949 if (command)
6950 {
6951 if (modified == CharT{})
6952 {
6953 int tG = not_a_year;
6954 read(is, rs{tG, 1, width == -1 ? 4u : static_cast<unsigned>(width)});
6955 checked_set(G, tG, not_a_year, is);
6956 }
6957 else
6958 read(is, CharT{'%'}, width, modified, *fmt);
6959 command = nullptr;
6960 width = -1;
6961 modified = CharT{};
6962 }
6963 else
6964 read(is, *fmt);
6965 break;
6966 case 'U':
6967 if (command)
6968 {
6969 if (modified == CharT{})
6970 {
6971 int tU = not_a_week_num;
6972 read(is, ru{tU, 1, width == -1 ? 2u : static_cast<unsigned>(width)});
6973 checked_set(U, tU, not_a_week_num, is);
6974 }
6975 else
6976 read(is, CharT{'%'}, width, modified, *fmt);
6977 command = nullptr;
6978 width = -1;
6979 modified = CharT{};
6980 }
6981 else
6982 read(is, *fmt);
6983 break;
6984 case 'V':
6985 if (command)
6986 {
6987 if (modified == CharT{})
6988 {
6989 int tV = not_a_week_num;
6990 read(is, ru{tV, 1, width == -1 ? 2u : static_cast<unsigned>(width)});
6991 checked_set(V, tV, not_a_week_num, is);
6992 }
6993 else
6994 read(is, CharT{'%'}, width, modified, *fmt);
6995 command = nullptr;
6996 width = -1;
6997 modified = CharT{};
6998 }
6999 else
7000 read(is, *fmt);
7001 break;
7002 case 'W':
7003 if (command)
7004 {
7005 if (modified == CharT{})
7006 {
7007 int tW = not_a_week_num;
7008 read(is, ru{tW, 1, width == -1 ? 2u : static_cast<unsigned>(width)});
7009 checked_set(W, tW, not_a_week_num, is);
7010 }
7011 else
7012 read(is, CharT{'%'}, width, modified, *fmt);
7013 command = nullptr;
7014 width = -1;
7015 modified = CharT{};
7016 }
7017 else
7018 read(is, *fmt);
7019 break;
7020 case 'E':
7021 case 'O':
7022 if (command)
7023 {
7024 if (modified == CharT{})
7025 {
7026 modified = *fmt;
7027 }
7028 else
7029 {
7030 read(is, CharT{'%'}, width, modified, *fmt);
7031 command = nullptr;
7032 width = -1;
7033 modified = CharT{};
7034 }
7035 }
7036 else
7037 read(is, *fmt);
7038 break;
7039 case '%':
7040 if (command)
7041 {
7042 if (modified == CharT{})
7043 read(is, *fmt);
7044 else
7045 read(is, CharT{'%'}, width, modified, *fmt);
7046 command = nullptr;
7047 width = -1;
7048 modified = CharT{};
7049 }
7050 else
7051 command = fmt;
7052 break;
7053 case 'z':
7054 if (command)
7055 {
7056 int tH, tM;
7057 minutes toff = not_a_offset;
7058 bool neg = false;
7059 auto ic = is.peek();
7060 if (!Traits::eq_int_type(ic, Traits::eof()))
7061 {
7062 auto c = static_cast<char>(Traits::to_char_type(ic));
7063 if (c == '-')
7064 neg = true;
7065 }
7066 if (modified == CharT{})
7067 {
7068 read(is, rs{tH, 2, 2});
7069 if (!is.fail())
7070 toff = hours{std::abs(tH)};
7071 if (is.good())
7072 {
7073 ic = is.peek();
7074 if (!Traits::eq_int_type(ic, Traits::eof()))
7075 {
7076 auto c = static_cast<char>(Traits::to_char_type(ic));
7077 if ('0' <= c && c <= '9')
7078 {
7079 read(is, ru{tM, 2, 2});
7080 if (!is.fail())
7081 toff += minutes{tM};
7082 }
7083 }
7084 }
7085 }
7086 else
7087 {
7088 read(is, rs{tH, 1, 2});
7089 if (!is.fail())
7090 toff = hours{std::abs(tH)};
7091 if (is.good())
7092 {
7093 ic = is.peek();
7094 if (!Traits::eq_int_type(ic, Traits::eof()))
7095 {
7096 auto c = static_cast<char>(Traits::to_char_type(ic));
7097 if (c == ':')
7098 {
7099 (void)is.get();
7100 read(is, ru{tM, 2, 2});
7101 if (!is.fail())
7102 toff += minutes{tM};
7103 }
7104 }
7105 }
7106 }
7107 if (neg)
7108 toff = -toff;
7109 checked_set(temp_offset, toff, not_a_offset, is);
7110 command = nullptr;
7111 width = -1;
7112 modified = CharT{};
7113 }
7114 else
7115 read(is, *fmt);
7116 break;
7117 case 'Z':
7118 if (command)
7119 {
7120 if (modified == CharT{})
7121 {
7122 std::basic_string<CharT, Traits, Alloc> buf;
7123 while (is.rdstate() == std::ios::goodbit)
7124 {
7125 auto i = is.rdbuf()->sgetc();
7126 if (Traits::eq_int_type(i, Traits::eof()))
7127 {
7128 is.setstate(ios::eofbit);
7129 break;
7130 }
7131 auto wc = Traits::to_char_type(i);
7132 auto c = static_cast<char>(wc);
7133 // is c a valid time zone name or abbreviation character?
7134 if (!(CharT{1} < wc && wc < CharT{127}) || !(isalnum(c) ||
7135 c == '_' || c == '/' || c == '-' || c == '+'))
7136 break;
7137 buf.push_back(c);
7138 is.rdbuf()->sbumpc();
7139 }
7140 if (buf.empty())
7141 is.setstate(ios::failbit);
7142 checked_set(temp_abbrev, buf, {}, is);
7143 }
7144 else
7145 read(is, CharT{'%'}, width, modified, *fmt);
7146 command = nullptr;
7147 width = -1;
7148 modified = CharT{};
7149 }
7150 else
7151 read(is, *fmt);
7152 break;
7153 default:
7154 if (command)
7155 {
7156 if (width == -1 && modified == CharT{} && '0' <= *fmt && *fmt <= '9')
7157 {
7158 width = static_cast<char>(*fmt) - '0';
7159 while ('0' <= fmt[1] && fmt[1] <= '9')
7160 width = 10*width + static_cast<char>(*++fmt) - '0';
7161 }
7162 else
7163 {
7164 if (modified == CharT{})
7165 read(is, CharT{'%'}, width, *fmt);
7166 else
7167 read(is, CharT{'%'}, width, modified, *fmt);
7168 command = nullptr;
7169 width = -1;
7170 modified = CharT{};
7171 }
7172 }
7173 else // !command
7174 {
7175 if (isspace(static_cast<unsigned char>(*fmt)))
7176 {
7177 // space matches 0 or more white space characters
7178 if (is.good())
7179 ws(is);
7180 }
7181 else
7182 read(is, *fmt);
7183 }
7184 break;
7185 }
7186 }
7187 // is.fail() || *fmt == CharT{}
7188 if (is.rdstate() == ios::goodbit && command)
7189 {
7190 if (modified == CharT{})
7191 read(is, CharT{'%'}, width);
7192 else
7193 read(is, CharT{'%'}, width, modified);
7194 }
7195 if (!is.fail())
7196 {
7197 if (y != not_a_2digit_year)
7198 {
7199 // Convert y and an std::optional C to Y
7200 if (!(0 <= y && y <= 99))
7201 goto broken;
7202 if (C == not_a_century)
7203 {
7204 if (Y == not_a_year)
7205 {
7206 if (y >= 69)
7207 C = 19;
7208 else
7209 C = 20;
7210 }
7211 else
7212 {
7213 C = (Y >= 0 ? Y : Y-100) / 100;
7214 }
7215 }
7216 int tY;
7217 if (C >= 0)
7218 tY = 100*C + y;
7219 else
7220 tY = 100*(C+1) - (y == 0 ? 100 : y);
7221 if (Y != not_a_year && Y != tY)
7222 goto broken;
7223 Y = tY;
7224 }
7225 if (g != not_a_2digit_year)
7226 {
7227 // Convert g and an std::optional C to G
7228 if (!(0 <= g && g <= 99))
7229 goto broken;
7230 if (C == not_a_century)
7231 {
7232 if (G == not_a_year)
7233 {
7234 if (g >= 69)
7235 C = 19;
7236 else
7237 C = 20;
7238 }
7239 else
7240 {
7241 C = (G >= 0 ? G : G-100) / 100;
7242 }
7243 }
7244 int tG;
7245 if (C >= 0)
7246 tG = 100*C + g;
7247 else
7248 tG = 100*(C+1) - (g == 0 ? 100 : g);
7249 if (G != not_a_year && G != tG)
7250 goto broken;
7251 G = tG;
7252 }
7253 if (Y < static_cast<int>(year::min()) || Y > static_cast<int>(year::max()))
7254 Y = not_a_year;
7255 bool computed = false;
7256 if (G != not_a_year && V != not_a_week_num && wd != not_a_weekday)
7257 {
7258 year_month_day ymd_trial = sys_days(year{G-1}/December/Thursday[last]) +
7259 (Monday-Thursday) + weeks{V-1} +
7260 (weekday{static_cast<unsigned>(wd)}-Monday);
7261 if (Y == not_a_year)
7262 Y = static_cast<int>(ymd_trial.year());
7263 else if (year{Y} != ymd_trial.year())
7264 goto broken;
7265 if (m == not_a_month)
7266 m = static_cast<int>(static_cast<unsigned>(ymd_trial.month()));
7267 else if (month(static_cast<unsigned>(m)) != ymd_trial.month())
7268 goto broken;
7269 if (d == not_a_day)
7270 d = static_cast<int>(static_cast<unsigned>(ymd_trial.day()));
7271 else if (day(static_cast<unsigned>(d)) != ymd_trial.day())
7272 goto broken;
7273 computed = true;
7274 }
7275 if (Y != not_a_year && U != not_a_week_num && wd != not_a_weekday)
7276 {
7277 year_month_day ymd_trial = sys_days(year{Y}/January/Sunday[1]) +
7278 weeks{U-1} +
7279 (weekday{static_cast<unsigned>(wd)} - Sunday);
7280 if (Y == not_a_year)
7281 Y = static_cast<int>(ymd_trial.year());
7282 else if (year{Y} != ymd_trial.year())
7283 goto broken;
7284 if (m == not_a_month)
7285 m = static_cast<int>(static_cast<unsigned>(ymd_trial.month()));
7286 else if (month(static_cast<unsigned>(m)) != ymd_trial.month())
7287 goto broken;
7288 if (d == not_a_day)
7289 d = static_cast<int>(static_cast<unsigned>(ymd_trial.day()));
7290 else if (day(static_cast<unsigned>(d)) != ymd_trial.day())
7291 goto broken;
7292 computed = true;
7293 }
7294 if (Y != not_a_year && W != not_a_week_num && wd != not_a_weekday)
7295 {
7296 year_month_day ymd_trial = sys_days(year{Y}/January/Monday[1]) +
7297 weeks{W-1} +
7298 (weekday{static_cast<unsigned>(wd)} - Monday);
7299 if (Y == not_a_year)
7300 Y = static_cast<int>(ymd_trial.year());
7301 else if (year{Y} != ymd_trial.year())
7302 goto broken;
7303 if (m == not_a_month)
7304 m = static_cast<int>(static_cast<unsigned>(ymd_trial.month()));
7305 else if (month(static_cast<unsigned>(m)) != ymd_trial.month())
7306 goto broken;
7307 if (d == not_a_day)
7308 d = static_cast<int>(static_cast<unsigned>(ymd_trial.day()));
7309 else if (day(static_cast<unsigned>(d)) != ymd_trial.day())
7310 goto broken;
7311 computed = true;
7312 }
7313 if (j != not_a_doy && Y != not_a_year)
7314 {
7315 auto ymd_trial = year_month_day{local_days(year{Y}/1/1) + days{j-1}};
7316 if (m == not_a_month)
7317 m = static_cast<int>(static_cast<unsigned>(ymd_trial.month()));
7318 else if (month(static_cast<unsigned>(m)) != ymd_trial.month())
7319 goto broken;
7320 if (d == not_a_day)
7321 d = static_cast<int>(static_cast<unsigned>(ymd_trial.day()));
7322 else if (day(static_cast<unsigned>(d)) != ymd_trial.day())
7323 goto broken;
7324 j = not_a_doy;
7325 }
7326 auto ymd = year{Y}/m/d;
7327 if (ymd.ok())
7328 {
7329 if (wd == not_a_weekday)
7330 wd = static_cast<int>((weekday(sys_days(ymd)) - Sunday).count());
7331 else if (wd != static_cast<int>((weekday(sys_days(ymd)) - Sunday).count()))
7332 goto broken;
7333 if (!computed)
7334 {
7335 if (G != not_a_year || V != not_a_week_num)
7336 {
7337 sys_days sd = ymd;
7338 auto G_trial = year_month_day{sd + days{3}}.year();
7339 auto start = sys_days((G_trial - years{1})/December/Thursday[last]) +
7340 (Monday - Thursday);
7341 if (sd < start)
7342 {
7343 --G_trial;
7344 if (V != not_a_week_num)
7345 start = sys_days((G_trial - years{1})/December/Thursday[last])
7346 + (Monday - Thursday);
7347 }
7348 if (G != not_a_year && G != static_cast<int>(G_trial))
7349 goto broken;
7350 if (V != not_a_week_num)
7351 {
7352 auto V_trial = duration_cast<weeks>(sd - start).count() + 1;
7353 if (V != V_trial)
7354 goto broken;
7355 }
7356 }
7357 if (U != not_a_week_num)
7358 {
7359 auto start = sys_days(Sunday[1]/January/ymd.year());
7360 auto U_trial = floor<weeks>(sys_days(ymd) - start).count() + 1;
7361 if (U != U_trial)
7362 goto broken;
7363 }
7364 if (W != not_a_week_num)
7365 {
7366 auto start = sys_days(Monday[1]/January/ymd.year());
7367 auto W_trial = floor<weeks>(sys_days(ymd) - start).count() + 1;
7368 if (W != W_trial)
7369 goto broken;
7370 }
7371 }
7372 }
7373 fds.ymd = ymd;
7374 if (I != not_a_hour_12_value)
7375 {
7376 if (!(1 <= I && I <= 12))
7377 goto broken;
7378 if (p != not_a_ampm)
7379 {
7380 // p is in [0, 1] == [AM, PM]
7381 // Store trial H in I
7382 if (I == 12)
7383 --p;
7384 I += p*12;
7385 // Either set H from I or make sure H and I are consistent
7386 if (H == not_a_hour)
7387 H = I;
7388 else if (I != H)
7389 goto broken;
7390 }
7391 else // p == not_a_ampm
7392 {
7393 // if H, make sure H and I could be consistent
7394 if (H != not_a_hour)
7395 {
7396 if (I == 12)
7397 {
7398 if (H != 0 && H != 12)
7399 goto broken;
7400 }
7401 else if (!(I == H || I == H+12))
7402 {
7403 goto broken;
7404 }
7405 }
7406 else // I is ambiguous, AM or PM?
7407 goto broken;
7408 }
7409 }
7410 if (H != not_a_hour)
7411 {
7412 fds.has_tod = true;
7413 fds.tod = hh_mm_ss<Duration>{hours{H}};
7414 }
7415 if (M != not_a_minute)
7416 {
7417 fds.has_tod = true;
7418 fds.tod.m_ = minutes{M};
7419 }
7420 if (s != not_a_second)
7421 {
7422 fds.has_tod = true;
7423 fds.tod.s_ = detail::decimal_format_seconds<Duration>{s};
7424 }
7425 if (j != not_a_doy)
7426 {
7427 fds.has_tod = true;
7428 fds.tod.h_ += hours{days{j}};
7429 }
7430 if (wd != not_a_weekday)
7431 fds.wd = weekday{static_cast<unsigned>(wd)};
7432 if (abbrev != nullptr)
7433 *abbrev = std::move(temp_abbrev);
7434 if (offset != nullptr && temp_offset != not_a_offset)
7435 *offset = temp_offset;
7436 }
7437 return is;
7438 }
7439broken:
7440 is.setstate(ios::failbit);
7441 return is;
7442}
7443
7444template <class CharT, class Traits, class Alloc = std::allocator<CharT>>
7445std::basic_istream<CharT, Traits>&
7446from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt, year& y,
7447 std::basic_string<CharT, Traits, Alloc>* abbrev = nullptr,
7448 std::chrono::minutes* offset = nullptr)
7449{
7450 using CT = std::chrono::seconds;
7451 fields<CT> fds{};
7452 gul17::date::from_stream(is, fmt, fds, abbrev, offset);
7453 if (!fds.ymd.year().ok())
7454 is.setstate(std::ios::failbit);
7455 if (!is.fail())
7456 y = fds.ymd.year();
7457 return is;
7458}
7459
7460template <class CharT, class Traits, class Alloc = std::allocator<CharT>>
7461std::basic_istream<CharT, Traits>&
7462from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt, month& m,
7463 std::basic_string<CharT, Traits, Alloc>* abbrev = nullptr,
7464 std::chrono::minutes* offset = nullptr)
7465{
7466 using CT = std::chrono::seconds;
7467 fields<CT> fds{};
7468 gul17::date::from_stream(is, fmt, fds, abbrev, offset);
7469 if (!fds.ymd.month().ok())
7470 is.setstate(std::ios::failbit);
7471 if (!is.fail())
7472 m = fds.ymd.month();
7473 return is;
7474}
7475
7476template <class CharT, class Traits, class Alloc = std::allocator<CharT>>
7477std::basic_istream<CharT, Traits>&
7478from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt, day& d,
7479 std::basic_string<CharT, Traits, Alloc>* abbrev = nullptr,
7480 std::chrono::minutes* offset = nullptr)
7481{
7482 using CT = std::chrono::seconds;
7483 fields<CT> fds{};
7484 gul17::date::from_stream(is, fmt, fds, abbrev, offset);
7485 if (!fds.ymd.day().ok())
7486 is.setstate(std::ios::failbit);
7487 if (!is.fail())
7488 d = fds.ymd.day();
7489 return is;
7490}
7491
7492template <class CharT, class Traits, class Alloc = std::allocator<CharT>>
7493std::basic_istream<CharT, Traits>&
7494from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt, weekday& wd,
7495 std::basic_string<CharT, Traits, Alloc>* abbrev = nullptr,
7496 std::chrono::minutes* offset = nullptr)
7497{
7498 using CT = std::chrono::seconds;
7499 fields<CT> fds{};
7500 gul17::date::from_stream(is, fmt, fds, abbrev, offset);
7501 if (!fds.wd.ok())
7502 is.setstate(std::ios::failbit);
7503 if (!is.fail())
7504 wd = fds.wd;
7505 return is;
7506}
7507
7508template <class CharT, class Traits, class Alloc = std::allocator<CharT>>
7509std::basic_istream<CharT, Traits>&
7510from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt, year_month& ym,
7511 std::basic_string<CharT, Traits, Alloc>* abbrev = nullptr,
7512 std::chrono::minutes* offset = nullptr)
7513{
7514 using CT = std::chrono::seconds;
7515 fields<CT> fds{};
7516 gul17::date::from_stream(is, fmt, fds, abbrev, offset);
7517 if (!fds.ymd.month().ok())
7518 is.setstate(std::ios::failbit);
7519 if (!is.fail())
7520 ym = fds.ymd.year()/fds.ymd.month();
7521 return is;
7522}
7523
7524template <class CharT, class Traits, class Alloc = std::allocator<CharT>>
7525std::basic_istream<CharT, Traits>&
7526from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt, month_day& md,
7527 std::basic_string<CharT, Traits, Alloc>* abbrev = nullptr,
7528 std::chrono::minutes* offset = nullptr)
7529{
7530 using CT = std::chrono::seconds;
7531 fields<CT> fds{};
7532 gul17::date::from_stream(is, fmt, fds, abbrev, offset);
7533 if (!fds.ymd.month().ok() || !fds.ymd.day().ok())
7534 is.setstate(std::ios::failbit);
7535 if (!is.fail())
7536 md = fds.ymd.month()/fds.ymd.day();
7537 return is;
7538}
7539
7540template <class CharT, class Traits, class Alloc = std::allocator<CharT>>
7541std::basic_istream<CharT, Traits>&
7542from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
7543 year_month_day& ymd, std::basic_string<CharT, Traits, Alloc>* abbrev = nullptr,
7544 std::chrono::minutes* offset = nullptr)
7545{
7546 using CT = std::chrono::seconds;
7547 fields<CT> fds{};
7548 gul17::date::from_stream(is, fmt, fds, abbrev, offset);
7549 if (!fds.ymd.ok())
7550 is.setstate(std::ios::failbit);
7551 if (!is.fail())
7552 ymd = fds.ymd;
7553 return is;
7554}
7555
7556template <class Duration, class CharT, class Traits, class Alloc = std::allocator<CharT>>
7557std::basic_istream<CharT, Traits>&
7558from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
7559 sys_time<Duration>& tp, std::basic_string<CharT, Traits, Alloc>* abbrev = nullptr,
7560 std::chrono::minutes* offset = nullptr)
7561{
7562 using CT = typename std::common_type<Duration, std::chrono::seconds>::type;
7563 using detail::round_i;
7564 std::chrono::minutes offset_local{};
7565 auto offptr = offset ? offset : &offset_local;
7566 fields<CT> fds{};
7567 fds.has_tod = true;
7568 gul17::date::from_stream(is, fmt, fds, abbrev, offptr);
7569 if (!fds.ymd.ok() || !fds.tod.in_conventional_range())
7570 is.setstate(std::ios::failbit);
7571 if (!is.fail())
7572 tp = round_i<Duration>(sys_days(fds.ymd) - *offptr + fds.tod.to_duration());
7573 return is;
7574}
7575
7576template <class Duration, class CharT, class Traits, class Alloc = std::allocator<CharT>>
7577std::basic_istream<CharT, Traits>&
7578from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
7579 local_time<Duration>& tp, std::basic_string<CharT, Traits, Alloc>* abbrev = nullptr,
7580 std::chrono::minutes* offset = nullptr)
7581{
7582 using CT = typename std::common_type<Duration, std::chrono::seconds>::type;
7583 using detail::round_i;
7584 fields<CT> fds{};
7585 fds.has_tod = true;
7586 gul17::date::from_stream(is, fmt, fds, abbrev, offset);
7587 if (!fds.ymd.ok() || !fds.tod.in_conventional_range())
7588 is.setstate(std::ios::failbit);
7589 if (!is.fail())
7590 tp = round_i<Duration>(local_seconds{local_days(fds.ymd)} + fds.tod.to_duration());
7591 return is;
7592}
7593
7594template <class Rep, class Period, class CharT, class Traits, class Alloc = std::allocator<CharT>>
7595std::basic_istream<CharT, Traits>&
7596from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
7597 std::chrono::duration<Rep, Period>& d,
7598 std::basic_string<CharT, Traits, Alloc>* abbrev = nullptr,
7599 std::chrono::minutes* offset = nullptr)
7600{
7601 using Duration = std::chrono::duration<Rep, Period>;
7602 using CT = typename std::common_type<Duration, std::chrono::seconds>::type;
7603 using detail::round_i;
7604 fields<CT> fds{};
7605 gul17::date::from_stream(is, fmt, fds, abbrev, offset);
7606 if (!fds.has_tod)
7607 is.setstate(std::ios::failbit);
7608 if (!is.fail())
7609 d = round_i<Duration>(fds.tod.to_duration());
7610 return is;
7611}
7612
7613template <class Parsable, class CharT, class Traits = std::char_traits<CharT>,
7614 class Alloc = std::allocator<CharT>>
7615struct parse_manip
7616{
7617 const std::basic_string<CharT, Traits, Alloc> format_;
7618 Parsable& tp_;
7619 std::basic_string<CharT, Traits, Alloc>* abbrev_;
7620 std::chrono::minutes* offset_;
7621
7622public:
7623 parse_manip(std::basic_string<CharT, Traits, Alloc> format, Parsable& tp,
7624 std::basic_string<CharT, Traits, Alloc>* abbrev = nullptr,
7625 std::chrono::minutes* offset = nullptr)
7626 : format_(std::move(format))
7627 , tp_(tp)
7628 , abbrev_(abbrev)
7629 , offset_(offset)
7630 {}
7631
7632 parse_manip(const CharT* format, Parsable& tp,
7633 std::basic_string<CharT, Traits, Alloc>* abbrev = nullptr,
7634 std::chrono::minutes* offset = nullptr)
7635 : format_(format)
7636 , tp_(tp)
7637 , abbrev_(abbrev)
7638 , offset_(offset)
7639 {}
7640
7641 parse_manip(std::basic_string_view<CharT, Traits> format, Parsable& tp,
7642 std::basic_string<CharT, Traits, Alloc>* abbrev = nullptr,
7643 std::chrono::minutes* offset = nullptr)
7644 : format_(format)
7645 , tp_(tp)
7646 , abbrev_(abbrev)
7647 , offset_(offset)
7648 {}
7649};
7650
7651template <class Parsable, class CharT, class Traits, class Alloc>
7652std::basic_istream<CharT, Traits>&
7653operator>>(std::basic_istream<CharT, Traits>& is,
7654 const parse_manip<Parsable, CharT, Traits, Alloc>& x)
7655{
7656 return gul17::date::from_stream(is, x.format_.c_str(), x.tp_, x.abbrev_, x.offset_);
7657}
7658
7659template <class Parsable, class CharT, class Traits, class Alloc>
7660inline auto
7661parse(const std::basic_string<CharT, Traits, Alloc>& format, Parsable& tp)
7662 -> decltype(gul17::date::from_stream(std::declval<std::basic_istream<CharT, Traits>&>(),
7663 format.c_str(), tp),
7664 parse_manip<Parsable, CharT, Traits, Alloc>{format, tp})
7665{
7666 return {format, tp};
7667}
7668
7669template <class Parsable, class CharT, class Traits, class Alloc>
7670inline auto
7671parse(const std::basic_string<CharT, Traits, Alloc>& format, Parsable& tp,
7672 std::basic_string<CharT, Traits, Alloc>& abbrev)
7673 -> decltype(gul17::date::from_stream(std::declval<std::basic_istream<CharT, Traits>&>(),
7674 format.c_str(), tp, &abbrev),
7675 parse_manip<Parsable, CharT, Traits, Alloc>{format, tp, &abbrev})
7676{
7677 return {format, tp, &abbrev};
7678}
7679
7680template <class Parsable, class CharT, class Traits, class Alloc>
7681inline auto
7682parse(const std::basic_string<CharT, Traits, Alloc>& format, Parsable& tp,
7683 std::chrono::minutes& offset)
7684 -> decltype(gul17::date::from_stream(std::declval<std::basic_istream<CharT, Traits>&>(),
7685 format.c_str(), tp,
7686 std::declval<std::basic_string<CharT, Traits, Alloc>*>(),
7687 &offset),
7688 parse_manip<Parsable, CharT, Traits, Alloc>{format, tp, nullptr, &offset})
7689{
7690 return {format, tp, nullptr, &offset};
7691}
7692
7693template <class Parsable, class CharT, class Traits, class Alloc>
7694inline auto
7695parse(const std::basic_string<CharT, Traits, Alloc>& format, Parsable& tp,
7696 std::basic_string<CharT, Traits, Alloc>& abbrev, std::chrono::minutes& offset)
7697 -> decltype(gul17::date::from_stream(std::declval<std::basic_istream<CharT, Traits>&>(),
7698 format.c_str(), tp, &abbrev, &offset),
7699 parse_manip<Parsable, CharT, Traits, Alloc>{format, tp, &abbrev, &offset})
7700{
7701 return {format, tp, &abbrev, &offset};
7702}
7703
7704// const CharT* formats
7705
7706template <class Parsable, class CharT>
7707inline auto
7708parse(const CharT* format, Parsable& tp)
7709 -> decltype(gul17::date::from_stream(std::declval<std::basic_istream<CharT>&>(), format, tp),
7710 parse_manip<Parsable, CharT>{format, tp})
7711{
7712 return {format, tp};
7713}
7714
7715template <class Parsable, class CharT, class Traits, class Alloc>
7716inline auto
7717parse(const CharT* format, Parsable& tp, std::basic_string<CharT, Traits, Alloc>& abbrev)
7718 -> decltype(gul17::date::from_stream(std::declval<std::basic_istream<CharT, Traits>&>(), format,
7719 tp, &abbrev),
7720 parse_manip<Parsable, CharT, Traits, Alloc>{format, tp, &abbrev})
7721{
7722 return {format, tp, &abbrev};
7723}
7724
7725template <class Parsable, class CharT>
7726inline auto
7727parse(const CharT* format, Parsable& tp, std::chrono::minutes& offset)
7728 -> decltype(gul17::date::from_stream(std::declval<std::basic_istream<CharT>&>(), format,
7729 tp, std::declval<std::basic_string<CharT>*>(), &offset),
7730 parse_manip<Parsable, CharT>{format, tp, nullptr, &offset})
7731{
7732 return {format, tp, nullptr, &offset};
7733}
7734
7735template <class Parsable, class CharT, class Traits, class Alloc>
7736inline auto
7737parse(const CharT* format, Parsable& tp,
7738 std::basic_string<CharT, Traits, Alloc>& abbrev, std::chrono::minutes& offset)
7739 -> decltype(gul17::date::from_stream(std::declval<std::basic_istream<CharT, Traits>&>(), format,
7740 tp, &abbrev, &offset),
7741 parse_manip<Parsable, CharT, Traits, Alloc>{format, tp, &abbrev, &offset})
7742{
7743 return {format, tp, &abbrev, &offset};
7744}
7745
7746// duration streaming
7747
7748template <class CharT, class Traits, class Rep, class Period>
7749inline
7750std::basic_ostream<CharT, Traits>&
7751operator<<(std::basic_ostream<CharT, Traits>& os,
7752 const std::chrono::duration<Rep, Period>& d)
7753{
7754 return os << detail::make_string<CharT, Traits>::from(d.count()) +
7755 detail::get_units<CharT>(typename Period::type{});
7756}
7757
7758} // namespace date
7759} // namespace gul17
7760
7761#ifdef _MSC_VER
7762# pragma warning(pop)
7763#endif
7764
7765#ifdef __GNUC__
7766# pragma GCC diagnostic pop
7767#endif
7768
7770
7771#endif // GUL17_DATE_H_
auto constexpr bit_set(unsigned bit) noexcept -> ReturnT
Set a bit in an integral type.
Definition bit_manip.h:121
constexpr auto abs(ValueT n) noexcept -> std::enable_if_t< std::is_unsigned< ValueT >::value, ValueT >
Compute the absolute value of a number.
Definition num_util.h:53
Namespace gul17 contains all functions and classes of the General Utility Library.
Definition doxygen.h:26