4#include "Stroika/Foundation/StroikaPreComp.h"
13#include "Stroika/Foundation/Containers/Sequence.h"
16#include "Stroika/Foundation/Execution/Throw.h"
17#include "Stroika/Foundation/Linguistics/Words.h"
19#if qStroika_Foundation_Common_Platform_Windows
20#include "Stroika/Foundation/Characters/Platform/Windows/SmartBSTR.h"
21#include "Stroika/Foundation/Execution/Platform/Windows/HRESULTErrorException.h"
29using namespace Stroika::Foundation::Memory;
30using namespace Stroika::Foundation::Time;
39#if qStroika_Foundation_Common_Platform_Windows
41 TimeOfDay mkTimeOfDay_ (const ::SYSTEMTIME& sysTime)
43 WORD hour = max (sysTime.wHour,
static_cast<WORD
> (0));
44 hour = min (hour,
static_cast<WORD
> (23));
45 WORD minute = max (sysTime.wMinute,
static_cast<WORD
> (0));
46 minute = min (minute,
static_cast<WORD
> (59));
47 WORD secs = max (sysTime.wSecond,
static_cast<WORD
> (0));
48 secs = min (secs,
static_cast<WORD
> (59));
55 constexpr bool kLocaleIndependent_iso8601_PerformanceOptimization_ =
true;
56 optional<TimeOfDay> LocaleIndependent_Parse_iso8601_ (
const String& rep)
62 if (::swscanf (rep.As<wstring> ().c_str (), L"%d:%d:%d", &hour, &minute, &secs) >= 2) {
63 hour = std::max (hour, 0);
64 hour = std::min (hour, 23);
65 minute = std::max (minute, 0);
66 minute = std::min (minute, 59);
67 secs = std::max (secs, 0);
68 secs = std::min (secs, 59);
69 return TimeOfDay{
static_cast<unsigned> (hour),
static_cast<unsigned> (minute),
static_cast<unsigned> (secs)};
71 DISABLE_COMPILER_MSC_WARNING_END (4996)
74 String LocaleIndependent_Format_iso8601_ (uint32_t timeInSeconds)
76 uint32_t hour = timeInSeconds / (60 * 60);
77 uint32_t minutes = (timeInSeconds - hour * 60 * 60) / 60;
78 uint32_t secs = timeInSeconds - hour * 60 * 60 - minutes * 60;
79 Assert (hour >= 0 and hour < 24);
80 Assert (minutes >= 0 and minutes < 60);
81 Assert (secs >= 0 and secs < 60);
82 return "{:02}:{:02}:{:02}"_f(hour, minutes, secs);
91TimeOfDay::FormatException::FormatException ()
101#if qStroika_Foundation_Common_Platform_Windows
105 using namespace Execution::Platform::Windows;
117 if (newRep.
length () == 4 and newRep[0].IsDigit () and newRep[1].IsDigit () and newRep[2].IsDigit () and newRep[3].IsDigit ()) {
118 newRep = newRep.
substr (0, 2) +
":"sv + newRep.
substr (2, 2);
128 ::SYSTEMTIME sysTime{};
129 Verify (::VariantTimeToSystemTime (d, &sysTime));
130 return mkTimeOfDay_ (sysTime);
140 hour, minute, seconds
148 if (hour >= 24 or minute >= 60 or seconds > 60) {
149 if (validationStrategy == DataExchange::ValidationStrategy::eThrow) {
156#if qStroika_Foundation_Debug_AssertionsChecked
157 *
this =
TimeOfDay{hour, minute, seconds};
163 switch (validationStrategy) {
164 case DataExchange::ValidationStrategy::eAssertion:
165 Require (t < kMaxSecondsPerDay);
167 case DataExchange::ValidationStrategy::eThrow:
168 if (not(t < kMaxSecondsPerDay)) {
173 Assert (fTime_ < kMaxSecondsPerDay);
178#if USE_NOISY_TRACE_IN_THIS_MODULE_
186#if USE_NOISY_TRACE_IN_THIS_MODULE_
187 DbgTrace (
"returning {}"_f, result);
194#if USE_NOISY_TRACE_IN_THIS_MODULE_
201 wstring wRep = rep.
As<wstring> ();
202 const time_get<wchar_t>& tmget = use_facet<time_get<wchar_t>> (l);
203 for (
const auto& formatPattern : formatPatterns) {
204 if (
auto o = ParseQuietly_ (wRep, tmget, formatPattern)) {
205#if USE_NOISY_TRACE_IN_THIS_MODULE_
216#if USE_NOISY_TRACE_IN_THIS_MODULE_
222 if (
auto o = ParseQuietly_ (rep.
As<wstring> (), formatPattern)) {
223#if USE_NOISY_TRACE_IN_THIS_MODULE_
233#if USE_NOISY_TRACE_IN_THIS_MODULE_
240 if (
auto o = ParseQuietly_ (rep.
As<wstring> (), use_facet<time_get<wchar_t>> (l), formatPattern)) {
241#if USE_NOISY_TRACE_IN_THIS_MODULE_
254 return ParseQuietly_ (rep.
As<wstring> (), formatPattern);
262 return ParseQuietly_ (rep.
As<wstring> (), use_facet<time_get<wchar_t>> (l), formatPattern);
265optional<TimeOfDay> TimeOfDay::ParseQuietly_ (
const wstring& rep,
const String& formatPattern)
267 if (kLocaleIndependent_iso8601_PerformanceOptimization_ and formatPattern ==
kISO8601Format) {
268 return LocaleIndependent_Parse_iso8601_ (rep);
270 return ParseQuietly_ (rep, use_facet<time_get<wchar_t>> (locale{}), formatPattern);
273optional<TimeOfDay> TimeOfDay::ParseQuietly_ (
const wstring& rep,
const time_get<wchar_t>& tmget,
const String& formatPattern)
275 ios::iostate errState = ios::goodbit;
277 wistringstream iss{rep};
278 istreambuf_iterator<wchar_t> itbegin{iss};
279 istreambuf_iterator<wchar_t> itend;
280 wstring wsFormatPattern = formatPattern.
As<wstring> ();
281 (void)tmget.get (itbegin, itend, iss, errState, &when, wsFormatPattern.c_str (), wsFormatPattern.c_str () + wsFormatPattern.length ());
282 if ((errState & ios::badbit) or (errState & ios::failbit)) [[unlikely]] {
283#if qCompilerAndStdLib_locale_get_time_needsStrptime_sometimes_Buggy
289 if ((errState & ios::badbit) or (errState & ios::failbit)) [[unlikely]] {
293 Ensure (0 <= when.tm_hour and when.tm_hour <= 23);
294 Ensure (0 <= when.tm_min and when.tm_min <= 59);
295 Ensure (0 <= when.tm_sec and when.tm_sec <= 59);
296 auto result =
TimeOfDay{
static_cast<unsigned> (when.tm_hour),
static_cast<unsigned> (when.tm_min),
static_cast<unsigned> (when.tm_sec)};
297#if USE_NOISY_TRACE_IN_THIS_MODULE_
298 DbgTrace (
"returning {}"_f, result);
306 case eCurrentLocale_WithZerosStripped: {
312 while ((i = tmp.
RFind (
":00"sv))) {
314 bool trailing =
false;
315 if (*i + 3 == tmp.
size ()) {
318 else if (*i + 3 < tmp.
size () and tmp[*i + 3] ==
' ') {
329 if (not tmp.empty () and tmp[0] ==
'0') {
348 if (kLocaleIndependent_iso8601_PerformanceOptimization_ and formatPattern ==
kISO8601Format) {
349 return LocaleIndependent_Format_iso8601_ (fTime_);
351 return Format (locale{}, formatPattern);
362 const time_put<wchar_t>& tmput = use_facet<time_put<wchar_t>> (l);
363 wstring wsFormatPattern = formatPattern.
As<wstring> ();
365 tmput.put (oss, oss,
' ', &when, wsFormatPattern.c_str (), wsFormatPattern.c_str () + wsFormatPattern.length ());
369void TimeOfDay::ClearSecondsField ()
372 int hour = fTime_ / (60 * 60);
373 int minutes = (fTime_ - hour * 60 * 60) / 60;
374 int secs = fTime_ - hour * 60 * 60 - minutes * 60;
375 Assert (hour >= 0 and hour < 24);
376 Assert (minutes >= 0 and minutes < 60);
377 Assert (secs >= 0 and secs < 60);
#define qStroika_Foundation_Debug_AssertionsChecked
The qStroika_Foundation_Debug_AssertionsChecked flag determines if assertions are checked and validat...
#define AssertNotReached()
#define Stroika_Foundation_Debug_OptionalizeTraceArgs(...)
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 string AsNarrowSDKString() const
static String FromNarrowSDKString(const char *from)
nonvirtual size_t size() const noexcept
nonvirtual String SubString(SZ from) const
nonvirtual optional< size_t > RFind(Character c) const noexcept
nonvirtual String substr(size_t from, size_t count=npos) const
A generalization of a vector: a container whose elements are keyed by the natural numbers.
Logically halfway between std::array and std::vector; Smart 'direct memory array' - which when needed...
static constexpr uint32_t kMaxSecondsPerDay
static constexpr string_view kISO8601Format
nonvirtual constexpr uint8_t GetMinutes() const
static constexpr string_view kLocaleStandardFormat
static const Traversal::Iterable< String > kDefaultParseFormats
nonvirtual String Format(NonStandardPrintFormat pf=NonStandardPrintFormat::eDEFAULT) const
nonvirtual constexpr uint8_t GetHours() const
nonvirtual constexpr uint8_t GetSeconds() const
static TimeOfDay Parse(const String &rep, const locale &l=locale{})
static optional< TimeOfDay > ParseQuietly(const String &rep, const String &formatPattern)
like Parse(), but returns nullopt on parse error, not throwing exception. if locale is missing,...
constexpr TimeOfDay(TimeOfDay &&src) noexcept=default
NonStandardPrintFormat
NonStandardPrintFormat is a representation which a TimeOfDay can be transformed into.
Iterable<T> is a base class for containers which easily produce an Iterator<T> to traverse them.
DISABLE_COMPILER_MSC_WARNING_START(4996)
void Throw(T &&e2Throw)
identical to builtin C++ 'throw' except that it does helpful, type dependent DbgTrace() messages firs...