4#include "Stroika/Foundation/StroikaPreComp.h"
14#include "Stroika/Foundation/Execution/Throw.h"
15#include "Stroika/Foundation/Linguistics/MessageUtilities.h"
22using namespace Stroika::Foundation::Memory;
23using namespace Stroika::Foundation::Time;
32Date::FormatException::FormatException ()
44 return DateTime::Now ().GetDate ();
52 wstring wRep = rep.
As<wstring> ();
53 const time_get<wchar_t>& tmget = use_facet<time_get<wchar_t>> (l);
54 for (
const auto& formatPattern : formatPatterns) {
55 if (
auto r = ParseQuietly_ (wRep, tmget, formatPattern, consumedCharsInStringUpTo)) {
62optional<Date> Date::LocaleFreeParseQuietly_kMonthDayYearFormat_ (
const wstring& rep,
size_t* consumedCharsInStringUpTo)
68 DISABLE_COMPILER_MSC_WARNING_START (4996)
70 int nItems = ::swscanf (rep.c_str (), L
"%d/%d/%d%n", &m, &d, &year, &pos);
71 DISABLE_COMPILER_MSC_WARNING_END (4996)
73 if (consumedCharsInStringUpTo !=
nullptr) {
74 Assert (pos + 2 < rep.length ());
75 *consumedCharsInStringUpTo = pos + 2;
77 if ((1 <= m and m <= 12) and (1 <= d and d <= 31) and (year > 0)) {
80 return Date{
Year{year}, month{
static_cast<unsigned int> (m)}, day{
static_cast<unsigned int> (d)},
91optional<Date> Date::ParseQuietly_ (
const wstring& rep,
const time_get<wchar_t>& tmget,
const String& formatPattern,
size_t* consumedCharsInStringUpTo)
93 Require (not rep.empty ());
94 if constexpr (qCompilerAndStdLib_locale_time_get_PCTM_RequiresLeadingZero_Buggy) {
96 return LocaleFreeParseQuietly_kMonthDayYearFormat_ (rep, consumedCharsInStringUpTo);
100 auto [formatPattern_CStr, formatPattern_SV] = formatPattern.
c_str (&formatPattern_BackingStore);
101 ios::iostate errState = ios::goodbit;
103 wistringstream iss{rep};
104 istreambuf_iterator<wchar_t> itbegin{iss};
105 istreambuf_iterator<wchar_t> itend;
106 istreambuf_iterator<wchar_t> i =
107 tmget.get (itbegin, itend, iss, errState, &when, formatPattern_CStr, formatPattern_CStr + formatPattern_SV.size ());
108 if ((errState & ios::badbit) or (errState & ios::failbit)) [[unlikely]] {
112 if (consumedCharsInStringUpTo !=
nullptr) {
113 *consumedCharsInStringUpTo =
static_cast<size_t> (distance (itbegin, i));
115 return AsDate_ (when);
122 case eCurrentLocale_WithZerosStripped: {
132 static const String kZero_ =
"0"sv;
133 optional<size_t> i = 0;
134 while ((i = tmp.
Find (kZero_, *i))) {
136 Assert (tmp[*i] ==
'0');
137 bool isLeadingZero =
false;
138 if (*i + 1 < tmp.
length () and tmp[*i + 1].IsDigit ()) {
139 if (*i == 0 or not tmp[*i - 1].IsDigit ()) {
143 if (*i + 2 < tmp.
length ()) {
144 isLeadingZero =
true;
171 return "{:04}-{:02}-{:02}"_f((
int)(this->GetYear ()), (
unsigned int)(this->GetMonth ()), (
unsigned int)(this->GetDayOfMonth ()));
174 return Format (locale{}, formatPattern);
181 ::tm when = As<::tm> ();
183 auto [formatPatternCStr, formatPatternSV] = formatPattern.
c_str (&formatBuf);
184 const time_put<wchar_t>& tmput = use_facet<time_put<wchar_t>> (l);
187#if qCompilerAndStdLib_FormatRangeRestriction_Buggy
188 WeakAssert (when.tm_year == clamp<int> (when.tm_year, -1900, 8099));
189 when.tm_year = clamp<int> (when.tm_year, -1900, 8099);
192 tmput.put (oss, oss,
' ', &when, formatPatternCStr, formatPatternCStr + formatPatternSV.length ());
196Date Date::AsDate_ (const ::tm& when)
198 return Date{
Year{when.tm_year + kTM_Year_RelativeToYear_},
212 return Add (chrono::round<days> (d));
220days Date::Since ()
const
222 return Since (DateTime::GetToday (), this->As<year_month_day> ());
225weekday Date::GetDayOfWeek ()
const
235 unsigned int y =
static_cast<unsigned int> (
static_cast<int> (GetYear ()));
236 auto R = [] (
unsigned int i,
unsigned int r) {
return i % r; };
237 unsigned int weekdayOfJan1 = R (1 + 5 * R (y - 1, 4) + 4 * R (y - 1, 100) + 6 * R (y - 1, 400), 7);
240 unsigned int month0 =
static_cast<unsigned int> (GetMonth ()) -
static_cast<unsigned int> (January);
242 static constexpr unsigned int kDayOfWeekOffsetPerMonth_[12] = {
245 3, 2, 3, 2, 3, 3, 2, 3, 2, 3,
247 unsigned int targetDayOfWeek = weekdayOfJan1;
248 for (
unsigned int i = 0; i < month0; ++i) {
249 targetDayOfWeek += kDayOfWeekOffsetPerMonth_[i];
251 if (month0 > 1 and GetYear ().is_leap ()) {
252 targetDayOfWeek += 1;
256 targetDayOfWeek += (GetDayOfMonth () - day{1}).count ();
258 return DayOfWeek{R (targetDayOfWeek, 7) + Sunday.c_encoding ()};
275 unsigned int diff = r - l;
276 Assert (INT_MIN <= -INT_MAX);
277 if (diff >=
static_cast<unsigned int> (INT_MAX)) {
281 return -
static_cast<int> (diff);
285 unsigned int diff = l - r;
286 if (diff >=
static_cast<unsigned int> (INT_MAX)) {
290 return static_cast<int> (diff);
302int Time::YearDifference (
const Date& lhs,
const Date& rhs)
304 int diff =
static_cast<int> (lhs.GetYear ()) -
static_cast<int> (rhs.GetYear ());
305 if (lhs.GetMonth () < rhs.GetMonth () or (lhs.GetMonth () == rhs.GetMonth () and lhs.GetDayOfMonth () < rhs.GetDayOfMonth ())) {
311float Time::YearDifferenceF (
const Date& lhs,
const Date& rhs)
313 return DayDifference (lhs, rhs) / 365.25f;
321String Time::GetFormattedAge (
const optional<Date>& birthDate,
const optional<Date>& deathDate)
323 if (birthDate.has_value ()) {
324 int yearDiff = deathDate.has_value () ? YearDifference (*deathDate, *birthDate) : YearDifference (DateTime::GetToday (), *birthDate);
325 return Format (
"{}"_f, yearDiff);
337String Time::GetFormattedAgeWithUnit (
const optional<Date>& birthDate,
const optional<Date>& deathDate,
bool abbrevUnit)
339 if (birthDate.has_value ()) {
340 int yearDiff = deathDate.has_value () ? YearDifference (*deathDate, *birthDate) : YearDifference (DateTime::GetToday (), *birthDate);
341 if (yearDiff >= 0 and yearDiff < 2) {
342 float yearDiffF = deathDate.has_value () ? YearDifferenceF (*deathDate, *birthDate) : YearDifferenceF (DateTime::GetToday (), *birthDate);
343 int months = int (yearDiffF * 12.0f + 0.4999f);
344 String unitBase = abbrevUnit ?
"mo"_k :
"month"_k;
345 return Format (
"{} {}"_f, months, Linguistics::MessageUtilities::Manager::sThe.PluralizeNoun (unitBase, months));
348 String unitBase = abbrevUnit ?
"yr"_k :
"year"_k;
349 return Format (
"{} {}"_f, yearDiff, Linguistics::MessageUtilities::Manager::sThe.PluralizeNoun (unitBase, yearDiff));
#define WeakAssert(c)
A WeakAssert() is for things that aren't guaranteed to be true, but are overwhelmingly likely to be t...
#define AssertNotReached()
String is like std::u32string, except it is much easier to use, often much more space efficient,...
nonvirtual size_t length() const noexcept
nonvirtual tuple< const wchar_t *, wstring_view > c_str(Memory::StackBuffer< wchar_t > *possibleBackingStore) const
nonvirtual optional< size_t > Find(Character c, CompareOptions co=eWithCase) const
nonvirtual String substr(size_t from, size_t count=npos) const
Logically halfway between std::array and std::vector; Smart 'direct memory array' - which when needed...
nonvirtual String Format(NonStandardPrintFormat pf=NonStandardPrintFormat::eDEFAULT) const
NonStandardPrintFormat
DisplayFormat is a representation which a date can be transformed in and out of.
nonvirtual days operator-(const Date &rhs) const
make_signed_t< JulianDayNumber > SignedJulianDayNumber
static constexpr string_view kISO8601Format
Y-M-D format - locale independent, and ISO-8601 date format standard.
static Date Now() noexcept
static days Since(Date dStart, Date dEnd)
static constexpr string_view kMonthDayYearFormat
classic (american) month-day-year format, but unlike D, this uses Y, so the 4-digit form of year
nonvirtual constexpr JulianDayNumber GetJulianRep() const
return the Julian Day Number (JDN) - corresponding to this date object (https://en....
static constexpr string_view kLocaleStandardFormat
nonvirtual Date Add(int d) const
Duration is a chrono::duration<double> (=.
Iterable<T> is a base class for containers which easily produce an Iterator<T> to traverse them.
void Throw(T &&e2Throw)
identical to builtin C++ 'throw' except that it does helpful, type dependent DbgTrace() messages firs...
Simple wrapper on std::chrono::day, with some helpful validation properties (assures constructed 'ok'...
Simple wrapper on std::chrono::weekday, with some helpful validation properties (assures constructed ...
Simple wrapper on std::chrono::month, with some helpful validation properties (assures constructed 'o...
Simple wrapper on std::chrono::year, with some helpful validation properties (assures constructed 'ok...