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