Stroika Library 3.0d24
 
Loading...
Searching...
No Matches
Date.h
Go to the documentation of this file.
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2026. All rights reserved
3 */
4#ifndef _Stroika_Foundation_Time_Date_h_
5#define _Stroika_Foundation_Time_Date_h_ 1
6
7#include "Stroika/Foundation/StroikaPreComp.h"
8
9#include <chrono>
10#include <climits>
11#include <compare>
12#include <string>
13
15#include "Stroika/Foundation/Common/Common.h"
17#include "Stroika/Foundation/DataExchange/ValidationStrategy.h"
18#include "Stroika/Foundation/Execution/Exceptions.h"
21
22/**
23 * \file
24 *
25 * \note Code-Status: <a href="Code-Status.md#Release">Release</a>
26 *
27 * TODO:
28 * @todo Could optimize the Format/Parse calls for case without locale to just hardwire implementation
29 * using sprintf/scanf (as we had before 2.1b10); only performance optimization and unclear it would help
30 *
31 * @todo I'm not sure eCurrentLocale_WithZerosStripped is a good idea. Not sure if better
32 * to use separate format print arg or???
33 *
34 * @todo It would be highly desirable to allow this date code to represent larger/smaller dates
35 * (without the Julian calendar restriction).
36 * That maybe a longer term issue.
37 *
38 * Consider representing as big struct
39 * o Like with STRUCT DATETIME or struct tm
40 * o Int year
41 * o Int month
42 * o And maybe store cached string reps for common cases as optimization and
43 * store cached second-offset (mutable) for quick compares
44 * o Note in docs for future versions the min/max date COULD be expanded
45 */
46
47namespace Stroika::Foundation::Time {
48
49 class Duration;
50
51 using Characters::String;
52
53 using chrono::month;
54 using chrono::months;
55
56 // clang-format off
57 using chrono::January;
58 using chrono::February;
59 using chrono::March;
60 using chrono::April;
61 using chrono::May;
62 using chrono::June;
63 using chrono::July;
64 using chrono::August;
65 using chrono::September;
66 using chrono::October;
67 using chrono::November;
68 using chrono::December;
69 // clang-format on
70
71 using chrono::weekday;
72
73 // clang-format off
74 using chrono::Sunday;
75 using chrono::Monday;
76 using chrono::Tuesday;
77 using chrono::Wednesday;
78 using chrono::Thursday;
79 using chrono::Friday;
80 using chrono::Saturday;
81 // clang-format on
82
83 using chrono::day;
84 using chrono::days;
85
86 using chrono::year;
87
88 using chrono::year_month_day;
89
90 using std::literals::chrono_literals::operator""d; // day
91 using std::literals::chrono_literals::operator""y; // year
92 using std::chrono::operator/; // year/month/day -> year_month_day
93
94 /**
95 * \brief Simple wrapper on std::chrono::weekday, with some helpful validation properties (assures constructed 'ok'). But not necessary to use - use just 'weekday' in most places
96 *
97 * \note - DayOfWeek was an enum in Stroika v2.1, so this is a significant change.
98 *
99 * \note DayOfWeek can be converted from/to unsigned int.
100 *
101 * \note not [[nodiscard]] cuz can use CTOR just for quiet validation
102 */
103 struct DayOfWeek : weekday {
104 /**
105 * For the purpose of integer constructors, 0==Sunday, 1==Monday, and so on
106 */
108 constexpr DayOfWeek (unsigned int w, DataExchange::ValidationStrategy validationStrategy = DataExchange::ValidationStrategy::eAssertion);
109
110 public:
111 [[deprecated ("Since Stroika v3.0d1, use chrono::Sunday")]] static constexpr weekday eSunday{Sunday};
112 [[deprecated ("Since Stroika v3.0d1, use chrono::Monday")]] static constexpr weekday eMonday{Monday};
113 [[deprecated ("Since Stroika v3.0d1, use chrono::Tuesday")]] static constexpr weekday eTuesday{Tuesday};
114 [[deprecated ("Since Stroika v3.0d1, use chrono::Wednesday")]] static constexpr weekday eWednesday{Wednesday};
115 [[deprecated ("Since Stroika v3.0d1, use chrono::Thursday")]] static constexpr weekday eThursday{Thursday};
116 [[deprecated ("Since Stroika v3.0d1, use chrono::Friday")]] static constexpr weekday eFriday{Friday};
117 [[deprecated ("Since Stroika v3.0d1, use chrono::Saturday")]] static constexpr weekday eSaturday{Saturday};
118 };
119
120 /**
121 * \brief Simple wrapper on std::chrono::month, with some helpful validation properties (assures constructed 'ok'). But not necessary to use - use just 'month' in most places
122 *
123 * \note - MonthOfYear was an enum in Stroika v2.1, so this is a significant change.
124 *
125 * \note MonthOfYear can be converted from/to unsigned int.
126 *
127 * \note not [[nodiscard]] cuz can use CTOR just for quiet validation
128 */
129 struct MonthOfYear : month {
130 /**
131 * For the purpose of integer constructors, 1==January, 2==February and so on (no zero).
132 */
135
136 public:
137 [[deprecated ("Since Stroika v3.0d1, use chrono::January")]] static constexpr chrono::month eJanuary{January};
138 [[deprecated ("Since Stroika v3.0d1, use chrono::February")]] static constexpr chrono::month eFebruary{February};
139 [[deprecated ("Since Stroika v3.0d1, use chrono::March")]] static constexpr chrono::month eMarch{March};
140 [[deprecated ("Since Stroika v3.0d1, use chrono::April")]] static constexpr chrono::month eApril{April};
141 [[deprecated ("Since Stroika v3.0d1, use chrono::May")]] static constexpr chrono::month eMay{May};
142 [[deprecated ("Since Stroika v3.0d1, use chrono::June")]] static constexpr chrono::month eJune{June};
143 [[deprecated ("Since Stroika v3.0d1, use chrono::July")]] static constexpr chrono::month eJuly{July};
144 [[deprecated ("Since Stroika v3.0d1, use chrono::August")]] static constexpr chrono::month eAugust{August};
145 [[deprecated ("Since Stroika v3.0d1, use chrono::September")]] static constexpr chrono::month eSeptember{September};
146 [[deprecated ("Since Stroika v3.0d1, use chrono::October")]] static constexpr chrono::month eOctober{October};
147 [[deprecated ("Since Stroika v3.0d1, use chrono::November")]] static constexpr chrono::month eNovember{November};
148 [[deprecated ("Since Stroika v3.0d1, use chrono::December")]] static constexpr chrono::month eDecember{December};
149 };
150
151 /**
152 * \brief Simple wrapper on std::chrono::day, with some helpful validation properties (assures constructed 'ok'). But not necessary to use - use just 'day' in most places
153 *
154 * \note - DayOfMonth was an enum in Stroika v2.1, so this is a significant change.
155 *
156 * \note DayOfMonth can be converted from/to unsigned int.
157 * \note You can use the suffix 'd' instead of DayOfMonth{n}
158 *
159 * \note not [[nodiscard]] cuz can use CTOR just for quiet validation
160 */
161 struct DayOfMonth : day {
162 /**
163 * For the purpose of integer constructors, 1==1st, 2==2nd, and so on (no zero)
164 */
167
168 public:
169 [[deprecated ("Since Stroika v3.0d1, use day{1} or 1d")]] static constexpr day e1{1};
170 [[deprecated ("Since Stroika v3.0d1, use day{2} or 2d")]] static constexpr day e2{2};
171 [[deprecated ("Since Stroika v3.0d1, use day{3}")]] static constexpr day e3{3};
172 [[deprecated ("Since Stroika v3.0d1, use day{4}")]] static constexpr day e4{4};
173 [[deprecated ("Since Stroika v3.0d1, use day{5}")]] static constexpr day e5{5};
174 [[deprecated ("Since Stroika v3.0d1, use day{6}")]] static constexpr day e6{6};
175 [[deprecated ("Since Stroika v3.0d1, use day{7}")]] static constexpr day e7{7};
176 [[deprecated ("Since Stroika v3.0d1, use day{8}")]] static constexpr day e8{8};
177 [[deprecated ("Since Stroika v3.0d1, use day{9}")]] static constexpr day e9{9};
178 [[deprecated ("Since Stroika v3.0d1, use day{10}")]] static constexpr day e10{10};
179 [[deprecated ("Since Stroika v3.0d1, use day{11}")]] static constexpr day e11{11};
180 [[deprecated ("Since Stroika v3.0d1, use day{12}")]] static constexpr day e12{12};
181 [[deprecated ("Since Stroika v3.0d1, use day{13}")]] static constexpr day e13{13};
182 [[deprecated ("Since Stroika v3.0d1, use day{14}")]] static constexpr day e14{14};
183 [[deprecated ("Since Stroika v3.0d1, use day{15}")]] static constexpr day e15{15};
184 [[deprecated ("Since Stroika v3.0d1, use day{16}")]] static constexpr day e16{16};
185 [[deprecated ("Since Stroika v3.0d1, use day{17}")]] static constexpr day e17{17};
186 [[deprecated ("Since Stroika v3.0d1, use day{18}")]] static constexpr day e18{18};
187 [[deprecated ("Since Stroika v3.0d1, use day{19}")]] static constexpr day e19{19};
188 [[deprecated ("Since Stroika v3.0d1, use day{20}")]] static constexpr day e20{20};
189 [[deprecated ("Since Stroika v3.0d1, use day{21}")]] static constexpr day e21{21};
190 [[deprecated ("Since Stroika v3.0d1, use day{22}")]] static constexpr day e22{22};
191 [[deprecated ("Since Stroika v3.0d1, use day{23}")]] static constexpr day e23{23};
192 [[deprecated ("Since Stroika v3.0d1, use day{24}")]] static constexpr day e24{24};
193 [[deprecated ("Since Stroika v3.0d1, use day{25}")]] static constexpr day e25{25};
194 [[deprecated ("Since Stroika v3.0d1, use day{26}")]] static constexpr day e26{26};
195 [[deprecated ("Since Stroika v3.0d1, use day{27}")]] static constexpr day e27{27};
196 [[deprecated ("Since Stroika v3.0d1, use day{28}")]] static constexpr day e28{28};
197 [[deprecated ("Since Stroika v3.0d1, use day{29}")]] static constexpr day e29{29};
198 [[deprecated ("Since Stroika v3.0d1, use day{30}")]] static constexpr day e30{30};
199 [[deprecated ("Since Stroika v3.0d1, use day{31}")]] static constexpr day e31{31};
200 };
201
202 /**
203 * \brief Simple wrapper on std::chrono::year, with some helpful validation properties (assures constructed 'ok'). But not necessary to use - use just 'year' in most places
204 *
205 * \note - Year was an enum in Stroika v2.1, so this is a significant change.
206 *
207 * \note Year can be converted from/to signed int.
208 *
209 * \note you can use the suffix y instead of Year{N} (assuming using namespace Foundation::Time).
210 *
211 * \note not [[nodiscard]] cuz can use CTOR just for quiet validation
212 */
213 struct Year : year {
214 /**
215 */
218
219 public:
220 /**
221 * \brief 4713 BC (no year zero)
222 *
223 * Was 1752 in Stroika v2.1
224 */
225 static constexpr year eFirstYear{-4712};
226
227 public:
228 /**
229 * Reason for current max-date:
230 * C:\Program Files (x86)\Windows Kits\10\Source\10.0.22000.0\ucrt\time\wcsftime.cpp
231 * _VALIDATE_RETURN(timeptr->tm_year >= -1900 && timeptr->tm_year <= 8099, EINVAL, false);
232 * -- LGP 2022-11-09
233 * Was SHRT_MAX - 1 in Stroika v2.1
234 */
235 static constexpr year eLastYear{8099};
236 };
237
238 /**
239 * \brief this defines undefined but important properties of the %x (read/write date) format string in stdc++ time_get/time_put
240 *
241 * This (rather important detail) appears to be left out of the std c++ specification for date/time formatting, and as a result
242 * each implementation varies. Attempt to capture the actual choices - so at least I can write regression tests that properly
243 * reflect expected Stroika behavior. And - perhaps - avoid the %x format string!
244 *
245 * @todo see if other format strings similarly unreliable. MAYBE the biggest lesson (obvious) is to not count on reading/writing dates
246 * in any locale-defined format (but for UIs this is a tricky constraint)?
247 *
248 * \note - These values all derived empirically (and checked in Stroika regression tests)
249 */
251 static constexpr bool kLocaleClassic_Write4DigitYear = false;
252 static constexpr bool kLocaleENUS_Write4DigitYear =
253#if defined(_MSC_VER)
254 true
255#elif defined(_GLIBCXX_RELEASE)
256 false
257#elif defined(_LIBCPP_VERSION)
258 true
259#else
260 true
261#endif
262 ;
263 };
264
265 /**
266 * Description:
267 * The Date class is (originally) based on SmallTalk-80, The Language & Its Implementation,
268 * page 108 (apx) - but changed to use Gregorian instead of Julian calendar.
269 *
270 * \note This class integrates neatly with the C++20 chrono date support. You can easily
271 * go back and forth (e.g. Date{std::chrono::year_month_day...}} or d.As<year_month_day> ())
272 *
273 * The main features of the Stroika Data class (compared to the std c++ date support):
274 *
275 * o Simpler to use/understand (Stroika 'Date' does about the same thing as a bevy of
276 * different chrono classes)
277 * o Stroika Date immutable (OK - difference not clearly advantage)
278 * o Validation (constructor DataExchange::ValidationStrategy)
279 * (no non-ok () Date objects in Stroika). Nice clear semantics about exceptions
280 * and assertions.
281 * o Easier to use formatting
282 * o ISO8601 formatting
283 * o Wraps needlessly complicated locale/facet API for formatting dates as Strings, or
284 * parsing them from strings.
285 * o Builtin support for Julian calendar (again - maybe this is a difference not advantage?)
286 *
287 * \note
288 * o Date stores date's internally as Julian days, and so is valid for any date > January 1, −4713;
289 * Also note sizeof (year_month_day) == sizeof (Date) == 4
290 *
291 * \par Miscellaneous references
292 * o According to https://en.wikipedia.org/wiki/Gregorian_calendar
293 * Britain and the British Empire (including the eastern part of what is
294 * now the United States) adopted the Gregorian calendar in 1752
295 * o https://aa.usno.navy.mil/data/JulianDate
296 * Best Julian date calculator I found (bad but best)
297 * o Proleptic Gregorian Calendar
298 * https://en.wikipedia.org/wiki/Gregorian_calendar#Proleptic_Gregorian_calendar
299 * o Julian Day Numer
300 * https://en.wikipedia.org/wiki/Julian_day
301 *
302 * Class Date knows about some obvious information:
303 * -> there are seven days in a week, each day having a symbolic name and
304 * an index 1..7
305 * -> there are twelve months in a year, each having a symbolic name and
306 * an index 1..12.
307 * -> months have 28..31 days and
308 * -> a particular year might be a leap year."
309 *
310 * NB: Date implies NO NOTION of timezone.
311 *
312 * \note The entire Date API is immutable - meaning that all methods are const (except constructor and assignment operator)
313 *
314 * \note Date constructors REQUIRE valid inputs, and any operations which might overflow throw range_error
315 * instead of creating invalid values.
316 *
317 * \note Would like to make Date inherit from Debug::AssertExternallySynchronizedChecker to assure its not accidentially modified, but
318 * that's difficult because its sometimes uses as a constexpr
319 *
320 * \note \em Thread-Safety <a href="Thread-Safety.md#C++-Standard-Thread-Safety">C++-Standard-Thread-Safety</a>
321 *
322 * \note <a href="Design-Overview.md#Comparisons">Comparisons</a>:
323 * static_assert (totally_ordered<Date>);
324 */
325 class Date {
326 public:
327 /*
328 * This refers to Julian Day Number - JDN - https://en.wikipedia.org/wiki/Julian_day
329 *
330 * \note This was called JulianRepType in Stroika v2.1
331 */
332 using JulianDayNumber = uint32_t;
333
334 public:
335 /**
336 * Sometimes want a signed type to compute differences.
337 */
339
340 public:
341 /**
342 * Define a few 'reference' points, which define the correspondence between year/month/day in the Gregorian(ish)
343 * calendar with.
344 *
345 * Generally, users of the Date class can ignore this detail. Its used to 'calibrate' the mapping between Julian dates and
346 * year month day dates.
347 */
349 year_month_day fYMD;
350 JulianDayNumber fJulianRep;
351 };
352
353 public:
354 /**
355 * Start of Julian Calendar (see https://docs.kde.org/trunk5/en/kstars/kstars/ai-julianday.html)
356 * JD=0, is January 1, 4713 BC (or -4712 January 1, since there was no year '0').
357 */
358 static constexpr ReferencePoint kStartOfJulianCalendar{-4712y / January / 1, 0};
359
360 public:
361 /**
362 * Start of UNIX time (see https://docs.kde.org/trunk5/en/kstars/kstars/ai-julianday.html, https://aa.usno.navy.mil/data/JulianDate)
363 */
364 static constexpr ReferencePoint kUNIXEpoch{1970y / January / 1, 2440588};
365
366 public:
367 /**
368 * See https://en.wikipedia.org/wiki/Gregorian_calendar
369 * September, 14d, 1752 (even this not sure of, but used this in Stroika v2.1)
370 *
371 * "Algorithm 199 from Communications of the ACM, Volume 6, No. 8, (Aug. 1963), p. 444.
372 * Gregorian calendar started on Sep. 14, 1752"
373 */
374 static constexpr ReferencePoint kGregorianCalendarEpoch{1752y / September / 14d, 2361222};
375
376 public:
377 /**
378 * The Stroika Date class works with any date after this date (apx 4000 BC), but mostly
379 * just very accurate post Gregorian Calendar era (1753 apx).
380 */
382 static_assert (kMinDateReference.fYMD.year () == Year::eFirstYear);
383
384 public:
385 /**
386 * Very hard to figure out how todo this. But this algorithm appears correct at least for dates > Gregorian Calendar era.
387 *
388 * Also, web is littered with Julian date converters that are wrong, somewhat wrong, or very wrong (at least all disagreeing).
389 * I used https://aa.usno.navy.mil/data/JulianDate as my reference/final arbiter/check (at least for dates past 1800).
390 */
391 constexpr static JulianDayNumber ToJulianRep (month m, day d, year y,
393 constexpr static JulianDayNumber
395
396 public:
397 /**
398 * Compute the month/day/year associated with a given Julian day number. NOTE, this is only
399 * really accurate (as of Stroika v3.0d1) for dates in the Gregorian Calendar epoch (roughly since 1753).
400 */
401 constexpr static year_month_day
403
404 public:
405 /**
406 * kMinJulianRep is defined (later) constexpr.
407 *
408 * \note In Stroika v2.1, 2361222, aka Date::ToJulianRep (September, 14d, year{1752})
409 * but now its around 4000BC (see kMinDateReference)
410 */
411 static const JulianDayNumber kMinJulianRep = kMinDateReference.fJulianRep;
412
413 public:
414 /**
415 * kMaxJulianRep is defined (later) constexpr.
416 */
417 static const JulianDayNumber kMaxJulianRep; // = Date::ToJulianRep (December, 31d, Year::eLastYear)
418
419 public:
420 class FormatException;
421
422 public:
423 /**
424 * if DataExchange::ValidationStrategy is NOT specified, or == DataExchange::ValidationStrategy::eAssertion, then
425 * \pre kMinJulianRep <= julianRep <= kMaxJulianRep AND Date::kMin <= d <= Date::kMax
426 * else if eThrow, then throw when arguments out of range.
427 *
428 * \par Example Usage
429 * \code
430 * Assert (1906y/May/12d == Date{1906y, May, 12d});
431 * \endcode
432 */
433 constexpr Date (Date&& src) noexcept = default;
434 constexpr Date (const Date& src) noexcept = default;
435 explicit constexpr Date (JulianDayNumber julianRep,
439
440 public:
441 /**
442 */
443 nonvirtual Date& operator= (Date&& rhs) noexcept = default;
444 nonvirtual Date& operator= (const Date& rhs) = default;
445
446 public:
447 /**
448 * Return the current Date - shorthand for DateTime::Now ().GetDate () (so uses localtime)
449 */
450 static Date Now () noexcept;
451
452 public:
453 /**
454 * \brief Y-M-D format - locale independent, and ISO-8601 date format standard
455 *
456 * \note sometimes represented as %F (see https://en.cppreference.com/w/cpp/chrono/c/wcsftime), but that's not supported in https://en.cppreference.com/w/cpp/locale/time_get/get.
457 * so equivalent to %Y-%m-%d
458 *
459 * \note this is LOCALE-INDEPENDENT
460 *
461 * \see kMonthDayYearFormat
462 *
463 * \note also used for XML
464 */
465 static constexpr string_view kISO8601Format = "%Y-%m-%d"sv;
466
467 public:
468 /**
469 * \note https://en.cppreference.com/w/cpp/locale/time_get/get
470 */
472
473 public:
474 /**
475 * \note https://en.cppreference.com/w/cpp/locale/time_get/get
476 */
478
479 public:
480 /**
481 * \brief classic (american) month-day-year format, but unlike %D, this uses %Y, so the 4-digit form of year
482 *
483 * \note https://en.cppreference.com/w/cpp/locale/time_get/get
484 * \note This format is LOCALE INDEPENDENT (according to https://en.cppreference.com/w/cpp/locale/time_get/get)
485 * \see kISO8601Format
486 */
487 static constexpr string_view kMonthDayYearFormat = "%m/%d/%Y"sv;
488
489 public:
490 /**
491 * Default formats used by Date::Parse () to parse time strings. The first of these - kLocaleStandardFormat, is
492 * the locale-specific date format.
493 */
495
496 public:
497 /**
498 * Note that for the consumedCharsInStringUpTo overload, the consumedCharsInStringUpTo is filled in with the position after the last
499 * character read (so before the next character to be read).
500 *
501 * \note Parse (... locale) with no formats specified, defaults to parsing with kDefaultParseFormats formats.
502 *
503 * \note if the locale is not specified, its assumed to be the current locale (locale{}))
504 *
505 * \note an empty string produces BadFormat exception.
506 *
507 * \see https://en.cppreference.com/w/cpp/locale/time_get/get for allowed formatPatterns
508 *
509 * \note when calling Parse with a format string and no locale, the default locale is assumed
510 */
512 static Date Parse (const String& rep, const locale& l, const Traversal::Iterable<String>& formatPatterns);
514 static Date Parse (const String& rep, const locale& l, size_t* consumedCharsInStringUpTo);
515 static Date Parse (const String& rep, const locale& l, const String& formatPattern);
516 static Date Parse (const String& rep, const locale& l, const String& formatPattern, size_t* consumedCharsInStringUpTo);
517 static Date Parse (const String& rep, const Traversal::Iterable<String>& formatPatterns);
519 static Date Parse (const String& rep, const String& formatPattern);
520 static Date Parse (const String& rep, const String& formatPattern, size_t* consumedCharsInStringUpTo);
521
522 public:
523 /**
524 * \brief like Parse(), but returns nullopt on parse error, not throwing exception.
525 * if locale is missing, and formatPattern is not locale independent, the current locale (locale{}) is used.
526 * if rep is empty, this will return nullopt
527 */
528 static optional<Date> ParseQuietly (const String& rep, const String& formatPattern);
529 static optional<Date> ParseQuietly (const String& rep, const locale& l, const String& formatPattern);
530
531 private:
532 static optional<Date> ParseQuietly_ (const wstring& rep, const time_get<wchar_t>& tmget, const String& formatPattern,
534
535 private:
536 static Date Parse_ (const String& rep, const locale& l, const Traversal::Iterable<String>& formatPatterns, size_t* consumedCharsInStringUpTo);
537
538 public:
539 /**
540 * Date::kMin is the first date this Date class supports representing.
541 */
542 static const Date kMin; // defined constexpr
543
544 public:
545 /**
546 * Date::kMax is the last date this Date class supports representing.
547 */
548 static const Date kMax; // defined constexpr
549
550 public:
551 /**
552 */
553 nonvirtual constexpr year GetYear () const;
554
555 public:
556 /**
557 */
558 nonvirtual constexpr month GetMonth () const;
559
560 public:
561 /**
562 */
563 nonvirtual constexpr day GetDayOfMonth () const;
564
565 public:
566 /**
567 */
568 nonvirtual weekday GetDayOfWeek () const;
569
570 public:
571 /**
572 * \brief return the Julian Day Number (JDN) - corresponding to this date object (https://en.wikipedia.org/wiki/Julian_day) - days since Monday, January 1, 4713 BC
573 */
574 nonvirtual constexpr JulianDayNumber GetJulianRep () const;
575
576 public:
577 /**
578 * \brief DisplayFormat is a representation which a date can be transformed in and out of
579 *
580 * eCurrentLocale_WithZerosStripped
581 * eCurrentLocale_WithZerosStripped is locale{}, but with many cases of leading zero's,
582 * stripped, so for example, 03/05/2013 becomes 3/5/2013. This only affects the day/month, and not the
583 * year.
584 *
585 * \note Common::DefaultNames<> supported
586 */
588 eCurrentLocale_WithZerosStripped,
589
590 eDEFAULT = eCurrentLocale_WithZerosStripped,
591
592 Stroika_Define_Enum_Bounds (eCurrentLocale_WithZerosStripped, eCurrentLocale_WithZerosStripped)
593 };
594
595 public:
596 static constexpr NonStandardPrintFormat eCurrentLocale_WithZerosStripped = NonStandardPrintFormat::eCurrentLocale_WithZerosStripped;
597
598 public:
599 /**
600 * For formatPattern, see http://en.cppreference.com/w/cpp/locale/time_put/put
601 * If only formatPattern specified, and no locale, use default (global) locale.
602 */
603 nonvirtual String Format (NonStandardPrintFormat pf = NonStandardPrintFormat::eDEFAULT) const;
604 nonvirtual String Format (const locale& l) const;
605 nonvirtual String Format (const locale& l, const String& formatPattern) const;
606 nonvirtual String Format (const String& formatPattern) const;
607
608 public:
609 /**
610 * @see Characters::ToString ()
611 */
612 nonvirtual String ToString () const;
613
614 public:
615 /**
616 * Returns a new Date object based on this Date, with 'dayCount' days added.
617 *
618 * \par Example Usage
619 * \code
620 * Date d = 1906y/May/12d;
621 * d = d.Add (1); // OR d = d + 1;
622 * Assert (d == 1906y/May/13d);
623 * \endcode
624 *
625 * \note - a duration is much more precise than a day, so that overload rounds.
626 */
627 nonvirtual [[nodiscard]] Date Add (int d) const;
628 nonvirtual [[nodiscard]] Date Add (days d) const;
629 nonvirtual [[nodiscard]] Date Add (const Duration& d) const;
630
631 public:
632 /**
633 * returns number of days between a start day and end day: Never less than zero.
634 * No argument version computes days between *this and 'now'.
635 */
636 static days Since (Date dStart, Date dEnd);
637 nonvirtual days Since () const;
638
639 public:
640 /**
641 * \brief Returns the difference (*this - rhs) between the two Date records;
642 *
643 * \note Before Stroika v3.0d1, this returned SignedJulianDayNumber.
644 */
645 nonvirtual days Difference (const Date& rhs) const;
646
647 public:
648 /**
649 * \brief Syntactic sure for Add (n);
650 *
651 * \par Example Usage
652 * \code
653 * Date d = 1906y/May/12d;
654 * d = d + 1;
655 * Assert (d == 1906y/May/13d);
656 * \endcode
657 */
658 nonvirtual Date operator+ (int daysOffset) const;
659 nonvirtual Date operator+ (days daysOffset) const;
660 nonvirtual Date operator+ (const Duration& d) const;
661
662 public:
663 /**
664 * days operator- (const Date& rhs): Syntactic sugar on Difference()
665 * Date operator- (days or int daysOffset) Syntactic sugar on Add(-arg)
666 *
667 * \note subtracting by duration 'd' rounds to days...
668 */
669 nonvirtual days operator- (const Date& rhs) const;
670 nonvirtual Date operator- (int daysOffset) const;
671 nonvirtual Date operator- (days daysOffset) const;
672 nonvirtual Date operator- (const Duration& d) const;
673
674 public:
675 /**
676 */
677 constexpr strong_ordering operator<=> (const Date& rhs) const = default;
678
679 public:
680 /**
681 * Defined for
682 * struct tm
683 * year_month_day
684 * any std::time_point
685 *
686 * Generally constexpr where possible.
687 *
688 * @todo understand why on MSVC I need ::tm and tm in the IAnyOf<>
689 */
690 template <typename T>
691 constexpr T As () const
692 requires (Common::IAnyOf<::tm, tm, year_month_day> or Common::ITimePoint<T>);
693
694 public:
695 using JulianRepType [[deprecated ("Since Stroika v3.0d1 - use JulianDayNumber")]] = JulianDayNumber;
696 using SignedJulianRepType [[deprecated ("Since Stroika v3.0d1 - use SignedJulianDayNumber")]] = SignedJulianDayNumber;
697 [[deprecated ("Since Stroika v3.0d1 - use.Add () - now Date immutable")]] Date& operator++ ()
698 {
699 *this = Add (1);
700 return *this;
701 }
702 [[deprecated ("Since Stroika v3.0d1 - use.Add () - now Date immutable")]] Date operator++ (int)
703 {
704 return *this + 1;
705 }
706 [[deprecated ("Since Stroika v3.0d1, use As<year_month_day> ()")]] void mdy (month* m, day* d, year* y) const
707 {
708 RequireNotNull (m);
709 RequireNotNull (d);
710 RequireNotNull (y);
711 *m = fRep_.month ();
712 *d = fRep_.day ();
713 *y = fRep_.year ();
714 }
715 [[deprecated ("Since Stroika v3.0d1 - use Add(days)")]] Date AddDays (SignedJulianDayNumber dayCount) const
716 {
717 return Add (chrono::days{dayCount});
718 }
719 [[deprecated ("Since Stroika 3.0d1 - use Since")]] JulianDayNumber DaysSince () const
720 {
721 return static_cast<JulianDayNumber> (Since ().count ());
722 }
723
724 private:
725 static optional<Date> LocaleFreeParseQuietly_kMonthDayYearFormat_ (const wstring& rep, size_t* consumedCharsInStringUpTo);
726
727 private:
728 static constexpr int kTM_Year_RelativeToYear_{1900}; // see https://man7.org/linux/man-pages/man3/ctime.3.html
729
730 private:
731 static Date AsDate_ (const ::tm& when);
732
733 private:
734 year_month_day fRep_;
735 };
736 static_assert (sizeof (Date) == sizeof (year_month_day)); // generally 4 bytes
737 static_assert (totally_ordered<Date>);
738
739 class Date::FormatException : public Execution::RuntimeErrorException<> {
740 public:
741 FormatException ();
742
743 public:
744 /**
745 */
746 static const FormatException kThe;
747 };
748 inline const Date::FormatException Date::FormatException::kThe;
749 inline const Traversal::Iterable<String> Date::kDefaultParseFormats{
750 kLocaleStandardFormat, // x (kLocaleStandardFormat) parses the locale's standard date representation
751 kLocaleStandardAlternateFormat, // Ex (kLocaleStandardAlternateFormat) parses the locale's alternative date representation, e.g. expecting 平成23年 (year Heisei 23) instead of 2011年 (year 2011) in ja_JP locale
752 kMonthDayYearFormat, // Before Stroika 2.1b10, this was L"%D" (=="%m/%d/%y) which is the 2-digit year
753 kISO8601Format,
754 };
755
756 Date::SignedJulianDayNumber DayDifference (const Date& lhs, const Date& rhs);
757 int YearDifference (const Date& lhs, const Date& rhs);
758 float YearDifferenceF (const Date& lhs, const Date& rhs);
759
760 String GetFormattedAge (const optional<Date>& birthDate, const optional<Date>& deathDate = {}); // returns ? if not a good src date
761 String GetFormattedAgeWithUnit (const optional<Date>& birthDate, const optional<Date>& deathDate = {}, bool abbrevUnit = true); // returns ? if not a good src date
762
763}
764
766
767 template <>
768 struct DefaultOpenness<Time::Date> : ExplicitOpenness<Openness::eClosed, Openness::eClosed> {};
769 template <>
770 struct DefaultDifferenceTypes<Time::Date> : ExplicitDifferenceTypes<chrono::days> {};
771 template <>
772 struct Default<Time::Date> : ExplicitOpennessAndDifferenceType<Time::Date> {
773 static const Time::Date kLowerBound;
774 static const Time::Date kUpperBound;
775
776 static Time::Date GetNext (Time::Date n);
777 static Time::Date GetPrevious (Time::Date n);
778
779 static size_t DifferenceToSizeT (chrono::days s)
780 {
781 return size_t (s.count ());
782 }
783 };
784
785}
786
787/*
788 ********************************************************************************
789 ***************************** Implementation Details ***************************
790 ********************************************************************************
791 */
792#include "Date.inl"
793
794#endif /*_Stroika_Foundation_Time_Date_h_*/
#define RequireNotNull(p)
Definition Assertions.h:348
#define Stroika_Define_Enum_Bounds(FIRST_ITEM, LAST_ITEM)
String is like std::u32string, except it is much easier to use, often much more space efficient,...
Definition String.h:201
nonvirtual days Difference(const Date &rhs) const
Returns the difference (*this - rhs) between the two Date records;.
Definition Date.inl:431
constexpr T As() const
Definition Date.inl:270
nonvirtual String Format(NonStandardPrintFormat pf=NonStandardPrintFormat::eDEFAULT) const
Definition Date.cpp:119
NonStandardPrintFormat
DisplayFormat is a representation which a date can be transformed in and out of.
Definition Date.h:587
nonvirtual days operator-(const Date &rhs) const
Definition Date.inl:435
make_signed_t< JulianDayNumber > SignedJulianDayNumber
Definition Date.h:338
nonvirtual Date operator+(int daysOffset) const
Syntactic sure for Add (n);.
Definition Date.inl:412
static constexpr string_view kISO8601Format
Y-M-D format - locale independent, and ISO-8601 date format standard.
Definition Date.h:465
static constexpr ReferencePoint kGregorianCalendarEpoch
Definition Date.h:374
static optional< Date > ParseQuietly(const String &rep, const String &formatPattern)
like Parse(), but returns nullopt on parse error, not throwing exception. if locale is missing,...
Definition Date.inl:393
static Date Now() noexcept
Definition Date.cpp:42
static const JulianDayNumber kMinJulianRep
Definition Date.h:411
static constexpr ReferencePoint kUNIXEpoch
Definition Date.h:364
static const Date kMax
Definition Date.h:548
static const JulianDayNumber kMaxJulianRep
Definition Date.h:417
static constexpr ReferencePoint kMinDateReference
Definition Date.h:381
static Date Parse(const String &rep, const locale &l=locale{})
Definition Date.inl:316
nonvirtual String ToString() const
Definition Date.inl:404
static constexpr JulianDayNumber ToJulianRep(month m, day d, year y, DataExchange::ValidationStrategy validationStrategy=DataExchange::ValidationStrategy::eAssertion)
Definition Date.inl:140
static constexpr ReferencePoint kStartOfJulianCalendar
Definition Date.h:358
static constexpr year_month_day FromJulianRep(JulianDayNumber j, DataExchange::ValidationStrategy validationStrategy=DataExchange::ValidationStrategy::eAssertion)
Definition Date.inl:195
static constexpr string_view kLocaleStandardAlternateFormat
Definition Date.h:477
static days Since(Date dStart, Date dEnd)
Definition Date.inl:424
static constexpr string_view kMonthDayYearFormat
classic (american) month-day-year format, but unlike D, this uses Y, so the 4-digit form of year
Definition Date.h:487
static const Date kMin
Definition Date.h:542
nonvirtual constexpr JulianDayNumber GetJulianRep() const
return the Julian Day Number (JDN) - corresponding to this date object (https://en....
Definition Date.inl:298
constexpr Date(Date &&src) noexcept=default
static constexpr string_view kLocaleStandardFormat
Definition Date.h:471
static const Traversal::Iterable< String > kDefaultParseFormats
Definition Date.h:494
nonvirtual Date Add(int d) const
Definition Date.inl:408
Duration is a chrono::duration<double> (=.
Definition Duration.h:96
Iterable<T> is a base class for containers which easily produce an Iterator<T> to traverse them.
Definition Iterable.h:238
Simple wrapper on std::chrono::day, with some helpful validation properties (assures constructed 'ok'...
Definition Date.h:161
Simple wrapper on std::chrono::weekday, with some helpful validation properties (assures constructed ...
Definition Date.h:103
Simple wrapper on std::chrono::month, with some helpful validation properties (assures constructed 'o...
Definition Date.h:129
this defines undefined but important properties of the x (read/write date) format string in stdc++ ti...
Definition Date.h:250
Simple wrapper on std::chrono::year, with some helpful validation properties (assures constructed 'ok...
Definition Date.h:213
static constexpr year eFirstYear
4713 BC (no year zero)
Definition Date.h:225
static constexpr year eLastYear
Definition Date.h:235