-
Notifications
You must be signed in to change notification settings - Fork 1.5k
/
chrono
6009 lines (5193 loc) · 260 KB
/
chrono
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
// chrono standard header
// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#ifndef _CHRONO_
#define _CHRONO_
#include <yvals_core.h>
#if _STL_COMPILER_PREPROCESSOR
#include <__msvc_chrono.hpp>
#if _HAS_CXX17
#include <system_error>
#include <xfilesystem_abi.h>
#include <xstring>
#endif // _HAS_CXX17
#if _HAS_CXX20
#include <__msvc_tzdb.hpp>
#include <atomic>
#include <cmath>
#include <compare>
#include <cstdint>
#include <forward_list>
#include <istream>
#include <memory>
#include <optional>
#include <sstream>
#include <string>
#include <vector>
#include <xloctime>
#include <xthreads.h>
#ifdef __cpp_lib_concepts
#include <concepts>
#include <format>
#include <iomanip>
#endif // defined(__cpp_lib_concepts)
#endif // _HAS_CXX20
#pragma pack(push, _CRT_PACKING)
#pragma warning(push, _STL_WARNING_LEVEL)
#pragma warning(disable : _STL_DISABLED_WARNINGS)
_STL_DISABLE_CLANG_WARNINGS
#pragma push_macro("new")
#undef new
_STD_BEGIN
#if _HAS_CXX17
_NODISCARD inline int _Check_convert_result(const __std_fs_convert_result _Result) {
if (_Result._Err != __std_win_error::_Success) {
_Throw_system_error_from_std_win_error(_Result._Err);
}
return _Result._Len;
}
template <class _Traits, class _Alloc>
_NODISCARD basic_string<typename _Traits::char_type, _Traits, _Alloc> _Convert_wide_to_narrow(
const __std_code_page _Code_page, const wstring_view _Input, const _Alloc& _Al) {
basic_string<typename _Traits::char_type, _Traits, _Alloc> _Output(_Al);
if (!_Input.empty()) {
if (_Input.size() > static_cast<size_t>(INT_MAX)) {
_Throw_system_error(errc::invalid_argument);
}
const int _Len = _Check_convert_result(
__std_fs_convert_wide_to_narrow(_Code_page, _Input.data(), static_cast<int>(_Input.size()), nullptr, 0));
_Output.resize(static_cast<size_t>(_Len));
const auto _Data_as_char = reinterpret_cast<char*>(_Output.data());
(void) _Check_convert_result(__std_fs_convert_wide_to_narrow(
_Code_page, _Input.data(), static_cast<int>(_Input.size()), _Data_as_char, _Len));
}
return _Output;
}
#endif // _HAS_CXX17
#if _HAS_CXX20
namespace chrono {
// [time.duration.io]
#define _IF_PERIOD_RETURN_SUFFIX_ELSE(_TYPE, _SUFFIX) \
if constexpr (is_same_v<_Period, _TYPE>) { \
if constexpr (is_same_v<_CharT, char>) { \
return _SUFFIX; \
} else { \
return L##_SUFFIX; \
} \
} else
template <class _CharT, class _Period>
_NODISCARD constexpr const _CharT* _Get_literal_unit_suffix() {
_IF_PERIOD_RETURN_SUFFIX_ELSE(atto, "as")
_IF_PERIOD_RETURN_SUFFIX_ELSE(femto, "fs")
_IF_PERIOD_RETURN_SUFFIX_ELSE(pico, "ps")
_IF_PERIOD_RETURN_SUFFIX_ELSE(nano, "ns")
_IF_PERIOD_RETURN_SUFFIX_ELSE(micro, "us")
_IF_PERIOD_RETURN_SUFFIX_ELSE(milli, "ms")
_IF_PERIOD_RETURN_SUFFIX_ELSE(centi, "cs")
_IF_PERIOD_RETURN_SUFFIX_ELSE(deci, "ds")
_IF_PERIOD_RETURN_SUFFIX_ELSE(seconds::period, "s")
_IF_PERIOD_RETURN_SUFFIX_ELSE(deca, "das")
_IF_PERIOD_RETURN_SUFFIX_ELSE(hecto, "hs")
_IF_PERIOD_RETURN_SUFFIX_ELSE(kilo, "ks")
_IF_PERIOD_RETURN_SUFFIX_ELSE(mega, "Ms")
_IF_PERIOD_RETURN_SUFFIX_ELSE(giga, "Gs")
_IF_PERIOD_RETURN_SUFFIX_ELSE(tera, "Ts")
_IF_PERIOD_RETURN_SUFFIX_ELSE(peta, "Ps")
_IF_PERIOD_RETURN_SUFFIX_ELSE(exa, "Es")
_IF_PERIOD_RETURN_SUFFIX_ELSE(minutes::period, "min")
_IF_PERIOD_RETURN_SUFFIX_ELSE(hours::period, "h")
_IF_PERIOD_RETURN_SUFFIX_ELSE(ratio<86400>, "d")
{
return nullptr;
}
}
#undef _IF_PERIOD_RETURN_SUFFIX_ELSE
template <class _CharT>
_NODISCARD _CharT* _Get_general_unit_suffix(_CharT* _Rnext, const intmax_t _Num, const intmax_t _Den) {
// Returns the head pointer of the string, built in reverse.
_STL_INTERNAL_CHECK(_Num > 0 && _Den > 0);
*--_Rnext = '\0';
*--_Rnext = 's';
*--_Rnext = ']';
if (_Den != 1) {
_Rnext = _UIntegral_to_buff(_Rnext, static_cast<uintmax_t>(_Den));
*--_Rnext = '/';
}
_Rnext = _UIntegral_to_buff(_Rnext, static_cast<uintmax_t>(_Num));
*--_Rnext = '[';
return _Rnext;
}
template <class _Period, class _CharT, class _Traits>
void _Write_unit_suffix(basic_ostream<_CharT, _Traits>& _Os) {
constexpr auto _Suffix = _Get_literal_unit_suffix<_CharT, _Period>();
if constexpr (_Suffix == nullptr) {
_CharT _Buffer[2 * (numeric_limits<intmax_t>::digits10 + 1) + 5] = {}; // 2 numbers + "[/]s\0"
const _CharT* const _Begin =
_Get_general_unit_suffix<_CharT>(_STD end(_Buffer), _Period::num, _Period::den);
_Os << _Begin;
} else {
_Os << _Suffix;
}
}
_EXPORT_STD template <class _CharT, class _Traits, class _Rep, class _Period>
basic_ostream<_CharT, _Traits>& operator<<(
basic_ostream<_CharT, _Traits>& _Os, const duration<_Rep, _Period>& _Dur) {
basic_ostringstream<_CharT, _Traits> _Sstr;
_Sstr.flags(_Os.flags());
_Sstr.imbue(_Os.getloc());
_Sstr.precision(_Os.precision());
_Sstr << _Dur.count();
_Write_unit_suffix<_Period>(_Sstr);
return _Os << _Sstr.str();
}
_EXPORT_STD struct local_t {};
_EXPORT_STD template <class _Duration>
using local_time = time_point<local_t, _Duration>;
_EXPORT_STD using local_seconds = local_time<seconds>;
_EXPORT_STD using local_days = local_time<days>;
_EXPORT_STD struct last_spec {
explicit last_spec() = default;
};
_EXPORT_STD inline constexpr last_spec last{};
_EXPORT_STD class day {
public:
day() = default;
constexpr explicit day(unsigned int _Val) noexcept : _Day{static_cast<unsigned char>(_Val)} {}
constexpr day& operator++() noexcept {
++_Day;
return *this;
}
constexpr day operator++(int) noexcept {
return day{_Day++};
}
constexpr day& operator--() noexcept {
--_Day;
return *this;
}
constexpr day operator--(int) noexcept {
return day{_Day--};
}
constexpr day& operator+=(const days& _Days) noexcept {
_Day += static_cast<unsigned char>(_Days.count());
return *this;
}
constexpr day& operator-=(const days& _Days) noexcept {
_Day -= static_cast<unsigned char>(_Days.count());
return *this;
}
_NODISCARD constexpr explicit operator unsigned int() const noexcept {
return _Day;
}
_NODISCARD constexpr bool ok() const noexcept {
return _Day >= 1 && _Day <= 31;
}
private:
unsigned char _Day;
};
_EXPORT_STD _NODISCARD constexpr bool operator==(const day& _Left, const day& _Right) noexcept {
return static_cast<unsigned int>(_Left) == static_cast<unsigned int>(_Right);
}
_EXPORT_STD _NODISCARD constexpr strong_ordering operator<=>(const day& _Left, const day& _Right) noexcept {
return static_cast<unsigned int>(_Left) <=> static_cast<unsigned int>(_Right);
}
_EXPORT_STD _NODISCARD constexpr day operator+(const day& _Left, const days& _Right) noexcept {
return day{static_cast<unsigned int>(_Left) + _Right.count()};
}
_EXPORT_STD _NODISCARD constexpr day operator+(const days& _Left, const day& _Right) noexcept {
return _Right + _Left;
}
_EXPORT_STD _NODISCARD constexpr day operator-(const day& _Left, const days& _Right) noexcept {
return day{static_cast<unsigned int>(_Left) - _Right.count()};
}
_EXPORT_STD _NODISCARD constexpr days operator-(const day& _Left, const day& _Right) noexcept {
return days{
static_cast<int>(static_cast<unsigned int>(_Left)) - static_cast<int>(static_cast<unsigned int>(_Right))};
}
_EXPORT_STD class month {
public:
month() = default;
constexpr explicit month(unsigned int _Val) noexcept : _Month{static_cast<unsigned char>(_Val)} {}
constexpr month& operator++() noexcept {
*this += months{1};
return *this;
}
constexpr month operator++(int) noexcept {
month _Temp{*this};
++*this;
return _Temp;
}
constexpr month& operator--() noexcept {
*this -= months{1};
return *this;
}
constexpr month operator--(int) noexcept {
month _Temp{*this};
--*this;
return _Temp;
}
constexpr month& operator+=(const months& _Months) noexcept;
constexpr month& operator-=(const months& _Months) noexcept;
_NODISCARD constexpr explicit operator unsigned int() const noexcept {
return _Month;
}
_NODISCARD constexpr bool ok() const noexcept {
return _Month >= 1 && _Month <= 12;
}
private:
unsigned char _Month;
};
_EXPORT_STD _NODISCARD constexpr bool operator==(const month& _Left, const month& _Right) noexcept {
return static_cast<unsigned int>(_Left) == static_cast<unsigned int>(_Right);
}
_EXPORT_STD _NODISCARD constexpr strong_ordering operator<=>(const month& _Left, const month& _Right) noexcept {
return static_cast<unsigned int>(_Left) <=> static_cast<unsigned int>(_Right);
}
_EXPORT_STD _NODISCARD constexpr month operator+(const month& _Left, const months& _Right) noexcept {
const auto _Mo = static_cast<long long>(static_cast<unsigned int>(_Left)) + (_Right.count() - 1);
const auto _Div = (_Mo >= 0 ? _Mo : _Mo - 11) / 12;
return month{static_cast<unsigned int>(_Mo - _Div * 12 + 1)};
}
_EXPORT_STD _NODISCARD constexpr month operator+(const months& _Left, const month& _Right) noexcept {
return _Right + _Left;
}
_EXPORT_STD _NODISCARD constexpr month operator-(const month& _Left, const months& _Right) noexcept {
return _Left + -_Right;
}
_EXPORT_STD _NODISCARD constexpr months operator-(const month& _Left, const month& _Right) noexcept {
const auto _Mo = static_cast<unsigned int>(_Left) - static_cast<unsigned int>(_Right);
return months{_Mo <= 11 ? _Mo : _Mo + 12};
}
constexpr month& month::operator+=(const months& _Months) noexcept {
*this = *this + _Months;
return *this;
}
constexpr month& month::operator-=(const months& _Months) noexcept {
*this = *this - _Months;
return *this;
}
_EXPORT_STD class year {
public:
year() = default;
constexpr explicit year(int _Val) noexcept : _Year{static_cast<short>(_Val)} {}
constexpr year& operator++() noexcept {
++_Year;
return *this;
}
constexpr year operator++(int) noexcept {
return year{_Year++};
}
constexpr year& operator--() noexcept {
--_Year;
return *this;
}
constexpr year operator--(int) noexcept {
return year{_Year--};
}
constexpr year& operator+=(const years& _Years) noexcept {
#ifdef __EDG__ // TRANSITION, VSO-1271098
_Year = static_cast<short>(_Year + _Years.count());
#else // ^^^ workaround / no workaround vvv
_Year += static_cast<short>(_Years.count());
#endif // ^^^ no workaround ^^^
return *this;
}
constexpr year& operator-=(const years& _Years) noexcept {
#ifdef __EDG__ // TRANSITION, VSO-1271098
_Year = static_cast<short>(_Year - _Years.count());
#else // ^^^ workaround / no workaround vvv
_Year -= static_cast<short>(_Years.count());
#endif // ^^^ no workaround ^^^
return *this;
}
_NODISCARD constexpr year operator+() const noexcept {
return *this;
}
_NODISCARD constexpr year operator-() const noexcept {
return year{-_Year};
}
_NODISCARD constexpr bool is_leap() const noexcept {
return _Year % 4 == 0 && (_Year % 100 != 0 || _Year % 400 == 0);
}
_NODISCARD constexpr explicit operator int() const noexcept {
return _Year;
}
_NODISCARD constexpr bool ok() const noexcept {
return _Year_min <= _Year && _Year <= _Year_max;
}
_NODISCARD static constexpr year(min)() noexcept {
return year{_Year_min};
}
_NODISCARD static constexpr year(max)() noexcept {
return year{_Year_max};
}
private:
short _Year;
static constexpr int _Year_min = -32767;
static constexpr int _Year_max = 32767;
};
_EXPORT_STD _NODISCARD constexpr bool operator==(const year& _Left, const year& _Right) noexcept {
return static_cast<int>(_Left) == static_cast<int>(_Right);
}
_EXPORT_STD _NODISCARD constexpr strong_ordering operator<=>(const year& _Left, const year& _Right) noexcept {
return static_cast<int>(_Left) <=> static_cast<int>(_Right);
}
_EXPORT_STD _NODISCARD constexpr year operator+(const year& _Left, const years& _Right) noexcept {
return year{static_cast<int>(_Left) + _Right.count()};
}
_EXPORT_STD _NODISCARD constexpr year operator+(const years& _Left, const year& _Right) noexcept {
return _Right + _Left;
}
_EXPORT_STD _NODISCARD constexpr year operator-(const year& _Left, const years& _Right) noexcept {
return _Left + -_Right;
}
_EXPORT_STD _NODISCARD constexpr years operator-(const year& _Left, const year& _Right) noexcept {
return years{static_cast<int>(_Left) - static_cast<int>(_Right)};
}
_EXPORT_STD class weekday_indexed;
_EXPORT_STD class weekday_last;
_EXPORT_STD class weekday {
public:
weekday() = default;
constexpr explicit weekday(unsigned int _Val) noexcept
: _Weekday{static_cast<unsigned char>(_Val == 7 ? 0 : _Val)} {}
constexpr weekday(const sys_days& _Sys_day) noexcept
: _Weekday{static_cast<unsigned char>(_Weekday_from_days(_Sys_day.time_since_epoch().count()))} {}
constexpr explicit weekday(const local_days& _Local_day) noexcept
: _Weekday{static_cast<unsigned char>(_Weekday_from_days(_Local_day.time_since_epoch().count()))} {}
constexpr weekday& operator++() noexcept {
return *this += days{1};
}
constexpr weekday operator++(int) noexcept {
weekday _Temp{*this};
++*this;
return _Temp;
}
constexpr weekday& operator--() noexcept {
return *this -= days{1};
}
constexpr weekday operator--(int) noexcept {
weekday _Temp{*this};
--*this;
return _Temp;
}
constexpr weekday& operator+=(const days& _Days) noexcept;
constexpr weekday& operator-=(const days& _Days) noexcept;
_NODISCARD constexpr unsigned int c_encoding() const noexcept {
return _Weekday;
}
_NODISCARD constexpr unsigned int iso_encoding() const noexcept {
return _Weekday == 0u ? 7u : _Weekday;
}
_NODISCARD constexpr bool ok() const noexcept {
return _Weekday <= 6;
}
_NODISCARD constexpr weekday_indexed operator[](unsigned int _Index) const noexcept;
_NODISCARD constexpr weekday_last operator[](last_spec) const noexcept;
private:
unsigned char _Weekday;
// courtesy of Howard Hinnant
// https://howardhinnant.github.io/date_algorithms.html#weekday_from_days
_NODISCARD static constexpr unsigned int _Weekday_from_days(int _Tp) noexcept {
return static_cast<unsigned int>(_Tp >= -4 ? (_Tp + 4) % 7 : (_Tp + 5) % 7 + 6);
}
};
_EXPORT_STD _NODISCARD constexpr bool operator==(const weekday& _Left, const weekday& _Right) noexcept {
return _Left.c_encoding() == _Right.c_encoding();
}
_EXPORT_STD _NODISCARD constexpr weekday operator+(const weekday& _Left, const days& _Right) noexcept {
const auto _Wd = static_cast<long long>(_Left.c_encoding()) + _Right.count();
const auto _Div = (_Wd >= 0 ? _Wd : _Wd - 6) / 7;
return weekday{static_cast<unsigned int>(_Wd - _Div * 7)};
}
_EXPORT_STD _NODISCARD constexpr weekday operator+(const days& _Left, const weekday& _Right) noexcept {
return _Right + _Left;
}
_EXPORT_STD _NODISCARD constexpr weekday operator-(const weekday& _Left, const days& _Right) noexcept {
return _Left + -_Right;
}
_EXPORT_STD _NODISCARD constexpr days operator-(const weekday& _Left, const weekday& _Right) noexcept {
const auto _Wd = _Left.c_encoding() - _Right.c_encoding();
const auto _Wk = _Wd <= 6 ? _Wd : _Wd + 7;
return days{_Wk};
}
constexpr weekday& weekday::operator+=(const days& _Days) noexcept {
*this = *this + _Days;
return *this;
}
constexpr weekday& weekday::operator-=(const days& _Days) noexcept {
*this = *this - _Days;
return *this;
}
_EXPORT_STD class weekday_indexed {
public:
weekday_indexed() = default;
constexpr weekday_indexed(const weekday& _Wd, unsigned int _Idx) noexcept
: _Weekday{_Wd}, _Index{static_cast<unsigned char>(_Idx)} {}
_NODISCARD constexpr weekday weekday() const noexcept {
return _Weekday;
}
_NODISCARD constexpr unsigned int index() const noexcept {
return _Index;
}
_NODISCARD constexpr bool ok() const noexcept {
return _Weekday.ok() && _Index >= 1 && _Index <= 5;
}
private:
_CHRONO weekday _Weekday;
unsigned char _Index;
};
_EXPORT_STD _NODISCARD constexpr bool operator==(
const weekday_indexed& _Left, const weekday_indexed& _Right) noexcept {
return _Left.weekday() == _Right.weekday() && _Left.index() == _Right.index();
}
_EXPORT_STD class weekday_last {
public:
constexpr explicit weekday_last(const weekday& _Wd) noexcept : _Weekday{_Wd} {}
_NODISCARD constexpr weekday weekday() const noexcept {
return _Weekday;
}
_NODISCARD constexpr bool ok() const noexcept {
return _Weekday.ok();
}
private:
_CHRONO weekday _Weekday;
};
_EXPORT_STD _NODISCARD constexpr bool operator==(const weekday_last& _Left, const weekday_last& _Right) noexcept {
return _Left.weekday() == _Right.weekday();
}
_NODISCARD constexpr weekday_indexed weekday::operator[](unsigned int _Index) const noexcept {
return {*this, _Index};
}
_NODISCARD constexpr weekday_last weekday::operator[](last_spec) const noexcept {
return weekday_last{*this};
}
_EXPORT_STD class month_day {
public:
month_day() = default;
constexpr month_day(const month& _Month_, const day& _Day_) noexcept : _Month{_Month_}, _Day{_Day_} {}
_NODISCARD constexpr month month() const noexcept {
return _Month;
}
_NODISCARD constexpr day day() const noexcept {
return _Day;
}
_NODISCARD constexpr bool ok() const noexcept {
if (!_Month.ok() || !_Day.ok()) {
return false;
}
const auto _Da = static_cast<unsigned int>(_Day);
const auto _Mo = static_cast<unsigned int>(_Month);
if (_Mo == 2) {
return _Da <= 29;
}
if (_Mo == 4 || _Mo == 6 || _Mo == 9 || _Mo == 11) {
return _Da <= 30;
}
return true;
}
private:
_CHRONO month _Month;
_CHRONO day _Day;
};
_EXPORT_STD _NODISCARD constexpr bool operator==(const month_day& _Left, const month_day& _Right) noexcept {
return _Left.month() == _Right.month() && _Left.day() == _Right.day();
}
_EXPORT_STD _NODISCARD constexpr strong_ordering operator<=>(
const month_day& _Left, const month_day& _Right) noexcept {
const auto _Comp = _Left.month() <=> _Right.month();
if (_Comp != 0) {
return _Comp;
}
return _Left.day() <=> _Right.day();
}
_EXPORT_STD class month_day_last {
public:
constexpr explicit month_day_last(const month& _Month_) noexcept : _Month{_Month_} {}
_NODISCARD constexpr month month() const noexcept {
return _Month;
}
_NODISCARD constexpr bool ok() const noexcept {
return _Month.ok();
}
private:
_CHRONO month _Month;
};
_EXPORT_STD _NODISCARD constexpr bool operator==(
const month_day_last& _Left, const month_day_last& _Right) noexcept {
return _Left.month() == _Right.month();
}
_EXPORT_STD _NODISCARD constexpr strong_ordering operator<=>(
const month_day_last& _Left, const month_day_last& _Right) noexcept {
return _Left.month() <=> _Right.month();
}
_EXPORT_STD class month_weekday {
public:
constexpr month_weekday(const month& _Month_, const weekday_indexed& _Wdi) noexcept
: _Month{_Month_}, _Weekday_index{_Wdi} {}
_NODISCARD constexpr month month() const noexcept {
return _Month;
}
_NODISCARD constexpr weekday_indexed weekday_indexed() const noexcept {
return _Weekday_index;
}
_NODISCARD constexpr bool ok() const noexcept {
return _Month.ok() && _Weekday_index.ok();
}
private:
_CHRONO month _Month;
_CHRONO weekday_indexed _Weekday_index;
};
_EXPORT_STD _NODISCARD constexpr bool operator==(const month_weekday& _Left, const month_weekday& _Right) noexcept {
return _Left.month() == _Right.month() && _Left.weekday_indexed() == _Right.weekday_indexed();
}
_EXPORT_STD class month_weekday_last {
public:
constexpr month_weekday_last(const month& _Month_, const weekday_last& _Wdl) noexcept
: _Month{_Month_}, _Weekday_last{_Wdl} {}
_NODISCARD constexpr month month() const noexcept {
return _Month;
}
_NODISCARD constexpr weekday_last weekday_last() const noexcept {
return _Weekday_last;
}
_NODISCARD constexpr bool ok() const noexcept {
return _Month.ok() && _Weekday_last.ok();
}
private:
_CHRONO month _Month;
_CHRONO weekday_last _Weekday_last;
};
_EXPORT_STD _NODISCARD constexpr bool operator==(
const month_weekday_last& _Left, const month_weekday_last& _Right) noexcept {
return _Left.month() == _Right.month() && _Left.weekday_last() == _Right.weekday_last();
}
_EXPORT_STD class year_month {
public:
year_month() = default;
constexpr year_month(const year& _Year_, const month& _Month_) noexcept : _Year{_Year_}, _Month{_Month_} {}
_NODISCARD constexpr year year() const noexcept {
return _Year;
}
_NODISCARD constexpr month month() const noexcept {
return _Month;
}
template <int = 0>
constexpr year_month& operator+=(const months& _Months) noexcept;
template <int = 0>
constexpr year_month& operator-=(const months& _Months) noexcept;
constexpr year_month& operator+=(const years& _Years) noexcept;
constexpr year_month& operator-=(const years& _Years) noexcept;
_NODISCARD constexpr bool ok() const noexcept {
return _Year.ok() && _Month.ok();
}
private:
_CHRONO year _Year;
_CHRONO month _Month;
};
_EXPORT_STD _NODISCARD constexpr bool operator==(const year_month& _Left, const year_month& _Right) noexcept {
return _Left.year() == _Right.year() && _Left.month() == _Right.month();
}
_EXPORT_STD _NODISCARD constexpr strong_ordering operator<=>(
const year_month& _Left, const year_month& _Right) noexcept {
const auto _Comp = _Left.year() <=> _Right.year();
if (_Comp != 0) {
return _Comp;
}
return _Left.month() <=> _Right.month();
}
_EXPORT_STD template <int = 0>
_NODISCARD constexpr year_month operator+(const year_month& _Left, const months& _Right) noexcept {
const auto _Mo = static_cast<long long>(static_cast<unsigned int>(_Left.month())) + (_Right.count() - 1);
const auto _Div = (_Mo >= 0 ? _Mo : _Mo - 11) / 12;
return year_month{_Left.year() + years{_Div}, month{static_cast<unsigned int>(_Mo - _Div * 12 + 1)}};
}
_EXPORT_STD template <int = 0>
_NODISCARD constexpr year_month operator+(const months& _Left, const year_month& _Right) noexcept {
return _Right + _Left;
}
_EXPORT_STD template <int = 0>
_NODISCARD constexpr year_month operator-(const year_month& _Left, const months& _Right) noexcept {
return _Left + -_Right;
}
_EXPORT_STD _NODISCARD constexpr months operator-(const year_month& _Left, const year_month& _Right) noexcept {
return _Left.year() - _Right.year()
+ months{static_cast<int>(static_cast<unsigned int>(_Left.month()))
- static_cast<int>(static_cast<unsigned int>(_Right.month()))};
}
_EXPORT_STD _NODISCARD constexpr year_month operator+(const year_month& _Left, const years& _Right) noexcept {
return {year{_Left.year() + _Right}, _Left.month()};
}
_EXPORT_STD _NODISCARD constexpr year_month operator+(const years& _Left, const year_month& _Right) noexcept {
return _Right + _Left;
}
_EXPORT_STD _NODISCARD constexpr year_month operator-(const year_month& _Left, const years& _Right) noexcept {
return _Left + -_Right;
}
template <int>
constexpr year_month& year_month::operator+=(const months& _Months) noexcept {
*this = *this + _Months;
return *this;
}
template <int>
constexpr year_month& year_month::operator-=(const months& _Months) noexcept {
*this = *this - _Months;
return *this;
}
constexpr year_month& year_month::operator+=(const years& _Years) noexcept {
*this = *this + _Years;
return *this;
}
constexpr year_month& year_month::operator-=(const years& _Years) noexcept {
*this = *this - _Years;
return *this;
}
// To prevent UB by going out of bounds, four extra days with an invalid day are added.
inline constexpr day _Last_day_table[] = {day{31}, day{28}, day{31}, day{30}, day{31}, day{30}, day{31}, day{31},
day{30}, day{31}, day{30}, day{31}, day{255}, day{255}, day{255}, day{255}};
_NODISCARD constexpr day _Last_day(const year& _Year, const month& _Month) {
if (_Month == month{2} && _Year.is_leap()) {
return day{29};
}
return _Last_day_table[(static_cast<unsigned int>(_Month) - 1) & 0xF];
}
_EXPORT_STD class year_month_day_last;
_EXPORT_STD class year_month_day {
public:
year_month_day() = default;
constexpr year_month_day(const year& _Year_, const month& _Month_, const day& _Day_) noexcept
: _Year{_Year_}, _Month{_Month_}, _Day{_Day_} {}
constexpr year_month_day(const year_month_day_last& _Ymdl) noexcept;
constexpr year_month_day(const sys_days& _Sys_days) noexcept
: year_month_day{_Civil_from_days(_Sys_days.time_since_epoch().count())} {}
constexpr explicit year_month_day(const local_days& _Local_days) noexcept
: year_month_day{_Civil_from_days(_Local_days.time_since_epoch().count())} {}
template <int = 0>
constexpr year_month_day& operator+=(const months& _Months) noexcept;
template <int = 0>
constexpr year_month_day& operator-=(const months& _Months) noexcept;
constexpr year_month_day& operator+=(const years& _Years) noexcept;
constexpr year_month_day& operator-=(const years& _Years) noexcept;
_NODISCARD constexpr year year() const noexcept {
return _Year;
}
_NODISCARD constexpr month month() const noexcept {
return _Month;
}
_NODISCARD constexpr day day() const noexcept {
return _Day;
}
_NODISCARD constexpr operator sys_days() const noexcept {
return sys_days{_Days_from_civil()};
}
_NODISCARD constexpr explicit operator local_days() const noexcept {
return local_days{static_cast<sys_days>(*this).time_since_epoch()};
}
_NODISCARD constexpr bool ok() const noexcept {
if (!_Year.ok() || !_Month.ok()) {
return false;
}
return _Day >= _CHRONO day{1} && _Day <= _Last_day(_Year, _Month);
}
_NODISCARD constexpr int _Calculate_weekday() const noexcept {
const int _Day_int = static_cast<int>(static_cast<unsigned int>(_Day));
const int _Month_int = static_cast<int>(static_cast<unsigned int>(_Month));
const int _Era_year = static_cast<int>(_Year) - (_Month_int <= 2);
const int _Era = (_Era_year >= 0 ? _Era_year : _Era_year - 399) / 400;
const int _Yoe = _Era_year - _Era * 400;
const int _Yday_era = ((979 * (_Month_int + (_Month_int > 2 ? -3 : 9)) + 19) >> 5) + _Day_int - 1;
const int _Doe = ((1461 * _Yoe) >> 2) - _Yoe / 100 + _Yday_era;
return (_Doe + 3) % 7; // the era began on a Wednesday
}
private:
_CHRONO year _Year;
_CHRONO month _Month;
_CHRONO day _Day;
// _Civil_from_days and _Days_from_civil perform conversions between the dates in the (proleptic) Gregorian
// calendar and the continuous count of days since 1970-01-01.
// To simplify the handling of leap days (February 29th), the algorithm below uses a modified calendar
// internally, in which each year begins on March 1st, while January and February belong to the previous year.
// We denote the modified year and month number as _Yp and _Mp. We also define modified centuries that begin on
// each modified year whose _Yp is a multiple of 100.
// _Mp | Month | Day of Year
// --- | --------- | -----------
// 0 | March | [ 0, 30]
// 1 | April | [ 31, 60]
// 2 | May | [ 61, 91]
// 3 | June | [ 92, 121]
// 4 | July | [122, 152]
// 5 | August | [153, 183]
// 6 | September | [184, 213]
// 7 | October | [214, 244]
// 8 | November | [245, 274]
// 9 | December | [275, 305]
// 10 | January | [306, 336]
// 11 | February | [337, 365] on leap years, [337, 364] on regular years
// _Yp | First Day | Last Day (inclusive) | Leap Year?
// --- | ----------- | -------------------- | ----------
// -4 | -0004-03-01 | -0003-02-28 | No
// -3 | -0003-03-01 | -0002-02-28 | No
// -2 | -0002-03-01 | -0001-02-28 | No
// -1 | -0001-03-01 | 0000-02-29 | Yes
// 0 | 0000-03-01 | 0001-02-28 | No
// 1 | 0001-03-01 | 0002-02-28 | No
// 2 | 0002-03-01 | 0003-02-28 | No
// 3 | 0003-03-01 | 0004-02-29 | Yes
// _Century | First Day | Last Day (inclusive) | Long Century?
// -------- | ----------- | -------------------- | -------------
// -4 | -0400-03-01 | -0300-02-28 | No
// -3 | -0300-03-01 | -0200-02-28 | No
// -2 | -0200-03-01 | -0100-02-28 | No
// -1 | -0100-03-01 | 0000-02-29 | Yes
// 0 | 0000-03-01 | 0100-02-28 | No
// 1 | 0100-03-01 | 0200-02-28 | No
// 2 | 0200-03-01 | 0300-02-28 | No
// 3 | 0300-03-01 | 0400-02-29 | Yes
// The structure of the modified calendar:
// 1 ) It has a period of 4 centuries.
// 2 ) Each calendar period (146097 days) contains 3 regular centuries followed by a long century (36525 days).
// 3 ) Each regular century (36524 days) contains 24 regular 4-year spans followed by a short 4-year span.
// 3') Each long century (36525 days) contains 25 regular 4-year spans.
// 4 ) Each regular 4-year span (1461 days) contains 3 regular years followed by a leap year.
// 4') Each short 4-year span (1460 days) contains 4 regular years.
// Formula 1: Compute _Day_of_year of the first day of month _Mp
//
// _Day_of_year = (979 * _Mp + 19) >> 5
//
// A more well-known formula is 30 * _Mp + floor((3 * _Mp + 2) / 5) or floor((153 * _Mp + 2) / 5), which is used
// in Howard Hinnant's paper.
//
// The formula above returns the same result for all _Mp in [0, 11].
// Note that 979 / 2^5 = 30.59375 ~= 30.6 = 153 / 5.
// Formula 1': Compute _Mp from _Day_of_year
//
// _Mp = (535 * _Day_of_year + 333) >> 14
//
// Howard Hinnant's paper uses floor((5 * _Day_of_year + 2) / 153), the inverse of floor((153 * _Mp + 2) / 5) or
// ceil((153 * _Mp - 2) / 5).
//
// The formula above returns the same result for all _Day_of_year in [0, 365].
// Note that 2^14 / 535 = 30.624... ~= 30.6 = 153 / 5.
// Formula 2: Compute _Zx of the first day of year _Yp, where _Zx is the continuous count of days since
// 0000-03-01.
//
// _Zx = ((1461 * _Yp) >> 2) - _Century + (_Century >> 2)
//
// Start with multiplying by the number of days in regular years (365), add one day for the leap year in each
// 4-year span, subtract one day for the short 4-year span in each century, and finally add one day for the long
// century in each calendar period. This gives us 365 * _Yp + floor(_Yp / 4) - _Century + floor(_Century / 4).
// Formula 2-1: Compute _Day_of_century of the first day of year _Year_of_century
//
// _Day_of_century = (1461 * _Year_of_century) >> 2
//
// Start with multiplying by the number of days in regular years (365), add one day for the leap year in each
// 4-year span. This gives us 365 * _Year_of_century + floor(_Year_of_century / 4)
// == floor(1461 * _Year_of_century / 4).
// Formula 2-1': Compute _Year_of_century from _Day_of_century
//
// _Year_of_century = (91867 * (_Day_of_century + 1)) >> 25
//
// The inverse of floor(1461 * _Year_of_century / 4) or ceil((1461 * _Year_of_century - 3) / 4) is
// floor((4 * _Day_of_century + 3) / 1461).
//
// The formula above returns the same result for all _Day_of_century in [0, 36524].
// Note that 2^25 / 91867 = 365.2501... ~= 365.25 = 1461 / 4.
// Formula 2-2: Compute _Zx of the first day of century _Century, where _Zx is the continuous count of days
// since 0000-03-01.
//
// _Zx = (146097 * _Century) >> 2
//
// Start with multiplying by the number of days in regular centuries (36524), add one day for the long century
// in each calendar period. This gives us 36524 * _Century + floor(_Century / 4) = floor(146097 * _Century / 4).
// Formula 2-2': Compute _Century from _Zx, where _Zx is the continuous count of days since 0000-03-01.
//
// _Century = floor((4 * _Zx + 3) / 146097)
//
// This is the inverse of floor(146097 * _Year_of_century / 4) or ceil((146097 * _Year_of_century - 3) / 4)
// courtesy of Howard Hinnant
// https://howardhinnant.github.io/date_algorithms.html#civil_from_days
_NODISCARD static constexpr year_month_day _Civil_from_days(int _Tp) noexcept {
static_assert(numeric_limits<unsigned int>::digits >= 32);
static_assert(numeric_limits<int>::digits >= 26);
const int _Zx = _Tp + 719468; // Shift epoch to 0000-03-01
// Formula 2-2'
const int _Century = (_Zx >= 0 ? 4 * _Zx + 3 : 4 * _Zx - 146093) / 146097;
// Formula 2-2
const unsigned int _Day_of_century =
static_cast<unsigned int>(_Zx - ((146097 * _Century) >> 2)); // [0, 36524]
// Formula 2-1'
const unsigned int _Year_of_century = (91867 * (_Day_of_century + 1)) >> 25; // [0, 99]
const int _Yp = static_cast<int>(_Year_of_century) + _Century * 100; // Where March is the first month
// Formula 2-1
const unsigned int _Day_of_year = _Day_of_century - ((1461 * _Year_of_century) >> 2); // [0, 365]
// Formula 1'
const unsigned int _Mp = (535 * _Day_of_year + 333) >> 14; // [0, 11]
// Formula 1
const unsigned int _Day = _Day_of_year - ((979 * _Mp + 19) >> 5) + 1; // [1, 31]
const unsigned int _Month = _Mp + (_Mp < 10 ? 3 : static_cast<unsigned int>(-9)); // [1, 12]
return year_month_day{_CHRONO year{_Yp + (_Month <= 2)}, _CHRONO month{_Month}, _CHRONO day{_Day}};
}
// courtesy of Howard Hinnant
// https://howardhinnant.github.io/date_algorithms.html#days_from_civil
_NODISCARD constexpr days _Days_from_civil() const noexcept {
static_assert(numeric_limits<unsigned int>::digits >= 18);
static_assert(numeric_limits<int>::digits >= 26);
const unsigned int _Mo = static_cast<unsigned int>(_Month); // [1, 12]
const int _Yp = static_cast<int>(_Year) - (_Mo <= 2);
const int _Century = (_Yp >= 0 ? _Yp : _Yp - 99) / 100;
const unsigned int _Mp = _Mo + (_Mo > 2 ? static_cast<unsigned int>(-3) : 9); // [0, 11]
// Formula 1
const int _Day_of_year = static_cast<int>(((979 * _Mp + 19) >> 5) + static_cast<unsigned int>(_Day)) - 1;
// Formula 2
return days{((1461 * _Yp) >> 2) - _Century + (_Century >> 2) + _Day_of_year - 719468};
}
};
_EXPORT_STD _NODISCARD constexpr bool operator==(
const year_month_day& _Left, const year_month_day& _Right) noexcept {
return _Left.year() == _Right.year() && _Left.month() == _Right.month() && _Left.day() == _Right.day();
}
_EXPORT_STD _NODISCARD constexpr strong_ordering operator<=>(
const year_month_day& _Left, const year_month_day& _Right) noexcept {
auto _Comp = _Left.year() <=> _Right.year();
if (_Comp != 0) {
return _Comp;
}
_Comp = _Left.month() <=> _Right.month();
if (_Comp != 0) {
return _Comp;
}
return _Left.day() <=> _Right.day();
}
_EXPORT_STD template <int = 0>
_NODISCARD constexpr year_month_day operator+(const year_month_day& _Left, const months& _Right) noexcept {
const auto _Ym = year_month{_Left.year(), _Left.month()} + _Right;