[PATCH v3 1/2] libstdc++: Type-erase chrono-data for formatting [PR110739]
Tomasz Kaminski
tkaminsk@redhat.com
Wed Oct 8 13:11:29 GMT 2025
On Wed, Oct 8, 2025 at 8:52 AM Tomasz Kaminski <tkaminsk@redhat.com> wrote:
>
>
> On Mon, Oct 6, 2025 at 6:21 PM Patrick Palka <ppalka@redhat.com> wrote:
>
>> On Thu, 26 Jun 2025, Tomasz Kamiński wrote:
>>
>> > This patch reworks the formatting for the chrono types, such that they
>> are all
>> > formatted in terms of _ChronoData class, that includes all required
>> fields.
>> > Populating each required field is performed in formatter for specific
>> type,
>> > based on the chrono-spec used.
>> >
>> > To facilitate above, the _ChronoSpec now includes additional _M_needed
>> field,
>> > that represnts the chrono data that is referenced by format spec (this
>> value
>> > is also configured for __defSpec). This value differs from the value of
>> > __parts passed to _M_parse, which does include all fields that can be
>> computed
>> > from input (e.g. weekday_indexed can be computed for year_month_day).
>> Later
>> > it is used to fill _ChronoData, in particular _M_fill_* family of
>> functions,
>> > to determine if given field needs to be set, and thus its value needs
>> to be
>> > computed.
>> >
>> > In consequence _ChronoParts enum was extended with additional values,
>> that
>> > allows more fine grained identification:
>> > * _TimeOfDay is separated into _HoursMinutesSeconds and _Subseconds,
>> > * _TimeZone is separated into _ZoneAbbrev and _ZoneOffset,
>> > * _LocalDays, _WeekdayIndex are defined and in included in _Date,
>> > * _Duration is removed, and instead _EpochUnits and _UnitSuffix are
>> > introduced.
>> > Furthermore, to avoid name conflicts _ChonoParts is now defined as enum
>> class,
>> > with additional operators that simplify uses.
>> >
>> > In addition to fields that can be printed using chrono-spec,
>> _ChronoData stores:
>> > * Total days in wall time (_M_ldays), day of year (_M_day_of_year) -
>> used by
>> > struct tm construction, and for ISO calendar computation.
>> > * Total seconds in wall time (_M_lseconds) - this value may be
>> different from
>> > sum of days, hours, minutes, seconds (e.g. see utc_time below).
>> Included
>> > to allow future extension, like printing total minutes.
>> > * Total seconds since epoch - due offset different from above. Again
>> to be
>> > used with future extension (e.g. %s as proposed in P2945R1).
>> > * Subseconds - count of attoseconds (10^(-18)), in addition to
>> printing can
>> > be used to compute fractional hours, minutes.
>> > The both total seconds fields we use single _TotalSeconds enumerator in
>> > _ChronoParts, that when present in combination with _EpochUnits or
>> _LocalDays
>> > indicates that _M_eseconds (_EpochSeconds) or _M_lseconds
>> (_LocalSeconds) are
>> > provided/required.
>> >
>> > To handle type formatting of time since epoch ('%Q'|_EpochUnits), we
>> use the
>> > format_args mechanism, where the result of +d.count() (see LWG4118) is
>> erased
>> > into make_format_args to local __arg_store, that is later referenced by
>> > _M_ereps (_M_ereps.get(0)).
>> >
>> > To handle precision values, and in prepartion to allow user to
>> configure ones,
>> > we store the precision as third element of _M_ereps (_M_ereps.get(2)),
>> this
>> > allows duration with precision to be printed using "{0:{2}}". For
>> subseconds
>> > the precision is handled differently depending on the representation:
>> > * for integral reps, _M_subseconds value is used to determine
>> fractional value,
>> > precision is trimmed to 18 digits;
>> > * for floating-points, _M_ereps stores duration<Rep> initialized with
>> only
>> > fractional seconds, that is later formatted with precision.
>> > Always using _M_subseconds fields for integral duration, means that we
>> do not
>> > use formattter for user-defined durations that are considered to be
>> integral
>> > (see empty_spec.cc file change). To avoid potentially expensive
>> computation
>> > of _M_subseconds, we make sure that _ChronoParts::_Subseconds is set
>> only if
>> > _Subseconds are needed. In particular we remove this flag for localized
>> ouput
>> > in _M_parse.
>> >
>> > Construction of the _M_ereps as described above is handled by
>> __formatter_duration,
>> > that is then used to format duration, hh_mm_ss and time_points
>> specializations.
>> > This class also handles _UnitSuffix, the _M_units_suffix field is
>> populated
>> > either with predefined suffix (chrono::__detail::__units_suffix) or one
>> produced
>> > locally.
>> >
>> > Finally, formatters for types listed below contains type specific logic:
>> > * hh_mm_ss - we do not compute total duration and seconds, unless
>> explicitly
>> > requested, as such computation may overflow;
>> > * utc_time - for time during leap second insertion, the _M_seconds
>> field is
>> > increased to 60;
>> > * __local_time_fmt - exception is thrown if zone offset (_ZoneOffset)
>> or
>> > abbrevation (_ZoneAbbrev) is requsted, but corresponding pointer is
>> null,
>> > futhermore conversion from `char` to `wchar_t` for abbreviation is
>> performed
>> > if needed.
>> >
>> > PR libstdc++/110739
>> >
>> > libstdc++-v3/ChangeLog:
>> >
>> > * include/bits/chrono_io.h (__format::__no_timezone_available):
>> > Removed, replaced with separate throws in formatter for
>> > __local_time_fmt
>> > (__format::_ChronoParts): Defined additional enumertors and
>> > declared as enum class.
>> > (__format::operator&(_ChronoParts, _ChronoParts))
>> > (__format::operator&=(_ChronoParts&, _ChronoParts))
>> > (__format::operator-(_ChronoParts, _ChronoParts))
>> > (__format::operator-=(_ChronoParts&, _ChronoParts))
>> > (__format::operator==(_ChronoParts, decltype(nullptr)))
>> > (_ChronoSpec::_M_time_only, _ChronoSpec::_M_floating_point_rep)
>> > (_ChronoSpec::_M_custom_rep, _ChronoSpec::_M_needed)
>> > (_ChronoSpec::_M_needs, __format::_ChronoData): Define.
>> > (__format::__formatter_chrono): Redefine to accept _ChronoData.
>> > (__formatter_chrono::_M_format_to_ostream): Moved toi
>> > __formatter_duration.
>> > (__format::__formatter_duration): Define.
>> > (__formatter_chrono_info::format): Pass value-constructed
>> > _ChronoData.
>> > (std::formatter<chrono::day, _CharT>)
>> > (std::formatter<chrono::month, _CharT>)
>> > (std::formatter<chrono::year, _CharT>)
>> > (std::formatter<chrono::weekday, _CharT>)
>> > (std::formatter<chrono::weekday_indexed, _CharT>)
>> > (std::formatter<chrono::weekday_last, _CharT>)
>> > (std::formatter<chrono::month_day, _CharT>)
>> > (std::formatter<chrono::month_day_last, _CharT>)
>> > (std::formatter<chrono::month_weekday, _CharT>)
>> > (std::formatter<chrono::month_weekday_indexed, _CharT>)
>> > (std::formatter<chrono::month_weekday_last, _CharT>)
>> > (std::formatter<chrono::year_month, _CharT>)
>> > (std::formatter<chrono::year_month_day, _CharT>)
>> > (std::formatter<chrono::year_month_day_last, _CharT>)
>> > (std::formatter<chrono::year_month_weekday, _CharT>)
>> > (std::formatter<chrono::year_month_weekday_indexed, _CharT>)
>> > (std::formatter<chrono::year_month_weekday_last, _CharT>):
>> > Construct _ChronoData in format, and configure _M_needed in
>> > _ChronoSpec.
>> > (std::formatter<chrono::duration<_Rep, _Period>, _CharT>)
>> > (std::formatter<chrono::hh_mm_ss<_Duration>, _CharT>)
>> > (std::formatter<chrono::sys_time<_Duration>, _CharT>)
>> > (std::formatter<chrono::utc_time<_Duration>, _CharT>)
>> > (std::formatter<chrono::tai_time<_Duration>, _CharT>)
>> > (std::formatter<chrono::gps_time<_Duration>, _CharT>)
>> > (std::formatter<chrono::file_time<_Duration>, _CharT>)
>> > (std::formatter<chrono::local_time<_Duration>, _CharT>)
>> > (std::formatter<chrono::_detail::__local_time_fmt<_Duration>,
>> _CharT>):
>> > Reworked in terms of __formatter_duration and _ChronoData.
>> > (std::formatter<chrono::_detail::__utc_leap_second<_Duration>,
>> _CharT>):
>> > Removed.
>> > (_Parser<_Duration>::operator()): Adjusted for _ChronoParts
>> > being enum class.
>> > * include/std/chrono (__detail::__utc_leap_second): Removed,
>> > replaced with simply bumping _M_seconds in _ChronoData.
>> > * testsuite/std/time/format/empty_spec.cc: Updated %S integral
>> > ouput.
>> >
>> > Reviewed-by: Jonathan Wakely <jwakely@redhat.com>
>> > Signed-off-by: Tomasz Kamiński <tkaminsk@redhat.com>
>> > ---
>> > Changes in v3:
>> > - addreessed all types and suggetion from review
>> > - added comment for operator-/-= on _ChronoParts
>> > - removed negation of _M_time_only when parsing 'J'
>> >
>> > libstdc++-v3/include/bits/chrono_io.h | 1954 ++++++++++-------
>> > libstdc++-v3/include/std/chrono | 24 -
>> > .../testsuite/std/time/format/empty_spec.cc | 16 +-
>> > 3 files changed, 1165 insertions(+), 829 deletions(-)
>> >
>> > diff --git a/libstdc++-v3/include/bits/chrono_io.h
>> b/libstdc++-v3/include/bits/chrono_io.h
>> > index 4eb00f4932d..8811eaa5b3b 100644
>> > --- a/libstdc++-v3/include/bits/chrono_io.h
>> > +++ b/libstdc++-v3/include/bits/chrono_io.h
>> > @@ -187,11 +187,6 @@ namespace __detail
>> > /// @cond undocumented
>> > namespace __format
>> > {
>> > - [[noreturn,__gnu__::__always_inline__]]
>> > - inline void
>> > - __no_timezone_available()
>> > - { __throw_format_error("format error: no timezone available for %Z
>> or %z"); }
>> > -
>> > [[noreturn,__gnu__::__always_inline__]]
>> > inline void
>> > __not_valid_for_duration()
>> > @@ -204,40 +199,105 @@ namespace __format
>> > { __throw_format_error("format error: chrono-format-spec not valid
>> for "
>> > "argument type"); }
>> >
>> > - template<typename _CharT>
>> > - struct _ChronoSpec : _Spec<_CharT>
>> > - {
>> > - // Placed in tail-padding of __format::_Spec<C>.
>> > - // This indicates that a locale-dependent conversion specifier
>> such as
>> > - // %a is used in the chrono-specs. This is not the same as the
>> > - // _Spec<C>::_M_localized member which indicates that "L" was
>> present
>> > - // in the format-spec, e.g. "{:L%a}" is localized and
>> locale-specific,
>> > - // but "{:L}" is only localized and "{:%a}" is only
>> locale-specific.
>> > - unsigned _M_locale_specific : 1;
>> > -
>> > - basic_string_view<_CharT> _M_chrono_specs;
>> > - };
>> > -
>> > // Represents the information provided by a chrono type.
>> > // e.g. month_weekday has month and weekday but no year or time of
>> day,
>> > // hh_mm_ss has time of day but no date, sys_time is
>> time_point+timezone.
>> > - enum _ChronoParts {
>> > - _Year = 1, _Month = 2, _Day = 4, _Weekday = 8, _TimeOfDay = 16,
>> > - _TimeZone = 32,
>> > - _Date = _Year | _Month | _Day | _Weekday,
>> > - _DateTime = _Date | _TimeOfDay,
>> > + enum class _ChronoParts : unsigned short {
>> > + _None = 0, _TotalSeconds = 1u, _Subseconds = 1u << 2,
>> > +
>> > + // time since epoch
>> > + _EpochUnits = 1u << 3, _UnitSuffix = 1u << 4,
>> > + _EpochSeconds = _EpochUnits | _TotalSeconds,
>> > +
>> > + // local (wall) time
>> > + _LocalDays = 1u << 5,
>> > + _LocalSeconds = _LocalDays | _TotalSeconds,
>> > +
>> > + _Year = 1u << 6, _Month = 1u << 7, _Day = 1u << 8,
>> > + _Weekday = 1u << 9, _WeekdayIndex = 1u << 10, _DayOfYear = 1u <<
>> 11,
>> > + _IndexedWeekday = _Weekday | _WeekdayIndex,
>> > + _YearMonthDay = _Year | _Month | _Day,
>> > + _Date = _LocalDays | _YearMonthDay | _IndexedWeekday | _DayOfYear,
>> > +
>> > + _HoursMinutesSeconds = 1u << 12,
>> > + _TimeOfDay = _HoursMinutesSeconds | _Subseconds,
>> > + _Time = _TimeOfDay | _TotalSeconds,
>> > + _EpochTime = _Time | _EpochUnits | _UnitSuffix,
>> > + _DateTime = _Date | _Time,
>> > +
>> > + _ZoneAbbrev = 1u << 13, _ZoneOffset = 1u << 14,
>> > + _TimeZone = _ZoneAbbrev | _ZoneOffset,
>> > _ZonedDateTime = _DateTime | _TimeZone,
>> > - _Duration = 128 // special case
>> > };
>> >
>> > + [[__gnu__::__always_inline__]]
>> > + constexpr _ChronoParts
>> > + operator&(_ChronoParts __x, _ChronoParts __y) noexcept
>> > + { return static_cast<_ChronoParts>((unsigned)__x & (unsigned)__y); }
>> > +
>> > + [[__gnu__::__always_inline__]]
>> > + constexpr _ChronoParts&
>> > + operator&=(_ChronoParts& __x, _ChronoParts __y) noexcept
>> > + { return __x = __x & __y; }
>> > +
>> > + [[__gnu__::__always_inline__]]
>> > constexpr _ChronoParts
>> > operator|(_ChronoParts __x, _ChronoParts __y) noexcept
>> > - { return static_cast<_ChronoParts>((int)__x | (int)__y); }
>> > + { return static_cast<_ChronoParts>((unsigned short)__x | (unsigned
>> short)__y); }
>> >
>> > + [[__gnu__::__always_inline__]]
>> > constexpr _ChronoParts&
>> > operator|=(_ChronoParts& __x, _ChronoParts __y) noexcept
>> > { return __x = __x | __y; }
>> >
>> > + [[__gnu__::__always_inline__]]
>> > + // returns copy of x with all bits from y unset.
>> > + constexpr _ChronoParts
>> > + operator-(_ChronoParts __x, _ChronoParts __y) noexcept
>> > + { return static_cast<_ChronoParts>((unsigned short)__x & ~(unsigned
>> short)__y); }
>> > +
>> > + [[__gnu__::__always_inline__]]
>> > + // unsets all bits of x that are set in y
>> > + constexpr _ChronoParts&
>> > + operator-=(_ChronoParts& __x, _ChronoParts __y) noexcept
>> > + { return __x = __x - __y; }
>> > +
>> > + [[__gnu__::__always_inline__]]
>> > + constexpr bool
>> > + operator==(_ChronoParts __x, decltype(nullptr)) noexcept
>> > + { return (unsigned short)__x == 0; }
>> > +
>> > + template<typename _CharT>
>> > + struct _ChronoSpec : _Spec<_CharT>
>> > + {
>> > + // When _M_prec_kind is _WP_none, the _M_prec contains the
>> default
>> > + // value of fraction digits to be used for time '%S'.
>> > +
>> > + // Placed in tail-padding of __format::_Spec<C>.
>> > + // This indicates that a locale-dependent conversion specifier
>> such as
>> > + // %a is used in the chrono-specs. This is not the same as the
>> > + // _Spec<C>::_M_localized member which indicates that "L" was
>> present
>> > + // in the format-spec, e.g. "{:L%a}" is localized and
>> locale-specific,
>> > + // but "{:L}" is only localized and "{:%a}" is only
>> locale-specific.
>> > + unsigned _M_locale_specific : 1;
>> > + // Indicates that we are handling duration.
>> > + unsigned _M_time_only : 1;
>> > + // Indicates that duration should be treated as floating point.
>> > + unsigned _M_floating_point_rep : 1;
>> > + // Indicate that duration uses user-defined representation.
>> > + unsigned _M_custom_rep : 1;
>> > + unsigned _M_unused : 4;
>> > +
>> > + // Chrono parts required by format specs
>> > + _ChronoParts _M_needed;
>> > + basic_string_view<_CharT> _M_chrono_specs;
>> > +
>> > + [[__gnu__::__always_inline__]]
>> > + constexpr bool
>> > + _M_needs(_ChronoParts __parts) const
>> > + { return (_M_needed & __parts) != 0; }
>> > + };
>> > +
>> > template<typename _CharT>
>> > struct _ChronoFormats
>> > {
>> > @@ -340,6 +400,152 @@ namespace __format
>> > { return _S_yml().substr(3); }
>> > };
>> >
>> > + template<typename _CharT>
>> > + struct _ChronoData
>> > + {
>> > + static constexpr unsigned _S_max_prec = 18;
>> > + using _Attoseconds = chrono::duration<__UINT_LEAST64_TYPE__,
>> atto>;
>> > +
>> > + using _FormatContext
>> > + = basic_format_context<_Sink_iter<_CharT>, _CharT>;
>> > + using _FormatArgs = basic_format_args<_FormatContext>;
>> > + static inline auto _S_args =
>> std::make_format_args<_FormatContext>();
>> > +
>> > + _ChronoData() = default;
>> > + _ChronoData(_ChronoData&&) = delete;
>> > +
>> > + // time since epoch
>> > + chrono::seconds _M_eseconds;
>> > + // n.b. due offset being seconds or coarser, local and epoch
>> subseconds
>> > + // has the same value
>> > + _Attoseconds _M_subseconds;
>> > + // _M_ereps.get(0) stores duration units
>> > + // _M_ereps.get(1) stores subseconds units
>> > + // _M_ereps.get(2) stores precision
>> > + _FormatArgs _M_ereps = _S_args;
>> > + basic_string_view<_CharT> _M_unit_suffix;
>> > +
>> > + // local (wall) time
>> > + chrono::local_seconds _M_lseconds;
>> > + chrono::local_days _M_ldays;
>> > +
>> > + chrono::year _M_year;
>> > + chrono::month _M_month;
>> > + chrono::day _M_day;
>> > + chrono::weekday _M_weekday;
>> > + unsigned char _M_weekday_index;
>> > + chrono::days _M_day_of_year;
>> > +
>> > + bool _M_is_neg;
>> > + chrono::hours _M_hours;
>> > + chrono::minutes _M_minutes;
>> > + chrono::seconds _M_seconds;
>> > +
>> > + chrono::seconds _M_zone_offset;
>> > + basic_string_view<_CharT> _M_zone_abbrev;
>> > + const char* _M_zone_cstr = "";
>> > +
>> > + template<typename _YearMonth>
>> > + [[__gnu__::__always_inline__]]
>> > + _ChronoParts
>> > + _M_fill_year_month(const _YearMonth& __ym, _ChronoParts __parts)
>> > + {
>> > + _M_year = __ym.year();
>> > + __parts -= _ChronoParts::_Year;
>> > + _M_month = __ym.month();
>> > + __parts -= _ChronoParts::_Month;
>> > + return __parts;
>> > + }
>> > +
>> > + [[__gnu__::__always_inline__]]
>> > + _ChronoParts
>> > + _M_fill_day(chrono::day __d, _ChronoParts __parts)
>> > + {
>> > + _M_day = __d;
>> > + __parts -= _ChronoParts::_Day;
>> > + _M_weekday_index = ((unsigned)__d + 6u) % 7u;
>>
>> FWIW, while looking back at some past experiments I saw that Google
>> Gemini claims this calculation is problematic since it can result in a
>> weekday index of 0 which IIUC would be invalid.
>>
> It results in value 0 only if the __d (day of month) is 0, that is equally
> "invalid",
> so it is a garbage in, garbage out situation.
> (The day value is in range [0, 255], so __d + 6u cannot overflow to value
> < 7).
>
I have realized the real bug, this should be be (((unsigned)__d) + 6u) / 7u.
There is no specifier to print this value currently, but if we add this in
future, we will
print this value.
>
> Regarding the values 0 for both day and weekday_index, they are both
> required
> to be supported by standard:
> * https://eel.is/c++draft/time.cal#day.members-1 - requires preserving
> values in range [0, 255] for day
> * https://eel.is/c++draft/time.cal#wdidx.members-1 - requires preserving
> values in range [0, 7] for index
>
> For such values ok() method returns false, but the result of conversion to
> local days are fully specified,
> and:
> * year_month_day with day() == 0 produces last day of previous month per
> https://eel.is/c++draft/time.cal#ymd.members-19
> * year_month_weekday index() == 0 produces last weekday() of previous
> month per https://eel.is/c++draft/time.cal#ymwd.members-20
> (it's specified as first weekday - 7d) which is the same
>
> Regardless of which weekday last day of month is, it is also in last of
> this weekday of that month, so
> producing weekday index 0 for day 0, is exactly worth standard requires.
>
> And shouldn't the calculation also depend on the month and year?
>>
> No, regardless of which weekday W of week 1st of month is, it will be
> first W of month W[1],
> and 8th will be W[2], 15th will be W[3], e.t.c.
>
>
>>
>> > + __parts -= _ChronoParts::_WeekdayIndex;
>> > + return __parts;
>> > + }
>> > +
>> > + [[__gnu__::__always_inline__]]
>> > + _ChronoParts
>> > + _M_fill_weekday(chrono::weekday_indexed __wi, _ChronoParts
>> __parts)
>> > + {
>> > + _M_weekday = __wi.weekday();
>> > + __parts -= _ChronoParts::_Weekday;
>> > + _M_weekday_index = __wi.index();
>> > + __parts -= _ChronoParts::_WeekdayIndex;
>> > + return __parts;
>> > + }
>> > +
>> > + [[__gnu__::__always_inline__]]
>> > + _ChronoParts
>> > + _M_fill_aux(chrono::local_days __ld, _ChronoParts __parts)
>> > + {
>> > + using namespace chrono;
>> > + if ((__parts & _ChronoParts::_Weekday) != 0)
>> > + _M_weekday = weekday(__ld);
>> > + __parts -= _ChronoParts::_Weekday;
>> > + if ((__parts & _ChronoParts::_DayOfYear) != 0)
>> > + // See "Calculating Ordinal Dates" at
>> > + //
>> https://github.com/HowardHinnant/date/wiki/Examples-and-Recipes
>> > + _M_day_of_year = __ld - local_days(_M_year/January/0);
>> > + __parts -= _ChronoParts::_DayOfYear;
>> > + return __parts;
>> > + }
>> > +
>> > + [[__gnu__::__always_inline__]]
>> > + _ChronoParts
>> > + _M_fill_ldays(chrono::local_days __ld, _ChronoParts __parts)
>> > + {
>> > + _M_ldays = __ld;
>> > + __parts -= _ChronoParts::_LocalDays;
>> > + return _M_fill_aux(__ld, __parts);
>> > + }
>> > +
>> > + void
>> > + _M_fill_time(chrono::seconds __d)
>> > + {
>> > + chrono::hh_mm_ss<chrono::seconds> __hms(__d);
>> > + _M_hours = __hms.hours();
>> > + _M_minutes = __hms.minutes();
>> > + _M_seconds = __hms.seconds();
>> > + }
>> > +
>> > + void
>> > + _M_fill_date_time(chrono::local_seconds __ls, _ChronoParts
>> __parts)
>> > + {
>> > + _M_ldays = chrono::floor<chrono::days>(__ls);
>> > + __parts -= _ChronoParts::_LocalDays;
>> > + if ((__parts & _ChronoParts::_HoursMinutesSeconds) != 0)
>> > + _M_fill_time(_M_lseconds - _M_ldays);
>> > +
>> > + if ((__parts & _ChronoParts::_Date) != 0)
>> > + {
>> > + const chrono::year_month_day __ymd(_M_ldays);
>> > + _M_fill_year_month(__ymd, __parts);
>> > + _M_fill_day(__ymd.day(), __parts);
>> > + _M_fill_aux(_M_ldays, __parts);
>> > + }
>> > + }
>> > +
>> > + void
>> > + _M_fill_zone(const char* __abbrev, const wchar_t* __wabbrev)
>> > + {
>> > + if constexpr (is_same_v<_CharT, char>)
>> > + _M_zone_abbrev = __abbrev;
>> > + else
>> > + _M_zone_abbrev = __wabbrev;
>> > + _M_zone_cstr = __abbrev;
>> > + }
>> > +
>> > + [[__gnu__::__always_inline__]]
>> > + void
>> > + _M_fill_utc_zone()
>> > + { _M_fill_zone("UTC", L"UTC"); }
>> > + };
>> > +
>> > // TODO rename this to chrono::__formatter? or
>> chrono::__detail::__formatter?
>> > template<typename _CharT>
>> > struct __formatter_chrono
>> > @@ -357,7 +563,7 @@ namespace __format
>> > template<typename _ParseContext>
>> > constexpr typename _ParseContext::iterator
>> > _M_parse(_ParseContext& __pc, _ChronoParts __parts,
>> > - const _ChronoSpec<_CharT>& __def = {})
>> > + const _ChronoSpec<_CharT>& __def)
>> > {
>> > auto __first = __pc.begin();
>> > auto __last = __pc.end();
>> > @@ -388,11 +594,18 @@ namespace __format
>> > if (__finished())
>> > return __first;
>> >
>> > - if (__parts & _ChronoParts::_Duration)
>> > + if (*__first == '.')
>> > {
>> > - __first = __spec._M_parse_precision(__first, __last, __pc);
>> > - if (__finished())
>> > - return __first;
>> > + if ((__parts & _ChronoParts::_EpochUnits) == 0
>> > + || !__spec._M_floating_point_rep)
>> > + __throw_format_error("format error: invalid precision for
>> duration");
>> > +
>> > + // Precision is allowed, but value is ignored.
>> > + __first = _Spec<_CharT>()._M_parse_precision(__first,
>> __last, __pc);
>> > + // Still inditate that there was user supplied precision.
>> > + __spec._M_prec_kind = _WP_value;
>> > + if (__finished())
>> > + return __first;
>> > }
>> >
>> > __spec._M_localized = false;
>> > @@ -418,7 +631,8 @@ namespace __format
>> > // against __parts (so fail for %Y if no year in parts).
>> > // Save range in __spec._M_chrono_specs.
>> > __spec._M_debug = false;
>> > - __spec._M_locale_specific = true;
>> > + __spec._M_locale_specific = false;
>> > + __spec._M_needed = _ChronoParts::_None;
>> > __spec._M_chrono_specs = __string_view();
>> >
>> > const auto __chrono_specs = __first++; // Skip leading '%'
>> > @@ -428,17 +642,18 @@ namespace __format
>> >
>> > _CharT __mod{};
>> > bool __conv = true;
>> > - int __needed = 0;
>> > - bool __locale_specific = false;
>> > -
>> > while (__first != __last)
>> > {
>> > enum _Mods { _Mod_none, _Mod_E, _Mod_O, _Mod_E_O };
>> > _Mods __allowed_mods = _Mod_none;
>> >
>> > + _ChronoParts __needed = _ChronoParts::_None;
>> > + bool __locale_specific = false;
>> > +
>> > _CharT __c = *__first++;
>> > switch (__c)
>> > {
>> > + using enum _ChronoParts;
>> > case 'a':
>> > case 'A':
>> > __needed = _Weekday;
>> > @@ -451,7 +666,7 @@ namespace __format
>> > __locale_specific = true;
>> > break;
>> > case 'c':
>> > - __needed = _DateTime;
>> > + __needed = _Date|_HoursMinutesSeconds;
>> > __allowed_mods = _Mod_E;
>> > __locale_specific = true;
>> > break;
>> > @@ -466,27 +681,27 @@ namespace __format
>> > break;
>> > case 'D':
>> > case 'F':
>> > - __needed = _Date;
>> > + __needed = _YearMonthDay;
>> > break;
>> > case 'g':
>> > case 'G':
>> > - __needed = _Date;
>> > + __needed = _LocalDays|_Weekday;
>> > break;
>> > case 'H':
>> > case 'I':
>> > - __needed = _TimeOfDay;
>> > + __needed = _HoursMinutesSeconds;
>> > __allowed_mods = _Mod_O;
>> > break;
>> > case 'j':
>> > - if (!(__parts & _Duration))
>> > - __needed = _Date;
>> > + __needed = __spec._M_time_only ? _HoursMinutesSeconds
>> > + : _DayOfYear;
>> > break;
>> > case 'm':
>> > __needed = _Month;
>> > __allowed_mods = _Mod_O;
>> > break;
>> > case 'M':
>> > - __needed = _TimeOfDay;
>> > + __needed = _HoursMinutesSeconds;
>> > __allowed_mods = _Mod_O;
>> > break;
>> > case 'p':
>> > @@ -494,12 +709,16 @@ namespace __format
>> > __locale_specific = true;
>> > [[fallthrough]];
>> > case 'R':
>> > + __needed = _HoursMinutesSeconds;
>> > + break;
>> > case 'T':
>> > __needed = _TimeOfDay;
>> > break;
>> > case 'q':
>> > + __needed = _UnitSuffix;
>> > + break;
>> > case 'Q':
>> > - __needed = _Duration;
>> > + __needed = _EpochUnits;
>> > break;
>> > case 'S':
>> > __needed = _TimeOfDay;
>> > @@ -513,7 +732,7 @@ namespace __format
>> > case 'U':
>> > case 'V':
>> > case 'W':
>> > - __needed = _Date;
>> > + __needed = _LocalDays|_Year|_DayOfYear|_Weekday;
>> > __allowed_mods = _Mod_O;
>> > break;
>> > case 'x':
>> > @@ -522,7 +741,7 @@ namespace __format
>> > __allowed_mods = _Mod_E;
>> > break;
>> > case 'X':
>> > - __needed = _TimeOfDay;
>> > + __needed = _HoursMinutesSeconds;
>> > __locale_specific = true;
>> > __allowed_mods = _Mod_E;
>> > break;
>> > @@ -535,11 +754,11 @@ namespace __format
>> > __allowed_mods = _Mod_E;
>> > break;
>> > case 'z':
>> > - __needed = _TimeZone;
>> > + __needed = _ZoneOffset;
>> > __allowed_mods = _Mod_E_O;
>> > break;
>> > case 'Z':
>> > - __needed = _TimeZone;
>> > + __needed = _ZoneAbbrev;
>> > break;
>> > case 'n':
>> > case 't':
>> > @@ -567,10 +786,16 @@ namespace __format
>> > __locale_specific = true;
>> > __mod = _CharT();
>> >
>> > + // localized formats do not include subseconds
>> > + if (__locale_specific)
>> > + __needed -= _ChronoParts::_Subseconds;
>> > +
>> > if ((__parts & __needed) != __needed)
>> > __throw_format_error("chrono format error: format
>> argument "
>> > "does not contain the information "
>> > "required by the chrono-specs");
>> > + __spec._M_needed |= __needed;
>> > + __spec._M_locale_specific |= __locale_specific;
>> >
>> > // Scan for next '%', ignoring literal-chars before it.
>> > size_t __pos = __string_view(__first, __last -
>> __first).find('%');
>> > @@ -596,21 +821,14 @@ namespace __format
>> > _M_spec = __spec;
>> > _M_spec._M_chrono_specs
>> > = __string_view(__chrono_specs, __first -
>> __chrono_specs);
>> > - _M_spec._M_locale_specific = __locale_specific;
>> >
>> > return __first;
>> > }
>> >
>> > - // TODO this function template is instantiated for every
>> different _Tp.
>> > - // Consider creating a polymorphic interface for calendar types
>> so
>> > - // that we instantiate fewer different specializations. Similar
>> to
>> > - // _Sink_iter for std::format. Replace each _S_year, _S_day etc.
>> with
>> > - // member functions of that type.
>> > // pre: !_M_spec._M_chrono_specs.empty()
>> > - template<typename _Tp, typename _FormatContext>
>> > + template<typename _FormatContext>
>> > typename _FormatContext::iterator
>> > - _M_format(const _Tp& __t, _FormatContext& __fc,
>> > - bool __is_neg = false) const
>> > + _M_format(const _ChronoData<_CharT>& __t, _FormatContext& __fc)
>> const
>> > {
>> > #if defined _GLIBCXX_USE_NL_LANGINFO_L && __CHAR_BIT__ == 8
>> > // _GLIBCXX_RESOLVE_LIB_DEFECTS
>> > @@ -626,36 +844,80 @@ namespace __format
>> > // in the locale's encoding to UTF-8.
>> > locale __loc = __fc.locale();
>> > if (__loc != locale::classic())
>> > - __fc._M_loc = __with_encoding_conversion(__loc);
>> > + __fc._M_loc = __with_encoding_conversion(__loc);
>> > }
>> > #endif
>> > - // formatter<duration> passes the correct value of __is_neg
>> > - // for durations but for hh_mm_ss we decide it here.
>> > - if constexpr (__is_specialization_of<_Tp, chrono::hh_mm_ss>)
>> > - __is_neg = __t.is_negative();
>> >
>> > const size_t __padwidth = _M_spec._M_get_width(__fc);
>> > if (__padwidth == 0)
>> > - return _M_format_to(__t, __fc.out(), __fc, __is_neg);
>> > + return _M_format_to(__t, __fc.out(), __fc);
>> >
>> > using _Out = typename _FormatContext::iterator;
>> > _Padding_sink<_Out, _CharT> __sink(__fc.out(), __padwidth);
>> > - _M_format_to(__t, __sink.out(), __fc, __is_neg);
>> > + _M_format_to(__t, __sink.out(), __fc);
>> > return __sink._M_finish(_M_spec._M_align, _M_spec._M_fill);
>> > }
>> >
>> > - template<typename _Tp, typename _Out, typename _FormatContext>
>> > +
>> > + _ChronoSpec<_CharT> _M_spec;
>> > +
>> > + protected:
>> > + static constexpr const _CharT* _S_chars
>> > + = _GLIBCXX_WIDEN("0123456789.Lf:/ +-{}");
>> > + static constexpr _CharT _S_dot = _S_chars[10];
>> > + static constexpr _CharT _S_colon = _S_chars[13];
>> > + static constexpr _CharT _S_slash = _S_chars[14];
>> > + static constexpr _CharT _S_space = _S_chars[15];
>> > + static constexpr const _CharT* _S_fp_fmt = _S_chars + 11;
>> > + static constexpr const _CharT* _S_plus_minus = _S_chars + 16;
>> > + static constexpr const _CharT* _S_minus_empty_spec = _S_chars +
>> 17;
>> > + static constexpr const _CharT* _S_empty_spec = _S_chars + 18;
>> > +
>> > + // Return the formatting locale.
>> > + template<typename _FormatContext>
>> > + std::locale
>> > + _M_locale(_FormatContext& __fc) const
>> > + {
>> > + if (!_M_spec._M_localized)
>> > + return std::locale::classic();
>> > + else
>> > + return __fc.locale();
>> > + }
>> > +
>> > + private:
>> > + template<typename _OutIter>
>> > + _OutIter
>> > + _M_write(_OutIter __out, const locale& __loc, __string_view __s)
>> const
>> > + {
>> > +#if defined _GLIBCXX_USE_NL_LANGINFO_L && __CHAR_BIT__ == 8
>> > + __sso_string __buf;
>> > + // _GLIBCXX_RESOLVE_LIB_DEFECTS
>> > + // 3565. Handling of encodings in localized formatting
>> > + // of chrono types is underspecified
>> > + if constexpr (is_same_v<_CharT, char>)
>> > + if constexpr (__unicode::__literal_encoding_is_utf8())
>> > + if (_M_spec._M_localized && _M_spec._M_locale_specific
>> > + && __loc != locale::classic())
>> > + {
>> > + extern string_view
>> > + __locale_encoding_to_utf8(const locale&, string_view,
>> void*);
>> > +
>> > + __s = __locale_encoding_to_utf8(__loc, __s, &__buf);
>> > + }
>> > +#endif
>> > + return __format::__write(std::move(__out), __s);
>> > + }
>> > +
>> > + template<typename _Out, typename _FormatContext>
>> > _Out
>> > - _M_format_to(const _Tp& __t, _Out __out, _FormatContext& __fc,
>> > - bool __is_neg) const
>> > + _M_format_to(const _ChronoData<_CharT>& __t, _Out __out,
>> > + _FormatContext& __fc) const
>> > {
>> > auto __first = _M_spec._M_chrono_specs.begin();
>> > const auto __last = _M_spec._M_chrono_specs.end();
>> >
>> > - auto __print_sign = [&__is_neg, &__out] {
>> > - if constexpr (chrono::__is_duration_v<_Tp>
>> > - || __is_specialization_of<_Tp,
>> chrono::hh_mm_ss>)
>> > - if (__is_neg)
>> > + auto __print_sign = [__is_neg = __t._M_is_neg, &__out] ()
>> mutable {
>> > + if (__is_neg)
>> > {
>> > *__out++ = _S_plus_minus[1];
>> > __is_neg = false;
>> > @@ -676,16 +938,16 @@ namespace __format
>> > {
>> > // %\0 is extension for handling weekday index
>> > case '\0':
>> > - __out = _M_wi(__t, std::move(__out), __fc);
>> > + __out = _M_wi(__t._M_weekday_index, std::move(__out),
>> __fc);
>> > break;
>> > case 'a':
>> > case 'A':
>> > - __out = _M_a_A(__t, std::move(__out), __fc, __c == 'A');
>> > + __out = _M_a_A(__t._M_weekday, std::move(__out), __fc,
>> __c == 'A');
>> > break;
>> > case 'b':
>> > case 'h':
>> > case 'B':
>> > - __out = _M_b_B(__t, std::move(__out), __fc, __c == 'B');
>> > + __out = _M_b_B(__t._M_month, std::move(__out), __fc,
>> __c == 'B');
>> > break;
>> > case 'c':
>> > case 'r':
>> > @@ -696,11 +958,11 @@ namespace __format
>> > case 'C':
>> > case 'y':
>> > case 'Y':
>> > - __out = _M_C_y_Y(__t, std::move(__out), __fc, __c,
>> __mod);
>> > + __out = _M_C_y_Y(__t._M_year, std::move(__out), __fc,
>> __c, __mod);
>> > break;
>> > case 'd':
>> > case 'e':
>> > - __out = _M_d_e(__t, std::move(__out), __fc, __c, __mod
>> == 'O');
>> > + __out = _M_d_e(__t._M_day, std::move(__out), __fc, __c,
>> __mod == 'O');
>> > break;
>> > case 'D':
>> > __out = _M_D(__t, std::move(__out), __fc);
>> > @@ -714,33 +976,25 @@ namespace __format
>> > break;
>> > case 'H':
>> > case 'I':
>> > - __out = _M_H_I(__t, __print_sign(), __fc, __c, __mod ==
>> 'O');
>> > + __out = _M_H_I(__t._M_hours, __print_sign(), __fc, __c,
>> __mod == 'O');
>> > break;
>> > case 'j':
>> > __out = _M_j(__t, __print_sign(), __fc);
>> > break;
>> > case 'm':
>> > - __out = _M_m(__t, std::move(__out), __fc, __mod == 'O');
>> > + __out = _M_m(__t._M_month, std::move(__out), __fc,
>> __mod == 'O');
>> > break;
>> > case 'M':
>> > - __out = _M_M(__t, __print_sign(), __fc, __mod == 'O');
>> > + __out = _M_M(__t._M_minutes, __print_sign(), __fc,
>> __mod == 'O');
>> > break;
>> > case 'p':
>> > - __out = _M_p(__t, std::move(__out), __fc);
>> > + __out = _M_p(__t._M_hours, std::move(__out), __fc);
>> > break;
>> > case 'q':
>> > - __out = _M_q(__t, std::move(__out), __fc);
>> > + __out = _M_q(__t._M_unit_suffix, std::move(__out),
>> __fc);
>> > break;
>> > case 'Q':
>> > - // %Q The duration's numeric value.
>> > - if constexpr (chrono::__is_duration_v<_Tp>)
>> > - // _GLIBCXX_RESOLVE_LIB_DEFECTS
>> > - // 4118. How should duration formatters format custom
>> rep?
>> > - __out = std::format_to(__print_sign(), _S_empty_spec,
>> > - +__t.count());
>> > - else
>> > - __throw_format_error("chrono format error: argument
>> is "
>> > - "not a duration");
>> > + __out = _M_Q(__t, __print_sign(), __fc);
>> > break;
>> > case 'R':
>> > case 'T':
>> > @@ -751,7 +1005,7 @@ namespace __format
>> > break;
>> > case 'u':
>> > case 'w':
>> > - __out = _M_u_w(__t, std::move(__out), __fc, __c, __mod
>> == 'O');
>> > + __out = _M_u_w(__t._M_weekday, std::move(__out), __fc,
>> __c, __mod == 'O');
>> > break;
>> > case 'U':
>> > case 'V':
>> > @@ -760,10 +1014,10 @@ namespace __format
>> > __mod == 'O');
>> > break;
>> > case 'z':
>> > - __out = _M_z(__t, std::move(__out), __fc, (bool)__mod);
>> > + __out = _M_z(__t._M_zone_offset, std::move(__out),
>> __fc, (bool)__mod);
>> > break;
>> > case 'Z':
>> > - __out = _M_Z(__t, std::move(__out), __fc);
>> > + __out = _M_Z(__t._M_zone_abbrev, std::move(__out),
>> __fc);
>> > break;
>> > case 'n':
>> > *__out++ = __literals[0];
>> > @@ -804,78 +1058,12 @@ namespace __format
>> > return std::move(__out);
>> > }
>> >
>> > - // Format duration for empty chrono-specs, e.g. "{}" (C++20
>> [time.format] p6).
>> > - template<typename _Rep, typename _Period, typename
>> _FormatContext>
>> > - typename _FormatContext::iterator
>> > - _M_format_to_ostream(const chrono::duration<_Rep, _Period>& __d,
>> > - bool __is_neg, _FormatContext& __fc) const
>> > - {
>> > - basic_ostringstream<_CharT> __os;
>> > - __os.imbue(_M_locale(__fc));
>> > -
>> > - if (__is_neg) [[unlikely]]
>> > - __os << _S_plus_minus[1];
>> > - __os << __d;
>> > -
>> > - auto __str = std::move(__os).str();
>> > - return __format::__write_padded_as_spec(__str, __str.size(),
>> > - __fc, _M_spec);
>> > - }
>> > -
>> > - _ChronoSpec<_CharT> _M_spec;
>> > -
>> > - private:
>> > - // Return the formatting locale.
>> > template<typename _FormatContext>
>> > - std::locale
>> > - _M_locale(_FormatContext& __fc) const
>> > - {
>> > - if (!_M_spec._M_localized)
>> > - return std::locale::classic();
>> > - else
>> > - return __fc.locale();
>> > - }
>> > -
>> > - static constexpr const _CharT* _S_chars
>> > - = _GLIBCXX_WIDEN("0123456789:/ +-{}");
>> > - static constexpr _CharT _S_colon = _S_chars[10];
>> > - static constexpr _CharT _S_slash = _S_chars[11];
>> > - static constexpr _CharT _S_space = _S_chars[12];
>> > - static constexpr const _CharT* _S_plus_minus = _S_chars + 13;
>> > - static constexpr const _CharT* _S_minus_empty_spec = _S_chars +
>> 14;
>> > - static constexpr const _CharT* _S_empty_spec = _S_chars + 15;
>> > -
>> > - template<typename _OutIter>
>> > - _OutIter
>> > - _M_write(_OutIter __out, const locale& __loc, __string_view __s)
>> const
>> > - {
>> > -#if defined _GLIBCXX_USE_NL_LANGINFO_L && __CHAR_BIT__ == 8
>> > - __sso_string __buf;
>> > - // _GLIBCXX_RESOLVE_LIB_DEFECTS
>> > - // 3565. Handling of encodings in localized formatting
>> > - // of chrono types is underspecified
>> > - if constexpr (is_same_v<_CharT, char>)
>> > - if constexpr (__unicode::__literal_encoding_is_utf8())
>> > - if (_M_spec._M_localized && _M_spec._M_locale_specific
>> > - && __loc != locale::classic())
>> > - {
>> > - extern string_view
>> > - __locale_encoding_to_utf8(const locale&, string_view,
>> void*);
>> > -
>> > - __s = __locale_encoding_to_utf8(__loc, __s, &__buf);
>> > - }
>> > -#endif
>> > - return __format::__write(std::move(__out), __s);
>> > - }
>> > -
>> > - template<typename _Tp, typename _FormatContext>
>> > typename _FormatContext::iterator
>> > - _M_wi(const _Tp& __t, typename _FormatContext::iterator __out,
>> > - _FormatContext& __ctx) const
>> > + _M_wi(unsigned __wi, typename _FormatContext::iterator __out,
>> > + _FormatContext& __ctx) const
>> > {
>> > // %\0 Extension to format weekday index, used only by empty
>> format spec
>> > - unsigned __wi = _S_weekday_index(__t);
>> > -
>> > _CharT __buf[3];
>> > __out = __format::__write(std::move(__out), _S_str_d1(__buf,
>> __wi));
>> > if (_M_spec._M_debug && (__wi < 1 || __wi > 5))
>> > @@ -884,14 +1072,13 @@ namespace __format
>> > return std::move(__out);
>> > }
>> >
>> > - template<typename _Tp, typename _FormatContext>
>> > + template<typename _FormatContext>
>> > typename _FormatContext::iterator
>> > - _M_a_A(const _Tp& __t, typename _FormatContext::iterator __out,
>> > + _M_a_A(chrono::weekday __wd, typename _FormatContext::iterator
>> __out,
>> > _FormatContext& __ctx, bool __full) const
>> > {
>> > // %a Locale's abbreviated weekday name.
>> > // %A Locale's full weekday name.
>> > - chrono::weekday __wd = _S_weekday(__t);
>> > if (!__wd.ok())
>> > {
>> > if (!_M_spec._M_debug)
>> > @@ -915,14 +1102,13 @@ namespace __format
>> > return _M_write(std::move(__out), __loc, __str);
>> > }
>> >
>> > - template<typename _Tp, typename _FormatContext>
>> > + template<typename _FormatContext>
>> > typename _FormatContext::iterator
>> > - _M_b_B(const _Tp& __t, typename _FormatContext::iterator __out,
>> > + _M_b_B(chrono::month __m, typename _FormatContext::iterator __out,
>> > _FormatContext& __ctx, bool __full) const
>> > {
>> > // %b Locale's abbreviated month name.
>> > // %B Locale's full month name.
>> > - chrono::month __m = _S_month(__t);
>> > if (!__m.ok())
>> > {
>> > if (!_M_spec._M_debug)
>> > @@ -946,9 +1132,9 @@ namespace __format
>> > return _M_write(std::move(__out), __loc, __str);
>> > }
>> >
>> > - template<typename _Tp, typename _FormatContext>
>> > + template<typename _FormatContext>
>> > typename _FormatContext::iterator
>> > - _M_c_r_x_X(const _Tp& __t, typename _FormatContext::iterator
>> __out,
>> > + _M_c_r_x_X(const _ChronoData<_CharT>& __t, typename
>> _FormatContext::iterator __out,
>> > _FormatContext& __ctx, _CharT __conv, _CharT __mod)
>> const
>> > {
>> > // %c Locale's date and time representation.
>> > @@ -960,9 +1146,6 @@ namespace __format
>> > // %EX Locale's alternative time representation.
>> >
>> > using namespace chrono;
>> > - using ::std::chrono::__detail::__utc_leap_second;
>> > - using ::std::chrono::__detail::__local_time_fmt;
>> > -
>> > struct tm __tm{};
>> >
>> > // Some locales use %Z in their %c format but we don't want
>> strftime
>> > @@ -974,53 +1157,27 @@ namespace __format
>> > #ifdef _GLIBCXX_USE_STRUCT_TM_TM_ZONE
>> > // POSIX.1-2024 adds tm.tm_zone which will be used for %Z.
>> > // BSD has had tm_zone since 1987 but as char* so cast away
>> const.
>> > - if constexpr (__is_time_point_v<_Tp>)
>> > - {
>> > - // One of sys_time, utc_time, or local_time.
>> > - if constexpr (!is_same_v<typename _Tp::clock, local_t>)
>> > - __tm.tm_zone = const_cast<char*>("UTC");
>> > - }
>> > - else if constexpr (__is_specialization_of<_Tp,
>> __local_time_fmt>)
>> > - {
>> > - // local-time-format-t is used to provide time zone info for
>> > - // one of zoned_time, tai_time, gps_time, or local_time.
>> > - if (__t._M_abbrev)
>> > - __tm.tm_zone = const_cast<char*>(__t._M_abbrev->c_str());
>> > - }
>> > - else
>> > - __tm.tm_zone = const_cast<char*>("UTC");
>> > + if (__t._M_zone_cstr)
>> > + __tm.tm_zone = const_cast<char*>(__t._M_zone_cstr);
>> > #endif
>> >
>> > - if (__conv == 'c' || __conv == 'x')
>> > - {
>> > - auto __d = _S_days(__t); // Either sys_days or local_days.
>> > - using _TDays = decltype(__d);
>> > - const year_month_day __ymd(__d);
>> > - const auto __y = __ymd.year();
>> > -
>> > - __tm.tm_year = (int)__y - 1900;
>> > - __tm.tm_yday = (__d - _TDays(__y/January/1)).count();
>> > - __tm.tm_mon = (unsigned)__ymd.month() - 1;
>> > - __tm.tm_mday = (unsigned)__ymd.day();
>> > - __tm.tm_wday = weekday(__d).c_encoding();
>> > - }
>> > -
>> > - if (__conv != 'x')
>> > - {
>> > - const auto __hms = _S_hms(__t);
>> > - __tm.tm_hour = __hms.hours().count();
>> > - __tm.tm_min = __hms.minutes().count();
>> > - __tm.tm_sec = __hms.seconds().count();
>> > - }
>> > + __tm.tm_year = (int)__t._M_year - 1900;
>> > + __tm.tm_yday = __t._M_day_of_year.count();
>> > + __tm.tm_mon = (unsigned)__t._M_month - 1;
>> > + __tm.tm_mday = (unsigned)__t._M_day;
>> > + __tm.tm_wday = __t._M_weekday.c_encoding();
>> > + __tm.tm_hour = __t._M_hours.count();
>> > + __tm.tm_min = __t._M_minutes.count();
>> > + __tm.tm_sec = __t._M_seconds.count();
>> >
>> > return _M_locale_fmt(std::move(__out), _M_locale(__ctx), __tm,
>> > __conv, __mod);
>> > }
>> >
>> > - template<typename _Tp, typename _FormatContext>
>> > + template<typename _FormatContext>
>> > typename _FormatContext::iterator
>> > - _M_C_y_Y(const _Tp& __t, typename _FormatContext::iterator __out,
>> > - _FormatContext& __ctx, _CharT __conv, _CharT __mod = 0)
>> const
>> > + _M_C_y_Y(chrono::year __y, typename _FormatContext::iterator
>> __out,
>> > + _FormatContext& __ctx, _CharT __conv, _CharT __mod = 0)
>> const
>> > {
>> > // %C Year divided by 100 using floored division.
>> > // %EC Locale's alternative preresentation of the century (era
>> name).
>> > @@ -1030,8 +1187,6 @@ namespace __format
>> > // %Y Year as a decimal number.
>> > // %EY Locale's alternative full year representation.
>> >
>> > - chrono::year __y = _S_year(__t);
>> > -
>> > if (__mod && _M_spec._M_localized) [[unlikely]]
>> > if (auto __loc = __ctx.locale(); __loc != locale::classic())
>> > {
>> > @@ -1080,15 +1235,14 @@ namespace __format
>> > return __out;
>> > }
>> >
>> > - template<typename _Tp, typename _FormatContext>
>> > + template<typename _FormatContext>
>> > typename _FormatContext::iterator
>> > - _M_D(const _Tp& __t, typename _FormatContext::iterator __out,
>> > + _M_D(const _ChronoData<_CharT>& __t, typename
>> _FormatContext::iterator __out,
>> > _FormatContext&) const
>> > {
>> > - auto __ymd = _S_date(__t);
>> > - auto __di = (unsigned)__ymd.day();
>> > - auto __mi = (unsigned)__ymd.month();
>> > - auto __yi = __builtin_abs((int)__ymd.year()) % 100;
>> > + auto __di = (unsigned)__t._M_day;
>> > + auto __mi = (unsigned)__t._M_month;
>> > + auto __yi = __builtin_abs((int)__t._M_year) % 100;
>> >
>> > if (__mi >= 100 || __di >= 100) [[unlikely]]
>> > {
>> > @@ -1112,9 +1266,9 @@ namespace __format
>> > return std::move(__out);
>> > }
>> >
>> > - template<typename _Tp, typename _FormatContext>
>> > + template<typename _FormatContext>
>> > typename _FormatContext::iterator
>> > - _M_d_e(const _Tp& __t, typename _FormatContext::iterator __out,
>> > + _M_d_e(chrono::day __d, typename _FormatContext::iterator __out,
>> > _FormatContext& __ctx, _CharT __conv, bool __mod = false)
>> const
>> > {
>> > // %d The day of month as a decimal number.
>> > @@ -1122,7 +1276,6 @@ namespace __format
>> > // %e Day of month as decimal number, padded with space.
>> > // %Oe Locale's alternative digits.
>> >
>> > - chrono::day __d = _S_day(__t);
>> > unsigned __i = (unsigned)__d;
>> >
>> > if (__mod && _M_spec._M_localized) [[unlikely]]
>> > @@ -1150,15 +1303,14 @@ namespace __format
>> > return std::move(__out);
>> > }
>> >
>> > - template<typename _Tp, typename _FormatContext>
>> > + template<typename _FormatContext>
>> > typename _FormatContext::iterator
>> > - _M_F(const _Tp& __t, typename _FormatContext::iterator __out,
>> > + _M_F(const _ChronoData<_CharT>& __t, typename
>> _FormatContext::iterator __out,
>> > _FormatContext&) const
>> > {
>> > - auto __ymd = _S_date(__t);
>> > - auto __di = (unsigned)__ymd.day();
>> > - auto __mi = (unsigned)__ymd.month();
>> > - auto __yi = (int)__ymd.year();
>> > + auto __di = (unsigned)__t._M_day;
>> > + auto __mi = (unsigned)__t._M_month;
>> > + auto __yi = (int)__t._M_year;
>> > const bool __is_neg = __yi < 0;
>> > __yi = __builtin_abs(__yi);
>> >
>> > @@ -1185,31 +1337,31 @@ namespace __format
>> > __out = __format::__write(std::move(__out), __sv);
>> > }
>> >
>> > - if (_M_spec._M_debug && !__ymd.ok())
>> > + if (_M_spec._M_debug &&
>> !(__t._M_year/__t._M_month/__t._M_day).ok())
>> > __out = __format::__write(std::move(__out),
>> > __string_view(_GLIBCXX_WIDEN(" is not a valid
>> date")));
>> > return std::move(__out);
>> > }
>> >
>> > - template<typename _Tp, typename _FormatContext>
>> > + template<typename _FormatContext>
>> > typename _FormatContext::iterator
>> > - _M_g_G(const _Tp& __t, typename _FormatContext::iterator __out,
>> > + _M_g_G(const _ChronoData<_CharT>& __t, typename
>> _FormatContext::iterator __out,
>> > _FormatContext& __ctx, bool __full) const
>> > {
>> > // %g last two decimal digits of the ISO week-based year.
>> > // %G ISO week-based year.
>> > using namespace chrono;
>> > - auto __d = _S_days(__t);
>> > + auto __d = __t._M_ldays;
>> > // Move to nearest Thursday:
>> > - __d -= (weekday(__d) - Monday) - days(3);
>> > + __d -= (__t._M_weekday - Monday) - days(3);
>> > // ISO week-based year is the year that contains that Thursday:
>> > year __y = year_month_day(__d).year();
>> > return _M_C_y_Y(__y, std::move(__out), __ctx, "yY"[__full]);
>> > }
>> >
>> > - template<typename _Tp, typename _FormatContext>
>> > + template<typename _FormatContext>
>> > typename _FormatContext::iterator
>> > - _M_H_I(const _Tp& __t, typename _FormatContext::iterator __out,
>> > + _M_H_I(chrono::hours __h, typename _FormatContext::iterator __out,
>> > _FormatContext& __ctx, _CharT __conv, bool __mod = false)
>> const
>> > {
>> > // %H The hour (24-hour clock) as a decimal number.
>> > @@ -1217,8 +1369,7 @@ namespace __format
>> > // %I The hour (12-hour clock) as a decimal number.
>> > // %OI Locale's alternative representation.
>> >
>> > - const auto __hms = _S_hms(__t);
>> > - int __i = __hms.hours().count();
>> > + int __i = __h.count();
>> >
>> > if (__mod && _M_spec._M_localized) [[unlikely]]
>> > if (auto __loc = __ctx.locale(); __loc != locale::classic())
>> > @@ -1241,44 +1392,30 @@ namespace __format
>> > return __format::__write(std::move(__out), _S_two_digits(__i));
>> > }
>> >
>> > - template<typename _Tp, typename _FormatContext>
>> > + template<typename _FormatContext>
>> > typename _FormatContext::iterator
>> > - _M_j(const _Tp& __t, typename _FormatContext::iterator __out,
>> > + _M_j(const _ChronoData<_CharT>& __t, typename
>> _FormatContext::iterator __out,
>> > _FormatContext&) const
>> > {
>> > - if constexpr (chrono::__is_duration_v<_Tp>)
>> > - {
>> > - // Decimal number of days, without padding.
>> > - unsigned __d =
>> chrono::duration_cast<chrono::days>(__t).count();
>> > - return std::format_to(std::move(__out), _S_empty_spec, __d);
>> > - }
>> > - else
>> > - {
>> > - // Day of the year as a decimal number, padding with zero.
>> > - using namespace chrono;
>> > - auto __day = _S_days(__t);
>> > - auto __ymd = _S_date(__t);
>> > - days __d;
>> > - // See "Calculating Ordinal Dates" at
>> > - //
>> https://github.com/HowardHinnant/date/wiki/Examples-and-Recipes
>> > - if constexpr (is_same_v<typename decltype(__day)::clock,
>> local_t>)
>> > - __d = __day - local_days(__ymd.year()/January/0);
>> > - else
>> > - __d = __day - sys_days(__ymd.year()/January/0);
>> > - return std::format_to(std::move(__out),
>> _GLIBCXX_WIDEN("{:03d}"),
>> > - __d.count());
>> > - }
>> > + if (_M_spec._M_time_only)
>> > + {
>> > + // Decimal number of days, without padding.
>> > + auto __d = chrono::floor<chrono::days>(__t._M_hours).count();
>> > + return std::format_to(std::move(__out), _S_empty_spec, __d);
>> > + }
>> > +
>> > + return std::format_to(std::move(__out),
>> _GLIBCXX_WIDEN("{:03d}"),
>> > + __t._M_day_of_year.count());
>> > }
>> >
>> > - template<typename _Tp, typename _FormatContext>
>> > + template<typename _FormatContext>
>> > typename _FormatContext::iterator
>> > - _M_m(const _Tp& __t, typename _FormatContext::iterator __out,
>> > + _M_m(chrono::month __m, typename _FormatContext::iterator __out,
>> > _FormatContext& __ctx, bool __mod) const
>> > {
>> > // %m month as a decimal number.
>> > // %Om Locale's alternative representation.
>> >
>> > - auto __m = _S_month(__t);
>> > auto __i = (unsigned)__m;
>> >
>> > if (__mod && _M_spec._M_localized) [[unlikely]] // %Om
>> > @@ -1294,15 +1431,14 @@ namespace __format
>> > return __format::__write(std::move(__out), _S_str_d2(__buf,
>> __i));
>> > }
>> >
>> > - template<typename _Tp, typename _FormatContext>
>> > + template<typename _FormatContext>
>> > typename _FormatContext::iterator
>> > - _M_M(const _Tp& __t, typename _FormatContext::iterator __out,
>> > + _M_M(chrono::minutes __m, typename _FormatContext::iterator __out,
>> > _FormatContext& __ctx, bool __mod) const
>> > {
>> > // %M The minute as a decimal number.
>> > // %OM Locale's alternative representation.
>> >
>> > - auto __m = _S_hms(__t).minutes();
>> > auto __i = __m.count();
>> >
>> > if (__mod && _M_spec._M_localized) [[unlikely]] // %OM
>> > @@ -1317,14 +1453,13 @@ namespace __format
>> > return __format::__write(std::move(__out), _S_two_digits(__i));
>> > }
>> >
>> > - template<typename _Tp, typename _FormatContext>
>> > + template<typename _FormatContext>
>> > typename _FormatContext::iterator
>> > - _M_p(const _Tp& __t, typename _FormatContext::iterator __out,
>> > + _M_p(chrono::hours __h, typename _FormatContext::iterator __out,
>> > _FormatContext& __ctx) const
>> > {
>> > // %p The locale's equivalent of the AM/PM designations.
>> > - auto __hms = _S_hms(__t);
>> > - auto __hi = __hms.hours().count();
>> > + auto __hi = __h.count();
>> > if (__hi >= 24) [[unlikely]]
>> > __hi %= 24;
>> >
>> > @@ -1335,35 +1470,34 @@ namespace __format
>> > return _M_write(std::move(__out), __loc, __ampm[__hi >= 12]);
>> > }
>> >
>> > - template<typename _Tp, typename _FormatContext>
>> > + template<typename _FormatContext>
>> > typename _FormatContext::iterator
>> > - _M_q(const _Tp&, typename _FormatContext::iterator __out,
>> > + _M_q(__string_view __us, typename _FormatContext::iterator __out,
>> > _FormatContext&) const
>> > {
>> > // %q The duration's unit suffix
>> > - if constexpr (!chrono::__is_duration_v<_Tp>)
>> > - __throw_format_error("format error: argument is not a
>> duration");
>> > - else
>> > - {
>> > - namespace __d = chrono::__detail;
>> > - using period = typename _Tp::period;
>> > - return __d::__fmt_units_suffix<period,
>> _CharT>(std::move(__out));
>> > - }
>> > + return __format::__write(std::move(__out), __us);
>> > }
>> >
>> > - // %Q handled in _M_format
>> > + template<typename _FormatContext>
>> > + typename _FormatContext::iterator
>> > + _M_Q(const _ChronoData<_CharT>& __t, typename
>> _FormatContext::iterator __out,
>> > + _FormatContext& __ctx) const
>> > + {
>> > + // %Q The duration's numeric value.
>> > + return std::vformat_to(std::move(__out), _S_empty_spec,
>> __t._M_ereps);
>> > + }
>> >
>> > - template<typename _Tp, typename _FormatContext>
>> > + template<typename _FormatContext>
>> > typename _FormatContext::iterator
>> > - _M_R_T(const _Tp& __t, typename _FormatContext::iterator __out,
>> > + _M_R_T(const _ChronoData<_CharT>& __t, typename
>> _FormatContext::iterator __out,
>> > _FormatContext& __ctx, bool __secs) const
>> > {
>> > // %R Equivalent to %H:%M
>> > // %T Equivalent to %H:%M:%S
>> > - auto __hms = _S_hms(__t);
>> > - auto __hi = __hms.hours().count();
>> > + auto __hi = __t._M_hours.count();
>> >
>> > - _CharT __buf[6];
>> > + _CharT __buf[6];
>> > __buf[2] = _S_colon;
>> > __buf[5] = _S_colon;
>> > __string_view __sv(__buf, 5 + __secs);
>> > @@ -1376,86 +1510,96 @@ namespace __format
>> > else
>> > _S_fill_two_digits(__buf, __hi);
>> >
>> > - _S_fill_two_digits(__buf + 3, __hms.minutes().count());
>> > + _S_fill_two_digits(__buf + 3, __t._M_minutes.count());
>> > __out = __format::__write(std::move(__out), __sv);
>> > if (__secs)
>> > - __out = _M_S(__hms, std::move(__out), __ctx);
>> > + __out = _M_S(__t, std::move(__out), __ctx);
>> > return __out;
>> > }
>> >
>> > - template<typename _Tp, typename _FormatContext>
>> > + template<typename _FormatContext>
>> > typename _FormatContext::iterator
>> > - _M_S(const _Tp& __t, typename _FormatContext::iterator __out,
>> > + _M_S(const _ChronoData<_CharT>& __t, typename
>> _FormatContext::iterator __out,
>> > _FormatContext& __ctx, bool __mod = false) const
>> > {
>> > // %S Seconds as a decimal number.
>> > // %OS The locale's alternative representation.
>> > - auto __hms = _S_hms(__t);
>> > - auto __s = __hms.seconds();
>> > + auto __s = __t._M_seconds;
>> >
>> > - if (__mod) [[unlikely]] // %OS
>> > - {
>> > - if (_M_spec._M_localized)
>> > - if (auto __loc = __ctx.locale(); __loc !=
>> locale::classic())
>> > - {
>> > - struct tm __tm{};
>> > - __tm.tm_sec = (int)__s.count();
>> > - return _M_locale_fmt(std::move(__out), __loc, __tm,
>> > - 'S', 'O');
>> > - }
>> > + if (__mod && _M_spec._M_localized) [[unlikely]] // %OS
>> > + if (auto __loc = __ctx.locale(); __loc != locale::classic())
>> > + {
>> > + struct tm __tm{};
>> > + __tm.tm_sec = (int)__s.count();
>> > + return _M_locale_fmt(std::move(__out), __loc, __tm,
>> > + 'S', 'O');
>> > + }
>> >
>> > - // %OS formats don't include subseconds, so just format
>> that:
>> > - return __format::__write(std::move(__out),
>> > - _S_two_digits(__s.count()));
>> > + __out = __format::__write(std::move(__out),
>> > + _S_two_digits(__s.count()));
>> > +
>> > + unsigned __prec = _M_spec._M_prec_kind != _WP_none
>> > + ? _M_spec._M_get_precision(__ctx)
>> > + : _M_spec._M_prec;
>> > +
>> > + // %OS formats don't include subseconds
>> > + if (__prec == 0 || __mod)
>> > + return __out;
>> > +
>> > + _CharT __dot = _S_dot;
>> > + if (_M_spec._M_localized)
>> > + if (auto __loc = __ctx.locale(); __loc != locale::classic())
>> > + {
>> > + const auto& __np = use_facet<numpunct<_CharT>>(__loc);
>> > + __dot = __np.decimal_point();
>> > }
>> > + *__out = __dot;
>> > + ++__out;
>> >
>> > - if constexpr (__hms.fractional_width == 0)
>> > - __out = __format::__write(std::move(__out),
>> > - _S_two_digits(__s.count()));
>> > - else
>> > + if (_M_spec._M_floating_point_rep)
>> > {
>> > - locale __loc = _M_locale(__ctx);
>> > - auto __ss = __hms.subseconds();
>> > - using rep = typename decltype(__ss)::rep;
>> > - if constexpr (is_floating_point_v<rep>)
>> > - {
>> > - chrono::duration<rep> __fs = __s + __ss;
>> > - __out = std::format_to(std::move(__out), __loc,
>> > - _GLIBCXX_WIDEN("{:#0{}.{}Lf}"),
>> > - __fs.count(),
>> > - 3 + __hms.fractional_width,
>> > - __hms.fractional_width);
>> > - }
>> > + _Str_sink<_CharT> __sink;
>> > + if (_M_spec._M_localized && _M_spec._M_custom_rep)
>> > + std::vformat_to(__sink.out(), _M_locale(__ctx),
>> > + _GLIBCXX_WIDEN("{1:0.{2}Lf}"),
>> __t._M_ereps);
>> > else
>> > - {
>> > - const auto& __np
>> > - = use_facet<numpunct<_CharT>>(__loc);
>> > - __out = __format::__write(std::move(__out),
>> > - _S_two_digits(__s.count()));
>> > - *__out++ = __np.decimal_point();
>> > - if constexpr (is_integral_v<rep>)
>> > - __out = std::format_to(std::move(__out),
>> > - _GLIBCXX_WIDEN("{:0{}}"),
>> > - __ss.count(),
>> > - __hms.fractional_width);
>> > - else
>> > - {
>> > - auto __str = std::format(_S_empty_spec,
>> __ss.count());
>> > - __out = std::format_to(std::move(__out),
>> > - _GLIBCXX_WIDEN("{:0>{}s}"),
>> > - __str,
>> > - __hms.fractional_width);
>> > - }
>> > - }
>> > + std::vformat_to(__sink.out(),
>> > + _GLIBCXX_WIDEN("{1:0.{2}f}"),
>> __t._M_ereps);
>> > +
>> > + auto __sv = __sink.view();
>> > + // Skip leading zero and dot
>> > + __sv.remove_prefix(2);
>> > + return __format::__write(std::move(__out), __sv);
>> > }
>> > - return __out;
>> > +
>> > + constexpr unsigned __max_prec =
>> _ChronoData<_CharT>::_S_max_prec;
>> > + constexpr typename _ChronoData<_CharT>::_Attoseconds::rep
>> __pow10t[]
>> > + {
>> > + 1u,
>> > + 10u, 100u, 1000u,
>> > + 10'000u, 100'000u, 1000'000u,
>> > + 10'000'000u, 100'000'000u,
>> 1000'000'000u,
>> > + 10'000'000'000u, 100'000'000'000u,
>> 1000'000'000'000u,
>> > + 10'000'000'000'000u, 100'000'000'000'000u,
>> 1000'000'000'000'000u,
>> > + 10'000'000'000'000'000u, 100'000'000'000'000'000u,
>> 1000'000'000'000'000'000u,
>> > + };
>> > +
>> > + auto __subs = __t._M_subseconds.count();
>> > + if (__prec < __max_prec)
>> > + __subs /= __pow10t[__max_prec - __prec];
>> > + else if (__prec > __max_prec)
>> > + __prec = __max_prec;
>> > +
>> > + using _FmtStr = _Runtime_format_string<_CharT>;
>> > + return std::format_to(__out,
>> _FmtStr(_GLIBCXX_WIDEN("{0:0{1}}")),
>> > + __subs, __prec);
>> > }
>> >
>> > // %t handled in _M_format
>> >
>> > - template<typename _Tp, typename _FormatContext>
>> > + template<typename _FormatContext>
>> > typename _FormatContext::iterator
>> > - _M_u_w(const _Tp& __t, typename _FormatContext::iterator __out,
>> > + _M_u_w(chrono::weekday __wd, typename _FormatContext::iterator
>> __out,
>> > _FormatContext& __ctx, _CharT __conv, bool __mod = false)
>> const
>> > {
>> > // %u ISO weekday as a decimal number (1-7), where Monday is 1.
>> > @@ -1463,8 +1607,6 @@ namespace __format
>> > // %w Weekday as a decimal number (0-6), where Sunday is 0.
>> > // %Ow Locale's alternative numeric rep.
>> >
>> > - chrono::weekday __wd = _S_weekday(__t);
>> > -
>> > if (__mod && _M_spec._M_localized) [[unlikely]]
>> > if (auto __loc = __ctx.locale(); __loc != locale::classic())
>> > {
>> > @@ -1480,9 +1622,9 @@ namespace __format
>> > return __format::__write(std::move(__out), _S_str_d1(__buf,
>> __wdi));
>> > }
>> >
>> > - template<typename _Tp, typename _FormatContext>
>> > + template<typename _FormatContext>
>> > typename _FormatContext::iterator
>> > - _M_U_V_W(const _Tp& __t, typename _FormatContext::iterator __out,
>> > + _M_U_V_W(const _ChronoData<_CharT>& __t, typename
>> _FormatContext::iterator __out,
>> > _FormatContext& __ctx, _CharT __conv, bool __mod =
>> false) const
>> > {
>> > // %U Week number of the year as a decimal number, from first
>> Sunday.
>> > @@ -1492,126 +1634,68 @@ namespace __format
>> > // %W Week number of the year as a decimal number, from first
>> Monday.
>> > // %OW Locale's alternative numeric rep.
>> > using namespace chrono;
>> > - auto __d = _S_days(__t);
>> > - using _TDays = decltype(__d); // Either sys_days or local_days.
>> >
>> > if (__mod && _M_spec._M_localized) [[unlikely]]
>> > if (auto __loc = __ctx.locale(); __loc != locale::classic())
>> > {
>> > - const year_month_day __ymd(__d);
>> > - const year __y = __ymd.year();
>> > struct tm __tm{};
>> > - __tm.tm_year = (int)__y - 1900;
>> > - __tm.tm_yday = (__d - _TDays(__y/January/1)).count();
>> > - __tm.tm_wday = weekday(__d).c_encoding();
>> > + __tm.tm_year = (int)__t._M_year - 1900;
>> > + __tm.tm_yday = __t._M_day_of_year.count();
>> > + __tm.tm_wday = __t._M_weekday.c_encoding();
>> > return _M_locale_fmt(std::move(__out), __loc, __tm,
>> > (char)__conv, 'O');
>> > }
>> >
>> > - _TDays __first; // First day of week 1.
>> > + auto __d = __t._M_ldays;
>> > + local_days __first; // First day of week 1.
>> > if (__conv == 'V') // W01 begins on Monday before first
>> Thursday.
>> > {
>> > // Move to nearest Thursday:
>> > - __d -= (weekday(__d) - Monday) - days(3);
>> > + __d -= (__t._M_weekday - Monday) - days(3);
>> > // ISO week of __t is number of weeks since January 1 of the
>> > // same year as that nearest Thursday.
>> > - __first = _TDays(year_month_day(__d).year()/January/1);
>> > + __first = local_days(year_month_day(__d).year()/January/1);
>> > }
>> > else
>> > {
>> > - year __y;
>> > - if constexpr (requires { __t.year(); })
>> > - __y = __t.year();
>> > - else
>> > - __y = year_month_day(__d).year();
>> > const weekday __weekstart = __conv == 'U' ? Sunday : Monday;
>> > - __first = _TDays(__y/January/__weekstart[1]);
>> > + __first = local_days(__t._M_year/January/__weekstart[1]);
>> > }
>> > auto __weeks = chrono::floor<weeks>(__d - __first);
>> > __string_view __sv = _S_two_digits(__weeks.count() + 1);
>> > return __format::__write(std::move(__out), __sv);
>> > }
>> >
>> > - template<typename _Tp, typename _FormatContext>
>> > + template<typename _FormatContext>
>> > typename _FormatContext::iterator
>> > - _M_z(const _Tp& __t, typename _FormatContext::iterator __out,
>> > + _M_z(chrono::seconds __ts, typename _FormatContext::iterator
>> __out,
>> > _FormatContext&, bool __mod = false) const
>> > {
>> > - using ::std::chrono::__detail::__utc_leap_second;
>> > - using ::std::chrono::__detail::__local_time_fmt;
>> > -
>> > - auto __utc = __mod ? __string_view(_GLIBCXX_WIDEN("+00:00"), 6)
>> > - : __string_view(_GLIBCXX_WIDEN("+0000"), 5);
>> > -
>> > - if constexpr (chrono::__is_time_point_v<_Tp>)
>> > + if (__ts == 0s)
>> > {
>> > - if constexpr (is_same_v<typename _Tp::clock,
>> > - chrono::system_clock>)
>> > - return __format::__write(std::move(__out), __utc);
>> > - }
>> > - else if constexpr (__is_specialization_of<_Tp,
>> __local_time_fmt>)
>> > - {
>> > - if (__t._M_offset_sec)
>> > - {
>> > - auto __sv = __utc;
>> > - basic_string<_CharT> __s;
>> > - if (*__t._M_offset_sec != 0s)
>> > - {
>> > - chrono:: hh_mm_ss __hms(*__t._M_offset_sec);
>> > - __s = _S_plus_minus[__hms.is_negative()];
>> > - __s += _S_two_digits(__hms.hours().count());
>> > - if (__mod)
>> > - __s += _S_colon;
>> > - __s += _S_two_digits(__hms.minutes().count());
>> > - __sv = __s;
>> > - }
>> > - return __format::__write(std::move(__out), __sv);
>> > - }
>> > + __string_view __zero
>> > + = __mod ? _GLIBCXX_WIDEN("+00:00") :
>> _GLIBCXX_WIDEN("+0000");
>> > + return __format::__write(std::move(__out), __zero);
>> > }
>> > - else if constexpr (__is_specialization_of<_Tp,
>> __utc_leap_second>)
>> > - return __format::__write(std::move(__out), __utc);
>> >
>> > - __no_timezone_available();
>> > + chrono::hh_mm_ss<chrono::seconds> __hms(__ts);
>> > + unsigned __mo = 3 + __mod;
>> > +
>> > + _CharT __buf[6];
>> > + __buf[0] = _S_plus_minus[__hms.is_negative()];
>> > + __buf[3] = _S_colon;
>> > + _S_fill_two_digits(__buf + 1, __hms.hours().count());
>> > + _S_fill_two_digits(__buf + __mo, __hms.minutes().count());
>> > +
>> > + __string_view __sv(__buf, __mo + 2);
>> > + return __format::__write(std::move(__out), __sv);
>> > }
>> >
>> > - template<typename _Tp, typename _FormatContext>
>> > + template<typename _FormatContext>
>> > typename _FormatContext::iterator
>> > - _M_Z(const _Tp& __t, typename _FormatContext::iterator __out,
>> > + _M_Z(__string_view __abbrev, typename _FormatContext::iterator
>> __out,
>> > _FormatContext& __ctx) const
>> > - {
>> > - using ::std::chrono::__detail::__utc_leap_second;
>> > - using ::std::chrono::__detail::__local_time_fmt;
>> > -
>> > - __string_view __utc(_GLIBCXX_WIDEN("UTC"), 3);
>> > - if constexpr (chrono::__is_time_point_v<_Tp>)
>> > - {
>> > - if constexpr (is_same_v<typename _Tp::clock,
>> > - chrono::system_clock>)
>> > - return __format::__write(std::move(__out), __utc);
>> > - }
>> > - else if constexpr (__is_specialization_of<_Tp,
>> __local_time_fmt>)
>> > - {
>> > - if (__t._M_abbrev)
>> > - {
>> > - string_view __sv = *__t._M_abbrev;
>> > - if constexpr (is_same_v<_CharT, char>)
>> > - return __format::__write(std::move(__out), __sv);
>> > - else
>> > - {
>> > - // TODO use resize_and_overwrite
>> > - basic_string<_CharT> __ws(__sv.size(), _CharT());
>> > - auto& __ct =
>> use_facet<ctype<_CharT>>(_M_locale(__ctx));
>> > - __ct.widen(__sv.begin(), __sv.end(), __ws.data());
>> > - __string_view __wsv = __ws;
>> > - return __format::__write(std::move(__out), __wsv);
>> > - }
>> > - }
>> > - }
>> > - else if constexpr (__is_specialization_of<_Tp,
>> __utc_leap_second>)
>> > - return __format::__write(std::move(__out), __utc);
>> > -
>> > - __no_timezone_available();
>> > - }
>> > + { return __format::__write(std::move(__out), __abbrev); }
>> >
>> > // %% handled in _M_format
>> >
>> > @@ -1670,194 +1754,202 @@ namespace __format
>> > return _S_two_digits(__n);
>> >
>> > _S_fill_two_digits(__buf.data(), __n / 10);
>> > - __buf[2] = _S_digit(__n % 10)[0];
>> > + __buf[2] = _S_chars[__n % 10];
>> > return __string_view(__buf.data(), 3);
>> > }
>> >
>> > - // Accessors for the components of chrono types:
>> > + // Use the formatting locale's std::time_put facet to produce
>> > + // a locale-specific representation.
>> > + template<typename _Iter>
>> > + _Iter
>> > + _M_locale_fmt(_Iter __out, const locale& __loc, const struct tm&
>> __tm,
>> > + char __fmt, char __mod) const
>> > + {
>> > + basic_ostringstream<_CharT> __os;
>> > + __os.imbue(__loc);
>> > + const auto& __tp = use_facet<time_put<_CharT>>(__loc);
>> > + __tp.put(__os, __os, _S_space, &__tm, __fmt, __mod);
>> > + if (__os)
>> > + __out = _M_write(std::move(__out), __loc, __os.view());
>> > + return __out;
>> > + }
>> > + };
>> >
>> > - // Returns a hh_mm_ss.
>> > - template<typename _Tp>
>> > - static decltype(auto)
>> > - _S_hms(const _Tp& __t)
>> > + template<typename _CharT>
>> > + struct __formatter_duration : private __formatter_chrono<_CharT>
>> > + {
>> > + template<typename _Rep, typename _Period>
>> > + constexpr static auto
>> > + _S_subseconds(const chrono::duration<_Rep, _Period>& __d)
>> > {
>> > - using ::std::chrono::__detail::__utc_leap_second;
>> > - using ::std::chrono::__detail::__local_time_fmt;
>> > -
>> > - if constexpr (__is_specialization_of<_Tp, chrono::hh_mm_ss>)
>> > - return __t;
>> > - else if constexpr (__is_specialization_of<_Tp,
>> __utc_leap_second>)
>> > - return __t._M_time;
>> > - else if constexpr (chrono::__is_duration_v<_Tp>)
>> > - return chrono::hh_mm_ss<_Tp>(__t);
>> > - else if constexpr (chrono::__is_time_point_v<_Tp>)
>> > - return chrono::hh_mm_ss(__t -
>> chrono::floor<chrono::days>(__t));
>> > - else if constexpr (__is_specialization_of<_Tp,
>> __local_time_fmt>)
>> > - return _S_hms(__t._M_time);
>> > + if constexpr (chrono::treat_as_floating_point_v<_Rep>)
>> > + return chrono::duration<_Rep>(__d);
>> > + else if constexpr (_Period::den == 1)
>> > + return chrono::seconds(0);
>> > else
>> > - {
>> > - __invalid_chrono_spec();
>> > - return chrono::hh_mm_ss<chrono::seconds>();
>> > - }
>> > - }
>> > + {
>> > + using _Attoseconds = _ChronoData<_CharT>::_Attoseconds;
>> > + using _CRep = common_type_t<_Rep, typename
>> _Attoseconds::rep>;
>> > + chrono::duration<_CRep, _Period> subs(__d.count());
>> > + return chrono::duration_cast<_Attoseconds>(subs);
>> > + }
>> > + }
>> >
>> > - // Returns a sys_days or local_days.
>> > - template<typename _Tp>
>> > - static auto
>> > - _S_days(const _Tp& __t)
>> > + public:
>> > + template<typename _Duration>
>> > + static consteval
>> > + _ChronoSpec<_CharT>
>> > + _S_spec_for(_ChronoParts __parts)
>> > {
>> > - using namespace chrono;
>> > - using ::std::chrono::__detail::__utc_leap_second;
>> > - using ::std::chrono::__detail::__local_time_fmt;
>> > -
>> > - if constexpr (__is_time_point_v<_Tp>)
>> > - return chrono::floor<days>(__t);
>> > - else if constexpr (__is_specialization_of<_Tp,
>> __utc_leap_second>)
>> > - return __t._M_date;
>> > - else if constexpr (__is_specialization_of<_Tp,
>> __local_time_fmt>)
>> > - return chrono::floor<days>(__t._M_time);
>> > - else if constexpr (is_same_v<_Tp, year_month_day>
>> > - || is_same_v<_Tp, year_month_day_last>
>> > - || is_same_v<_Tp, year_month_weekday>
>> > - || is_same_v<_Tp, year_month_weekday_last>)
>> > - return sys_days(__t);
>> > - else
>> > + using _Rep = typename _Duration::rep;
>> > + using enum _ChronoParts;
>> > +
>> > + _ChronoSpec<_CharT> __res{};
>> > + __res._M_time_only = (__parts & _Date) == 0;
>> > + __res._M_floating_point_rep =
>> chrono::treat_as_floating_point_v<_Rep>;
>> > + __res._M_custom_rep = !is_arithmetic_v<_Rep>;
>> > + __res._M_prec = chrono::hh_mm_ss<_Duration>::fractional_width;
>> > + if ((__parts & _TimeOfDay) != 0)
>> > + __res._M_localized = __res._M_prec > 0 ||
>> __res._M_floating_point_rep;
>> > +
>> > + if ((__parts & _TimeOfDay) != 0)
>> > + __res._M_needed |= _TimeOfDay;
>> > + if ((__parts & _Date) != 0)
>> > + __res._M_needed |= _YearMonthDay;
>> > + if ((__parts & _ZoneAbbrev) != 0)
>> > + __res._M_needed |= _ZoneAbbrev;
>> > +
>> > + switch (__parts)
>> > {
>> > - if constexpr (__is_duration_v<_Tp>)
>> > - __not_valid_for_duration();
>> > - else
>> > - __invalid_chrono_spec();
>> > - return chrono::sys_days();
>> > + case _ZonedDateTime:
>> > + __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_ftz();
>> > + break;
>> > + case _DateTime:
>> > + __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_ft();
>> > + break;
>> > + case _Date:
>> > + __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_f();
>> > + break;
>> > + case _Time:
>> > + __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_t();
>> > + break;
>> > + case _None:
>> > + break;
>> > }
>> > - }
>> > + return __res;
>> > + };
>> >
>> > - // Returns a year_month_day.
>> > - template<typename _Tp>
>> > - static chrono::year_month_day
>> > - _S_date(const _Tp& __t)
>> > - {
>> > - if constexpr (is_same_v<_Tp, chrono::year_month_day>)
>> > - return __t;
>> > - else
>> > - return chrono::year_month_day(_S_days(__t));
>> > - }
>> > + using __formatter_chrono<_CharT>::__formatter_chrono;
>> > + using __formatter_chrono<_CharT>::_M_locale;
>> > + using __formatter_chrono<_CharT>::_M_spec;
>> >
>> > - template<typename _Tp>
>> > - static chrono::day
>> > - _S_day(const _Tp& __t)
>> > + template<typename _Duration, typename _ParseContext>
>> > + constexpr typename _ParseContext::iterator
>> > + _M_parse(_ParseContext& __pc, _ChronoParts __parts,
>> > + const _ChronoSpec<_CharT>& __def = {})
>> > {
>> > - using namespace chrono;
>> > -
>> > - if constexpr (is_same_v<_Tp, day>)
>> > - return __t;
>> > - else if constexpr (requires { __t.day(); })
>> > - return __t.day();
>> > - else
>> > - return _S_date(__t).day();
>> > + using _Rep = typename _Duration::rep;
>> > + using enum _ChronoParts;
>> > +
>> > + auto __res
>> > + = __formatter_chrono<_CharT>::_M_parse(__pc, __parts, __def);
>> > + // check for custom floating point durations, if digits of
>> output
>> > + // will contain subseconds, then formatters must support
>> specifying
>> > + // precision.
>> > + if constexpr (!is_floating_point_v<_Rep>)
>> > + if constexpr (chrono::treat_as_floating_point_v<_Rep>)
>> > + if (_M_spec._M_needs(_Subseconds|_EpochUnits)
>> > + || _M_spec._M_prec_kind != _WP_none
>> > + || _M_spec._M_prec_value > 0)
>> > + {
>> > + constexpr const _CharT* __fs =
>> _GLIBCXX_WIDEN("#02.5Lf");
>> > + basic_format_parse_context<_CharT> __npc(__fs);
>> > + formatter<_Rep, _CharT> __fmtter;
>> > + __fmtter.parse(__npc);
>> > + }
>> > + return __res;
>> > }
>> >
>> > - template<typename _Tp>
>> > - static chrono::month
>> > - _S_month(const _Tp& __t)
>> > + // Format duration for empty chrono-specs, e.g. "{}" (C++20
>> [time.format] p6).
>> > + template<typename _Rep, typename _Period, typename
>> _FormatContext>
>> > + typename _FormatContext::iterator
>> > + _M_format_to_ostream(const chrono::duration<_Rep, _Period>& __d,
>> > + bool __is_neg,
>> > + _FormatContext& __fc) const
>> > {
>> > - using namespace chrono;
>> > + basic_ostringstream<_CharT> __os;
>> > + __os.imbue(this->_M_locale(__fc));
>> >
>> > - if constexpr (is_same_v<_Tp, month>)
>> > - return __t;
>> > - else if constexpr (requires { __t.month(); })
>> > - return __t.month();
>> > - else
>> > - return _S_date(__t).month();
>> > + if (__is_neg) [[unlikely]]
>> > + __os << this->_S_plus_minus[1];
>> > + __os << __d;
>> > +
>> > + auto __str = std::move(__os).str();
>> > + return __format::__write_padded_as_spec(__str, __str.size(),
>> > + __fc, _M_spec);
>> > }
>> >
>> > - template<typename _Tp>
>> > - static chrono::year
>> > - _S_year(const _Tp& __t)
>> > + template<typename _Rep1, typename _Period1,
>> > + typename _Rep2, typename _Period2,
>> > + typename _FormatContext>
>> > + typename _FormatContext::iterator
>> > + _M_format_units(_ChronoData<_CharT>& __cd,
>> > + const chrono::duration<_Rep1, _Period1>& __ed,
>> > + const chrono::duration<_Rep2, _Period2>& __ss,
>> > + _FormatContext& __fc) const
>> > {
>> > - using namespace chrono;
>> > + __format::_Str_sink<_CharT> __suffix_store;
>> > + constexpr auto _S_unit_suffix
>> > + = chrono::__detail::__units_suffix<_Period1, _CharT>();
>> > + if constexpr (!_S_unit_suffix.empty())
>> > + __cd._M_unit_suffix = _S_unit_suffix;
>> > + else if (_M_spec._M_needs(_ChronoParts::_UnitSuffix))
>> > + {
>> > + chrono::__detail::
>> > + __fmt_units_suffix<_Period1,
>> _CharT>(__suffix_store.out());
>> > + __cd._M_unit_suffix = __suffix_store.view();
>> > + }
>> >
>> > - if constexpr (is_same_v<_Tp, year>)
>> > - return __t;
>> > - else if constexpr (requires { __t.year(); })
>> > - return __t.year();
>> > - else
>> > - return _S_date(__t).year();
>> > - }
>> > + const auto __prec = _M_spec._M_prec_kind != _WP_none
>> > + ? _M_spec._M_get_precision(__fc)
>> > + : _M_spec._M_prec;
>> >
>> > - template<typename _Tp>
>> > - static chrono::weekday
>> > - _S_weekday(const _Tp& __t)
>> > - {
>> > - using namespace ::std::chrono;
>> > - using ::std::chrono::__detail::__local_time_fmt;
>> > -
>> > - if constexpr (is_same_v<_Tp, weekday>)
>> > - return __t;
>> > - else if constexpr (requires { __t.weekday(); })
>> > - return __t.weekday();
>> > - else if constexpr (is_same_v<_Tp, month_weekday>)
>> > - return __t.weekday_indexed().weekday();
>> > - else if constexpr (is_same_v<_Tp, month_weekday_last>)
>> > - return __t.weekday_last().weekday();
>> > - else
>> > - return weekday(_S_days(__t));
>> > - }
>> > + using _ErasedContext = typename
>> _ChronoData<_CharT>::_FormatContext;
>> > + // _GLIBCXX_RESOLVE_LIB_DEFECTS
>> > + // 4118. How should duration formatters format custom rep?
>> > + auto __ereps = +__ed.count();
>> > + if (!_M_spec._M_needs(_ChronoParts::_Subseconds))
>> > + {
>> > + auto __ssreps = 0u;
>> > + auto __args_store
>> > + = std::make_format_args<_ErasedContext>(__ereps, __ssreps,
>> __prec);
>> > + __cd._M_ereps = __args_store;
>> > + return this->_M_format(__cd, __fc);
>> > + }
>> >
>> > - template<typename _Tp>
>> > - static unsigned
>> > - _S_weekday_index(const _Tp& __t)
>> > - {
>> > - using namespace ::std::chrono;
>> > + using _Attoseconds = _ChronoData<_CharT>::_Attoseconds;
>> > + auto __nss = _S_subseconds(__ss);
>> > + __cd._M_subseconds = chrono::duration_cast<_Attoseconds>(__nss);
>> >
>> > - if constexpr (is_same_v<_Tp, weekday_indexed>)
>> > - return __t.index();
>> > - else if constexpr (requires { __t.weekday_indexed(); })
>> > - return __t.weekday_indexed().index();
>> > - else
>> > - return ((unsigned)_S_day(__t) + 6) / 7;
>> > - }
>> > + auto __ssreps = __nss.count();
>> > + auto __args_store
>> > + = std::make_format_args<_ErasedContext>(__ereps, __ssreps,
>> __prec);
>> > + __cd._M_ereps = __args_store;
>> >
>> > - // Remove subsecond precision from a time_point.
>> > - template<typename _Tp>
>> > - static auto
>> > - _S_floor_seconds(const _Tp& __t)
>> > - {
>> > - using chrono::__detail::__local_time_fmt;
>> > - if constexpr (chrono::__is_time_point_v<_Tp>
>> > - || chrono::__is_duration_v<_Tp>)
>> > - {
>> > - if constexpr (_Tp::period::den != 1)
>> > - return chrono::floor<chrono::seconds>(__t);
>> > - else
>> > - return __t;
>> > - }
>> > - else if constexpr (__is_specialization_of<_Tp,
>> chrono::hh_mm_ss>)
>> > - {
>> > - if constexpr (_Tp::fractional_width != 0)
>> > - return chrono::floor<chrono::seconds>(__t.to_duration());
>> > - else
>> > - return __t;
>> > - }
>> > - else if constexpr (__is_specialization_of<_Tp,
>> __local_time_fmt>)
>> > - return _S_floor_seconds(__t._M_time);
>> > - else
>> > - return __t;
>> > + return this->_M_format(__cd, __fc);
>> > }
>> >
>> > - // Use the formatting locale's std::time_put facet to produce
>> > - // a locale-specific representation.
>> > - template<typename _Iter>
>> > - _Iter
>> > - _M_locale_fmt(_Iter __out, const locale& __loc, const struct tm&
>> __tm,
>> > - char __fmt, char __mod) const
>> > + // pre: __cd._M_lseconds and __cd._M_eseconds are set.
>> > + template<typename _Rep1, typename _Period1, typename
>> _FormatContext>
>> > + typename _FormatContext::iterator
>> > + _M_format_time_point(_ChronoData<_CharT>& __cd,
>> > + const chrono::duration<_Rep1, _Period1>&
>> __ed,
>> > + _FormatContext& __fc) const
>> > {
>> > - basic_ostringstream<_CharT> __os;
>> > - __os.imbue(__loc);
>> > - const auto& __tp = use_facet<time_put<_CharT>>(__loc);
>> > - __tp.put(__os, __os, _S_space, &__tm, __fmt, __mod);
>> > - if (__os)
>> > - __out = _M_write(std::move(__out), __loc, __os.view());
>> > - return __out;
>> > + auto __parts = _M_spec._M_needed - _ChronoParts::_TotalSeconds;
>> > + if ((__parts & _ChronoParts::_DateTime) != 0)
>> > + __cd._M_fill_date_time(__cd._M_lseconds, __parts);
>> > + return _M_format_units(__cd, __ed, __ed - __cd._M_eseconds,
>> __fc);
>> > }
>> > };
>> >
>> > @@ -1877,7 +1969,7 @@ namespace __format
>> > // n.b. only acceptable chrono-spec for info is one containing
>> > // only whitespaces and %%, that do not depend on formatted
>> object.
>> > if (!_M_f._M_spec._M_chrono_specs.empty()) [[unlikely]]
>> > - return _M_f._M_format(chrono::day(1), __fc);
>> > + return _M_f._M_format(_ChronoData<_CharT>{}, __fc);
>> >
>> > const size_t __padwidth = _M_f._M_spec._M_get_width(__fc);
>> > if (__padwidth == 0)
>> > @@ -1949,12 +2041,8 @@ namespace __format
>> > constexpr typename basic_format_parse_context<_CharT>::iterator
>> > parse(basic_format_parse_context<_CharT>& __pc)
>> > {
>> > - using namespace __format;
>> > - auto __it = _M_f._M_parse(__pc, _Duration|_TimeOfDay, __defSpec);
>> > - if constexpr (!is_floating_point_v<_Rep>)
>> > - if (_M_f._M_spec._M_prec_kind != __format::_WP_none)
>> > - __throw_format_error("format error: invalid precision for
>> duration");
>> > - return __it;
>> > + using enum __format::_ChronoParts;
>> > + return _M_f.template _M_parse<_Duration>(__pc, _EpochTime,
>> __defSpec);
>> > }
>> >
>> > template<typename _Out>
>> > @@ -1981,12 +2069,20 @@ namespace __format
>> > }
>> >
>> > private:
>> > + using _Duration = chrono::duration<_Rep, _Period>;
>> > +
>> > static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
>> > {
>> > - __format::_ChronoSpec<_CharT> __res{};
>> > + using enum __format::_ChronoParts;
>> > + auto __res = __format::__formatter_duration<_CharT>::
>> > + template _S_spec_for<_Duration>(_None);
>> > __res._M_localized = !is_integral_v<_Rep>;
>> > + // n.b. for integral format output is the same as ostream output
>> > if constexpr (is_integral_v<_Rep>)
>> > - __res._M_chrono_specs = _GLIBCXX_WIDEN("%Q%q");
>> > + {
>> > + __res._M_needed = _EpochUnits|_UnitSuffix;
>> > + __res._M_chrono_specs = _GLIBCXX_WIDEN("%Q%q");
>> > + }
>> > return __res;
>> > }();
>> >
>> > @@ -1996,13 +2092,22 @@ namespace __format
>> > bool __is_neg,
>> > basic_format_context<_Out, _CharT>& __fc) const
>> > {
>> > + using namespace chrono;
>> > + using enum __format::_ChronoParts;
>> > if constexpr (!is_integral_v<_Rep>)
>> > if (_M_f._M_spec._M_chrono_specs.empty())
>> > return _M_f._M_format_to_ostream(__d, __is_neg, __fc);
>> > - return _M_f._M_format(__d, __fc, __is_neg);
>> > +
>> > + __format::_ChronoData<_CharT> __cd;
>> > + __cd._M_is_neg = __is_neg;
>> > + auto __ts = chrono::floor<chrono::seconds>(__d);
>> > + __cd._M_eseconds = __ts;
>> > + if (_M_f._M_spec._M_needs(_HoursMinutesSeconds))
>> > + __cd._M_fill_time(__ts);
>> > + return _M_f._M_format_units(__cd, __d, __d - __ts, __fc);
>> > }
>> >
>> > - __format::__formatter_chrono<_CharT> _M_f{__defSpec};
>> > + __format::__formatter_duration<_CharT> _M_f{__defSpec};
>> > };
>> >
>> > template<__format::__char _CharT>
>> > @@ -2010,20 +2115,31 @@ namespace __format
>> > {
>> > constexpr typename basic_format_parse_context<_CharT>::iterator
>> > parse(basic_format_parse_context<_CharT>& __pc)
>> > - { return _M_f._M_parse(__pc, __format::_Day, __defSpec); }
>> > + {
>> > + using enum __format::_ChronoParts;
>> > + return _M_f._M_parse(__pc, _Day|_WeekdayIndex, __defSpec);
>> > + }
>> >
>> > template<typename _Out>
>> > typename basic_format_context<_Out, _CharT>::iterator
>> > format(const chrono::day& __t,
>> > basic_format_context<_Out, _CharT>& __fc) const
>> > - { return _M_f._M_format(__t, __fc); }
>> > + {
>> > + __format::_ChronoData<_CharT> __cd{};
>> > + __cd._M_fill_day(__t, __defSpec._M_needed);
>> > + return _M_f._M_format(__cd, __fc);
>> > + }
>> >
>> > private:
>> > static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
>> > {
>> > + using __format::_ChronoFormats;
>> > + using enum __format::_ChronoParts;
>> > +
>> > __format::_ChronoSpec<_CharT> __res{};
>> > __res._M_debug = true;
>> > - __res._M_chrono_specs =
>> __format::_ChronoFormats<_CharT>::_S_d();
>> > + __res._M_needed = _Day;
>> > + __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_d();
>> > return __res;
>> > }();
>> >
>> > @@ -2035,22 +2151,33 @@ namespace __format
>> > {
>> > constexpr typename basic_format_parse_context<_CharT>::iterator
>> > parse(basic_format_parse_context<_CharT>& __pc)
>> > - { return _M_f._M_parse(__pc, __format::_Month, __defSpec); }
>> > + {
>> > + using enum __format::_ChronoParts;
>> > + return _M_f._M_parse(__pc, _Month, __defSpec);
>> > + }
>> >
>> > template<typename _Out>
>> > typename basic_format_context<_Out, _CharT>::iterator
>> > format(const chrono::month& __t,
>> > basic_format_context<_Out, _CharT>& __fc) const
>> > - { return _M_f._M_format(__t, __fc); }
>> > + {
>> > + __format::_ChronoData<_CharT> __cd{};
>> > + __cd._M_month = __t;
>> > + return _M_f._M_format(__cd, __fc);
>> > + }
>> >
>> > private:
>> > static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
>> > {
>> > + using __format::_ChronoFormats;
>> > + using enum __format::_ChronoParts;
>> > +
>> > __format::_ChronoSpec<_CharT> __res{};
>> > __res._M_debug = true;
>> > __res._M_localized = true;
>> > __res._M_locale_specific = true;
>> > - __res._M_chrono_specs =
>> __format::_ChronoFormats<_CharT>::_S_m();
>> > + __res._M_needed = _Month;
>> > + __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_m();
>> > return __res;
>> > }();
>> >
>> > @@ -2062,20 +2189,31 @@ namespace __format
>> > {
>> > constexpr typename basic_format_parse_context<_CharT>::iterator
>> > parse(basic_format_parse_context<_CharT>& __pc)
>> > - { return _M_f._M_parse(__pc, __format::_Year, __defSpec); }
>> > + {
>> > + using enum __format::_ChronoParts;
>> > + return _M_f._M_parse(__pc, _Year, __defSpec);
>> > + }
>> >
>> > template<typename _Out>
>> > typename basic_format_context<_Out, _CharT>::iterator
>> > format(const chrono::year& __t,
>> > basic_format_context<_Out, _CharT>& __fc) const
>> > - { return _M_f._M_format(__t, __fc); }
>> > + {
>> > + __format::_ChronoData<_CharT> __cd{};
>> > + __cd._M_year = __t;
>> > + return _M_f._M_format(__cd, __fc);
>> > + }
>> >
>> > private:
>> > static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
>> > {
>> > + using __format::_ChronoFormats;
>> > + using enum __format::_ChronoParts;
>> > +
>> > __format::_ChronoSpec<_CharT> __res{};
>> > __res._M_debug = true;
>> > - __res._M_chrono_specs =
>> __format::_ChronoFormats<_CharT>::_S_y();
>> > + __res._M_needed = _Year;
>> > + __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_y();
>> > return __res;
>> > }();
>> >
>> > @@ -2087,22 +2225,33 @@ namespace __format
>> > {
>> > constexpr typename basic_format_parse_context<_CharT>::iterator
>> > parse(basic_format_parse_context<_CharT>& __pc)
>> > - { return _M_f._M_parse(__pc, __format::_Weekday, __defSpec); }
>> > + {
>> > + using enum __format::_ChronoParts;
>> > + return _M_f._M_parse(__pc, _Weekday, __defSpec);
>> > + }
>> >
>> > template<typename _Out>
>> > typename basic_format_context<_Out, _CharT>::iterator
>> > format(const chrono::weekday& __t,
>> > basic_format_context<_Out, _CharT>& __fc) const
>> > - { return _M_f._M_format(__t, __fc); }
>> > + {
>> > + __format::_ChronoData<_CharT> __cd{};
>> > + __cd._M_weekday = __t;
>> > + return _M_f._M_format(__cd, __fc);
>> > + }
>> >
>> > private:
>> > static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
>> > {
>> > + using __format::_ChronoFormats;
>> > + using enum __format::_ChronoParts;
>> > +
>> > __format::_ChronoSpec<_CharT> __res{};
>> > __res._M_debug = true;
>> > __res._M_localized = true;
>> > __res._M_locale_specific = true;
>> > - __res._M_chrono_specs =
>> __format::_ChronoFormats<_CharT>::_S_w();
>> > + __res._M_needed = _Weekday;
>> > + __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_w();
>> > return __res;
>> > }();
>> >
>> > @@ -2114,22 +2263,33 @@ namespace __format
>> > {
>> > constexpr typename basic_format_parse_context<_CharT>::iterator
>> > parse(basic_format_parse_context<_CharT>& __pc)
>> > - { return _M_f._M_parse(__pc, __format::_Weekday, __defSpec); }
>> > + {
>> > + using enum __format::_ChronoParts;
>> > + return _M_f._M_parse(__pc, _IndexedWeekday, __defSpec);
>> > + }
>> >
>> > template<typename _Out>
>> > typename basic_format_context<_Out, _CharT>::iterator
>> > format(const chrono::weekday_indexed& __t,
>> > basic_format_context<_Out, _CharT>& __fc) const
>> > - { return _M_f._M_format(__t, __fc); }
>> > + {
>> > + __format::_ChronoData<_CharT> __cd{};
>> > + __cd._M_fill_weekday(__t, __defSpec._M_needed);
>> > + return _M_f._M_format(__cd, __fc);
>> > + }
>> >
>> > private:
>> > static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
>> > {
>> > + using __format::_ChronoFormats;
>> > + using enum __format::_ChronoParts;
>> > +
>> > __format::_ChronoSpec<_CharT> __res{};
>> > __res._M_debug = true;
>> > __res._M_localized = true;
>> > __res._M_locale_specific = true;
>> > - __res._M_chrono_specs =
>> __format::_ChronoFormats<_CharT>::_S_wi();
>> > + __res._M_needed = _IndexedWeekday;
>> > + __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_wi();
>> > return __res;
>> > }();
>> >
>> > @@ -2141,22 +2301,33 @@ namespace __format
>> > {
>> > constexpr typename basic_format_parse_context<_CharT>::iterator
>> > parse(basic_format_parse_context<_CharT>& __pc)
>> > - { return _M_f._M_parse(__pc, __format::_Weekday, __defSpec); }
>> > + {
>> > + using enum __format::_ChronoParts;
>> > + return _M_f._M_parse(__pc, _Weekday, __defSpec);
>> > + }
>> >
>> > template<typename _Out>
>> > typename basic_format_context<_Out, _CharT>::iterator
>> > format(const chrono::weekday_last& __t,
>> > basic_format_context<_Out, _CharT>& __fc) const
>> > - { return _M_f._M_format(__t, __fc); }
>> > + {
>> > + __format::_ChronoData<_CharT> __cd{};
>> > + __cd._M_weekday = __t.weekday();
>> > + return _M_f._M_format(__cd, __fc);
>> > + }
>> >
>> > private:
>> > static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
>> > {
>> > + using __format::_ChronoFormats;
>> > + using enum __format::_ChronoParts;
>> > +
>> > __format::_ChronoSpec<_CharT> __res{};
>> > __res._M_debug = true;
>> > __res._M_localized = true;
>> > __res._M_locale_specific = true;
>> > - __res._M_chrono_specs =
>> __format::_ChronoFormats<_CharT>::_S_wl();
>> > + __res._M_needed = _Weekday;
>> > + __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_wl();
>> > return __res;
>> > }();
>> >
>> > @@ -2169,24 +2340,33 @@ namespace __format
>> > constexpr typename basic_format_parse_context<_CharT>::iterator
>> > parse(basic_format_parse_context<_CharT>& __pc)
>> > {
>> > - return _M_f._M_parse(__pc, __format::_Month|__format::_Day,
>> > - __defSpec);
>> > + using enum __format::_ChronoParts;
>> > + return _M_f._M_parse(__pc, _Month|_Day|_WeekdayIndex, __defSpec);
>> > }
>> >
>> > template<typename _Out>
>> > typename basic_format_context<_Out, _CharT>::iterator
>> > format(const chrono::month_day& __t,
>> > basic_format_context<_Out, _CharT>& __fc) const
>> > - { return _M_f._M_format(__t, __fc); }
>> > + {
>> > + __format::_ChronoData<_CharT> __cd{};
>> > + __cd._M_month = __t.month();
>> > + __cd._M_fill_day(__t.day(), __defSpec._M_needed);
>> > + return _M_f._M_format(__cd, __fc);
>> > + }
>> >
>> > private:
>> > static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
>> > {
>> > + using __format::_ChronoFormats;
>> > + using enum __format::_ChronoParts;
>> > +
>> > __format::_ChronoSpec<_CharT> __res{};
>> > __res._M_debug = true;
>> > __res._M_localized = true;
>> > __res._M_locale_specific = true;
>> > - __res._M_chrono_specs =
>> __format::_ChronoFormats<_CharT>::_S_md();
>> > + __res._M_needed = _Month|_Day;
>> > + __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_md();
>> > return __res;
>> > }();
>> >
>> > @@ -2199,23 +2379,32 @@ namespace __format
>> > constexpr typename basic_format_parse_context<_CharT>::iterator
>> > parse(basic_format_parse_context<_CharT>& __pc)
>> > {
>> > - return _M_f._M_parse(__pc, __format::_Month, __defSpec);
>> > + using enum __format::_ChronoParts;
>> > + return _M_f._M_parse(__pc, _Month, __defSpec);
>> > }
>> >
>> > template<typename _Out>
>> > typename basic_format_context<_Out, _CharT>::iterator
>> > format(const chrono::month_day_last& __t,
>> > basic_format_context<_Out, _CharT>& __fc) const
>> > - { return _M_f._M_format(__t, __fc); }
>> > + {
>> > + __format::_ChronoData<_CharT> __cd{};
>> > + __cd._M_month = __t.month();
>> > + return _M_f._M_format(__cd, __fc);
>> > + }
>> >
>> > private:
>> > static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
>> > {
>> > + using __format::_ChronoFormats;
>> > + using enum __format::_ChronoParts;
>> > +
>> > __format::_ChronoSpec<_CharT> __res{};
>> > __res._M_debug = true;
>> > __res._M_localized = true;
>> > __res._M_locale_specific = true;
>> > - __res._M_chrono_specs =
>> __format::_ChronoFormats<_CharT>::_S_ml();
>> > + __res._M_needed = _Month;
>> > + __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_ml();
>> > return __res;
>> > }();
>> >
>> > @@ -2228,24 +2417,33 @@ namespace __format
>> > constexpr typename basic_format_parse_context<_CharT>::iterator
>> > parse(basic_format_parse_context<_CharT>& __pc)
>> > {
>> > - return _M_f._M_parse(__pc, __format::_Month|__format::_Weekday,
>> > - __defSpec);
>> > + using enum __format::_ChronoParts;
>> > + return _M_f._M_parse(__pc, _Month|_IndexedWeekday, __defSpec);
>> > }
>> >
>> > template<typename _Out>
>> > typename basic_format_context<_Out, _CharT>::iterator
>> > format(const chrono::month_weekday& __t,
>> > basic_format_context<_Out, _CharT>& __fc) const
>> > - { return _M_f._M_format(__t, __fc); }
>> > + {
>> > + __format::_ChronoData<_CharT> __cd{};
>> > + __cd._M_month = __t.month();
>> > + __cd._M_fill_weekday(__t.weekday_indexed(),
>> __defSpec._M_needed);
>> > + return _M_f._M_format(__cd, __fc);
>> > + }
>> >
>> > private:
>> > static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
>> > {
>> > + using __format::_ChronoFormats;
>> > + using enum __format::_ChronoParts;
>> > +
>> > __format::_ChronoSpec<_CharT> __res{};
>> > __res._M_debug = true;
>> > __res._M_localized = true;
>> > __res._M_locale_specific = true;
>> > - __res._M_chrono_specs =
>> __format::_ChronoFormats<_CharT>::_S_mwi();
>> > + __res._M_needed = _Month|_IndexedWeekday;
>> > + __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_mwi();
>> > return __res;
>> > }();
>> >
>> > @@ -2258,24 +2456,33 @@ namespace __format
>> > constexpr typename basic_format_parse_context<_CharT>::iterator
>> > parse(basic_format_parse_context<_CharT>& __pc)
>> > {
>> > - return _M_f._M_parse(__pc, __format::_Month|__format::_Weekday,
>> > - __defSpec);
>> > + using enum __format::_ChronoParts;
>> > + return _M_f._M_parse(__pc, _Month|_Weekday, __defSpec);
>> > }
>> >
>> > template<typename _Out>
>> > typename basic_format_context<_Out, _CharT>::iterator
>> > format(const chrono::month_weekday_last& __t,
>> > basic_format_context<_Out, _CharT>& __fc) const
>> > - { return _M_f._M_format(__t, __fc); }
>> > + {
>> > + __format::_ChronoData<_CharT> __cd{};
>> > + __cd._M_month = __t.month();
>> > + __cd._M_weekday = __t.weekday_last().weekday();
>> > + return _M_f._M_format(__cd, __fc);
>> > + }
>> >
>> > private:
>> > static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
>> > {
>> > + using __format::_ChronoFormats;
>> > + using enum __format::_ChronoParts;
>> > +
>> > __format::_ChronoSpec<_CharT> __res{};
>> > __res._M_debug = true;
>> > __res._M_localized = true;
>> > __res._M_locale_specific = true;
>> > - __res._M_chrono_specs =
>> __format::_ChronoFormats<_CharT>::_S_mwl();
>> > + __res._M_needed = _Month|_Weekday;
>> > + __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_mwl();
>> > return __res;
>> > }();
>> >
>> > @@ -2288,24 +2495,32 @@ namespace __format
>> > constexpr typename basic_format_parse_context<_CharT>::iterator
>> > parse(basic_format_parse_context<_CharT>& __pc)
>> > {
>> > - return _M_f._M_parse(__pc, __format::_Year|__format::_Month,
>> > - __defSpec);
>> > + using enum __format::_ChronoParts;
>> > + return _M_f._M_parse(__pc, _Year|_Month, __defSpec);
>> > }
>> >
>> > template<typename _Out>
>> > typename basic_format_context<_Out, _CharT>::iterator
>> > format(const chrono::year_month& __t,
>> > basic_format_context<_Out, _CharT>& __fc) const
>> > - { return _M_f._M_format(__t, __fc); }
>> > + {
>> > + __format::_ChronoData<_CharT> __cd{};
>> > + __cd._M_fill_year_month(__t, __defSpec._M_needed);
>> > + return _M_f._M_format(__cd, __fc);
>> > + }
>> >
>> > private:
>> > static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
>> > {
>> > + using __format::_ChronoFormats;
>> > + using enum __format::_ChronoParts;
>> > +
>> > __format::_ChronoSpec<_CharT> __res{};
>> > __res._M_debug = true;
>> > __res._M_localized = true;
>> > __res._M_locale_specific = true;
>> > - __res._M_chrono_specs =
>> __format::_ChronoFormats<_CharT>::_S_ym();
>> > + __res._M_needed = _Year|_Month;
>> > + __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_ym();
>> > return __res;
>> > }();
>> >
>> > @@ -2317,20 +2532,38 @@ namespace __format
>> > {
>> > constexpr typename basic_format_parse_context<_CharT>::iterator
>> > parse(basic_format_parse_context<_CharT>& __pc)
>> > - { return _M_f._M_parse(__pc, __format::_Date, __defSpec); }
>> > + {
>> > + using enum __format::_ChronoParts;
>> > + return _M_f._M_parse(__pc, _Date, __defSpec);
>> > + }
>> >
>> > template<typename _Out>
>> > typename basic_format_context<_Out, _CharT>::iterator
>> > format(const chrono::year_month_day& __t,
>> > basic_format_context<_Out, _CharT>& __fc) const
>> > - { return _M_f._M_format(__t, __fc); }
>> > + {
>> > + __format::_ChronoData<_CharT> __cd{};
>> > + auto __parts = _M_f._M_spec._M_needed;
>> > + __parts = __cd._M_fill_year_month(__t, __parts);
>> > + __parts = __cd._M_fill_day(__t.day(), __parts);
>> > + if (__parts == 0)
>> > + return _M_f._M_format(__cd, __fc);
>> > +
>> > + chrono::local_days __ld(__t);
>> > + __cd._M_fill_ldays(__ld, __parts);
>> > + return _M_f._M_format(__cd, __fc);
>> > + }
>> >
>> > private:
>> > static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
>> > {
>> > + using __format::_ChronoFormats;
>> > + using enum __format::_ChronoParts;
>> > +
>> > __format::_ChronoSpec<_CharT> __res{};
>> > __res._M_debug = true;
>> > - __res._M_chrono_specs =
>> __format::_ChronoFormats<_CharT>::_S_f();
>> > + __res._M_needed = _YearMonthDay;
>> > + __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_f();
>> > return __res;
>> > }();
>> >
>> > @@ -2342,22 +2575,44 @@ namespace __format
>> > {
>> > constexpr typename basic_format_parse_context<_CharT>::iterator
>> > parse(basic_format_parse_context<_CharT>& __pc)
>> > - { return _M_f._M_parse(__pc, __format::_Date, __defSpec); }
>> > + {
>> > + using enum __format::_ChronoParts;
>> > + return _M_f._M_parse(__pc, _Date, __defSpec);
>> > + }
>> >
>> > template<typename _Out>
>> > typename basic_format_context<_Out, _CharT>::iterator
>> > format(const chrono::year_month_day_last& __t,
>> > basic_format_context<_Out, _CharT>& __fc) const
>> > - { return _M_f._M_format(__t, __fc); }
>> > + {
>> > + __format::_ChronoData<_CharT> __cd{};
>> > + auto __parts = _M_f._M_spec._M_needed;
>> > + __parts = __cd._M_fill_year_month(__t, __parts);
>> > + if (__parts == 0)
>> > + return _M_f._M_format(__cd, __fc);
>> > +
>> > + chrono::local_days __ld(__t);
>> > + __parts = __cd._M_fill_ldays(__ld, __parts);
>> > + if (__parts == 0)
>> > + return _M_f._M_format(__cd, __fc);
>> > +
>> > + chrono::year_month_day __ymd(__ld);
>> > + __cd._M_fill_day(__ymd.day(), __parts);
>> > + return _M_f._M_format(__cd, __fc);
>> > + }
>> >
>> > private:
>> > static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
>> > {
>> > + using __format::_ChronoFormats;
>> > + using enum __format::_ChronoParts;
>> > +
>> > __format::_ChronoSpec<_CharT> __res{};
>> > __res._M_debug = true;
>> > __res._M_localized = true;
>> > __res._M_locale_specific = true;
>> > - __res._M_chrono_specs =
>> __format::_ChronoFormats<_CharT>::_S_yml();
>> > + __res._M_needed = _Year|_Month;
>> > + __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_yml();
>> > return __res;
>> > }();
>> >
>> > @@ -2369,22 +2624,46 @@ namespace __format
>> > {
>> > constexpr typename basic_format_parse_context<_CharT>::iterator
>> > parse(basic_format_parse_context<_CharT>& __pc)
>> > - { return _M_f._M_parse(__pc, __format::_Date, __defSpec); }
>> > + {
>> > + using enum __format::_ChronoParts;
>> > + return _M_f._M_parse(__pc, _Date, __defSpec);
>> > + }
>> >
>> > template<typename _Out>
>> > typename basic_format_context<_Out, _CharT>::iterator
>> > format(const chrono::year_month_weekday& __t,
>> > basic_format_context<_Out, _CharT>& __fc) const
>> > - { return _M_f._M_format(__t, __fc); }
>> > + {
>> > + __format::_ChronoData<_CharT> __cd{};
>> > + auto __parts = _M_f._M_spec._M_needed;
>> > + __parts = __cd._M_fill_year_month(__t, __parts);
>> > + __parts = __cd._M_fill_weekday(__t.weekday_indexed(), __parts);
>> > + if (__parts == 0)
>> > + return _M_f._M_format(__cd, __fc);
>> > +
>> > + chrono::local_days __ld(__t);
>> > + __parts = __cd._M_fill_ldays(__ld, __parts);
>> > + if (__parts == 0)
>> > + return _M_f._M_format(__cd, __fc);
>> > +
>> > + chrono::year_month_day __ymd(__ld);
>> > + // n.b. weekday index is supplied in input, do not override it
>> > + __cd._M_day = __ymd.day();
>> > + return _M_f._M_format(__cd, __fc);
>> > + }
>> >
>> > private:
>> > static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
>> > {
>> > + using __format::_ChronoFormats;
>> > + using enum __format::_ChronoParts;
>> > +
>> > __format::_ChronoSpec<_CharT> __res{};
>> > __res._M_debug = true;
>> > __res._M_localized = true;
>> > __res._M_locale_specific = true;
>> > - __res._M_chrono_specs =
>> __format::_ChronoFormats<_CharT>::_S_ymwi();
>> > + __res._M_needed = _Year|_Month|_IndexedWeekday;
>> > + __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_ymwi();
>> > return __res;
>> > }();
>> >
>> > @@ -2396,22 +2675,46 @@ namespace __format
>> > {
>> > constexpr typename basic_format_parse_context<_CharT>::iterator
>> > parse(basic_format_parse_context<_CharT>& __pc)
>> > - { return _M_f._M_parse(__pc, __format::_Date, __defSpec); }
>> > + {
>> > + using enum __format::_ChronoParts;
>> > + return _M_f._M_parse(__pc, _Date, __defSpec);
>> > + }
>> >
>> > template<typename _Out>
>> > typename basic_format_context<_Out, _CharT>::iterator
>> > format(const chrono::year_month_weekday_last& __t,
>> > basic_format_context<_Out, _CharT>& __fc) const
>> > - { return _M_f._M_format(__t, __fc); }
>> > + {
>> > + __format::_ChronoData<_CharT> __cd{};
>> > + auto __parts = _M_f._M_spec._M_needed;
>> > + __parts = __cd._M_fill_year_month(__t, __parts);
>> > + __cd._M_weekday = __t.weekday_last().weekday();
>> > + __parts -= __format::_ChronoParts::_Weekday;
>> > + if (__parts == 0)
>> > + return _M_f._M_format(__cd, __fc);
>> > +
>> > + chrono::local_days __ld(__t);
>> > + __parts = __cd._M_fill_ldays(__ld, __parts);
>> > + if (__parts == 0)
>> > + return _M_f._M_format(__cd, __fc);
>> > +
>> > + chrono::year_month_day __ymd(__ld);
>> > + __cd._M_fill_day(__ymd.day(), __parts);
>> > + return _M_f._M_format(__cd, __fc);
>> > + }
>> >
>> > private:
>> > static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
>> > {
>> > + using __format::_ChronoFormats;
>> > + using enum __format::_ChronoParts;
>> > +
>> > __format::_ChronoSpec<_CharT> __res{};
>> > __res._M_debug = true;
>> > __res._M_localized = true;
>> > __res._M_locale_specific = true;
>> > - __res._M_chrono_specs =
>> __format::_ChronoFormats<_CharT>::_S_ymwl();
>> > + __res._M_needed = _Year|_Month|_Weekday;
>> > + __res._M_chrono_specs = _ChronoFormats<_CharT>::_S_ymwl();
>> > return __res;
>> > }();
>> >
>> > @@ -2423,24 +2726,43 @@ namespace __format
>> > {
>> > constexpr typename basic_format_parse_context<_CharT>::iterator
>> > parse(basic_format_parse_context<_CharT>& __pc)
>> > - { return _M_f._M_parse(__pc, __format::_TimeOfDay, __defSpec); }
>> > + {
>> > + using enum __format::_ChronoParts;
>> > + return _M_f.template _M_parse<_Precision>(__pc, _Time, __defSpec);
>> > + }
>> >
>> > template<typename _Out>
>> > typename basic_format_context<_Out, _CharT>::iterator
>> > format(const chrono::hh_mm_ss<chrono::duration<_Rep, _Period>>&
>> __t,
>> > basic_format_context<_Out, _CharT>& __fc) const
>> > - { return _M_f._M_format(__t, __fc); }
>> > + {
>> > + using enum __format::_ChronoParts;
>> > +
>> > + __format::_ChronoData<_CharT> __cd;
>> > + __cd._M_is_neg = __t.is_negative();
>> > + __cd._M_hours = __t.hours();
>> > + __cd._M_minutes = __t.minutes();
>> > + __cd._M_seconds = __t.seconds();
>> > +
>> > + _Precision __d(0);
>> > + // n.b. computing total duration or total seconds may overflow,
>> > + // do not compute them if not requested.
>> > + if (_M_f._M_spec._M_needs(_EpochUnits))
>> > + __d = __t.to_duration();
>> > + if (_M_f._M_spec._M_needs(_TotalSeconds))
>> > + __cd._M_eseconds
>> > + = __cd._M_hours + __cd._M_minutes + __cd._M_seconds;
>> > + return _M_f._M_format_units(__cd, __d, __t.subseconds(), __fc);
>> > + }
>> >
>> > private:
>> > - static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
>> > - {
>> > - __format::_ChronoSpec<_CharT> __res{};
>> > - __res._M_localized = true;
>> > - __res._M_chrono_specs =
>> __format::_ChronoFormats<_CharT>::_S_t();
>> > - return __res;
>> > - }();
>> > + using _Precision
>> > + = typename chrono::hh_mm_ss<chrono::duration<_Rep,
>> _Period>>::precision;
>> > + static constexpr __format::_ChronoSpec<_CharT> __defSpec =
>> > + __format::__formatter_duration<_CharT>::
>> > + template
>> _S_spec_for<_Precision>(__format::_ChronoParts::_Time);
>> >
>> > - __format::__formatter_chrono<_CharT> _M_f{__defSpec};
>> > + __format::__formatter_duration<_CharT> _M_f{__defSpec};
>> > };
>> >
>> > #if _GLIBCXX_USE_CXX11_ABI || ! _GLIBCXX_USE_DUAL_ABI
>> > @@ -2485,7 +2807,9 @@ namespace __format
>> > constexpr typename basic_format_parse_context<_CharT>::iterator
>> > parse(basic_format_parse_context<_CharT>& __pc)
>> > {
>> > - auto __next = _M_f._M_parse(__pc, __format::_ZonedDateTime,
>> __defSpec);
>> > + using enum __format::_ChronoParts;
>> > + auto __next
>> > + = _M_f.template _M_parse<_Duration>(__pc, _ZonedDateTime,
>> __defSpec);
>> > if constexpr (!__stream_insertable)
>> > if (_M_f._M_spec._M_chrono_specs.empty())
>> > __format::__invalid_chrono_spec(); // chrono-specs can't be
>> empty
>> > @@ -2496,7 +2820,15 @@ namespace __format
>> > typename basic_format_context<_Out, _CharT>::iterator
>> > format(const chrono::sys_time<_Duration>& __t,
>> > basic_format_context<_Out, _CharT>& __fc) const
>> > - { return _M_f._M_format(__t, __fc); }
>> > + {
>> > + __format::_ChronoData<_CharT> __cd{};
>> > + __cd._M_fill_utc_zone();
>> > +
>> > + _Duration __ed = __t.time_since_epoch();
>> > + __cd._M_eseconds = chrono::floor<chrono::seconds>(__ed);
>> > + __cd._M_lseconds = chrono::local_seconds(__cd._M_eseconds);
>> > + return _M_f._M_format_time_point(__cd, __ed, __fc);
>> > + }
>> >
>> > private:
>> > static constexpr bool __stream_insertable
>> > @@ -2505,20 +2837,17 @@ namespace __format
>> >
>> > static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
>> > {
>> > - __format::_ChronoSpec<_CharT> __res{};
>> > + using enum __format::_ChronoParts;
>> > + __format::_ChronoParts __needed = _DateTime;
>> > if constexpr (!__stream_insertable)
>> > - return __res;
>> > + __needed = _None;
>> > else if constexpr (is_convertible_v<_Duration, chrono::days>)
>> > - __res._M_chrono_specs =
>> __format::_ChronoFormats<_CharT>::_S_f();
>> > - else
>> > - {
>> > - __res._M_localized = true;
>> > - __res._M_chrono_specs =
>> __format::_ChronoFormats<_CharT>::_S_ft();
>> > - }
>> > - return __res;
>> > + __needed = _Date;
>> > + return __format::__formatter_duration<_CharT>::
>> > + template _S_spec_for<_Duration>(__needed);
>> > }();
>> >
>> > - __format::__formatter_chrono<_CharT> _M_f{__defSpec};
>> > + __format::__formatter_duration<_CharT> _M_f{__defSpec};
>> > };
>> >
>> > template<typename _Duration, __format::__char _CharT>
>> > @@ -2527,40 +2856,43 @@ namespace __format
>> > {
>> > constexpr typename basic_format_parse_context<_CharT>::iterator
>> > parse(basic_format_parse_context<_CharT>& __pc)
>> > - { return _M_f._M_parse(__pc, __format::_ZonedDateTime,
>> __defSpec); }
>> > + {
>> > + using enum __format::_ChronoParts;
>> > + return _M_f.template _M_parse<_Duration>(__pc, _ZonedDateTime,
>> __defSpec);
>> > + }
>> >
>> > template<typename _Out>
>> > typename basic_format_context<_Out, _CharT>::iterator
>> > format(const chrono::utc_time<_Duration>& __t,
>> > basic_format_context<_Out, _CharT>& __fc) const
>> > {
>> > + using __format::_ChronoParts;
>> > + using namespace chrono;
>> > + __format::_ChronoData<_CharT> __cd{};
>> > + __cd._M_fill_utc_zone();
>> > +
>> > + _Duration __ed = __t.time_since_epoch();
>> > + __cd._M_eseconds = chrono::floor<seconds>(__ed);
>> > // Adjust by removing leap seconds to get equivalent sys_time.
>> > // We can't just use clock_cast because we want to know if the
>> time
>> > // falls within a leap second insertion, and format seconds as
>> "60".
>> > - using chrono::__detail::__utc_leap_second;
>> > - using chrono::seconds;
>> > - using chrono::sys_time;
>> > - using _CDur = common_type_t<_Duration, seconds>;
>> > const auto __li = chrono::get_leap_second_info(__t);
>> > - sys_time<_CDur> __s{__t.time_since_epoch() - __li.elapsed};
>> > - if (!__li.is_leap_second) [[likely]]
>> > - return _M_f._M_format(__s, __fc);
>> > - else
>> > - return _M_f._M_format(__utc_leap_second(__s), __fc);
>> > + __cd._M_lseconds = local_seconds(__cd._M_eseconds -
>> __li.elapsed);
>> > + auto __parts = _M_f._M_spec._M_needed -
>> _ChronoParts::_TotalSeconds;
>> > + if ((__parts & _ChronoParts::_DateTime) != 0)
>> > + {
>> > + __cd._M_fill_date_time(__cd._M_lseconds, __parts);
>> > + __cd._M_seconds += seconds(__li.is_leap_second);
>> > + }
>> > + return _M_f._M_format_units(__cd, __ed, __ed -
>> __cd._M_eseconds, __fc);
>> > }
>> >
>> > private:
>> > - friend formatter<chrono::__detail::__utc_leap_second<_Duration>,
>> _CharT>;
>> > + static constexpr __format::_ChronoSpec<_CharT> __defSpec =
>> > + __format::__formatter_duration<_CharT>::
>> > + template
>> _S_spec_for<_Duration>(__format::_ChronoParts::_DateTime);
>> >
>> > - static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
>> > - {
>> > - __format::_ChronoSpec<_CharT> __res{};
>> > - __res._M_localized = true;
>> > - __res._M_chrono_specs =
>> __format::_ChronoFormats<_CharT>::_S_ft();
>> > - return __res;
>> > - }();
>> > -
>> > - __format::__formatter_chrono<_CharT> _M_f{__defSpec};
>> > + __format::__formatter_duration<_CharT> _M_f{__defSpec};
>> > };
>> >
>> > template<typename _Duration, __format::__char _CharT>
>> > @@ -2569,37 +2901,34 @@ namespace __format
>> > {
>> > constexpr typename basic_format_parse_context<_CharT>::iterator
>> > parse(basic_format_parse_context<_CharT>& __pc)
>> > - { return _M_f._M_parse(__pc, __format::_ZonedDateTime,
>> __defSpec); }
>> > + {
>> > + using enum __format::_ChronoParts;
>> > + return _M_f.template _M_parse<_Duration>(__pc, _ZonedDateTime,
>> __defSpec);
>> > + }
>> >
>> > template<typename _Out>
>> > typename basic_format_context<_Out, _CharT>::iterator
>> > format(const chrono::tai_time<_Duration>& __t,
>> > basic_format_context<_Out, _CharT>& __fc) const
>> > {
>> > - // Convert to __local_time_fmt with abbrev "TAI" and offset 0s.
>> > - // We use __local_time_fmt and not sys_time (as the standard
>> implies)
>> > - // because %Z for sys_time would print "UTC" and we want "TAI"
>> here.
>> > + using namespace chrono;
>> > + __format::_ChronoData<_CharT> __cd{};
>> > + __cd._M_fill_zone("TAI", L"TAI");
>> >
>> > + _Duration __ed = __t.time_since_epoch();
>> > + __cd._M_eseconds = chrono::floor<seconds>(__ed);
>> > // Offset is 1970y/January/1 - 1958y/January/1
>> > constexpr chrono::days __tai_offset = chrono::days(4383);
>> > - using _CDur = common_type_t<_Duration, chrono::days>;
>> > - chrono::local_time<_CDur> __lt(__t.time_since_epoch() -
>> __tai_offset);
>> > - const string __abbrev("TAI", 3);
>> > - const chrono::seconds __off = 0s;
>> > - const auto __lf = chrono::local_time_format(__lt, &__abbrev,
>> &__off);
>> > - return _M_f._M_format(__lf, __fc);
>> > + __cd._M_lseconds = local_seconds(__cd._M_eseconds -
>> __tai_offset);
>> > + return _M_f._M_format_time_point(__cd, __ed, __fc);
>> > }
>> >
>> > private:
>> > - static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
>> > - {
>> > - __format::_ChronoSpec<_CharT> __res{};
>> > - __res._M_localized = true;
>> > - __res._M_chrono_specs =
>> __format::_ChronoFormats<_CharT>::_S_ft();
>> > - return __res;
>> > - }();
>> > + static constexpr __format::_ChronoSpec<_CharT> __defSpec =
>> > + __format::__formatter_duration<_CharT>::
>> > + template
>> _S_spec_for<_Duration>(__format::_ChronoParts::_DateTime);
>> >
>> > - __format::__formatter_chrono<_CharT> _M_f{__defSpec};
>> > + __format::__formatter_duration<_CharT> _M_f{__defSpec};
>> > };
>> >
>> > template<typename _Duration, __format::__char _CharT>
>> > @@ -2608,37 +2937,34 @@ namespace __format
>> > {
>> > constexpr typename basic_format_parse_context<_CharT>::iterator
>> > parse(basic_format_parse_context<_CharT>& __pc)
>> > - { return _M_f._M_parse(__pc, __format::_ZonedDateTime,
>> __defSpec); }
>> > + {
>> > + using enum __format::_ChronoParts;
>> > + return _M_f.template _M_parse<_Duration>(__pc, _ZonedDateTime,
>> __defSpec);
>> > + }
>> >
>> > template<typename _Out>
>> > typename basic_format_context<_Out, _CharT>::iterator
>> > format(const chrono::gps_time<_Duration>& __t,
>> > basic_format_context<_Out, _CharT>& __fc) const
>> > {
>> > - // Convert to __local_time_fmt with abbrev "GPS" and offset 0s.
>> > - // We use __local_time_fmt and not sys_time (as the standard
>> implies)
>> > - // because %Z for sys_time would print "UTC" and we want "GPS"
>> here.
>> > + using namespace chrono;
>> > + __format::_ChronoData<_CharT> __cd{};
>> > + __cd._M_fill_zone("GPS", L"GPS");
>> >
>> > + _Duration __ed = __t.time_since_epoch();
>> > + __cd._M_eseconds = chrono::floor<seconds>(__ed);
>> > // Offset is 1980y/January/Sunday[1] - 1970y/January/1
>> > constexpr chrono::days __gps_offset = chrono::days(3657);
>> > - using _CDur = common_type_t<_Duration, chrono::days>;
>> > - chrono::local_time<_CDur> __lt(__t.time_since_epoch() +
>> __gps_offset);
>> > - const string __abbrev("GPS", 3);
>> > - const chrono::seconds __off = 0s;
>> > - const auto __lf = chrono::local_time_format(__lt, &__abbrev,
>> &__off);
>> > - return _M_f._M_format(__lf, __fc);
>> > + __cd._M_lseconds = local_seconds(__cd._M_eseconds +
>> __gps_offset);
>> > + return _M_f._M_format_time_point(__cd, __ed, __fc);
>> > }
>> >
>> > private:
>> > - static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
>> > - {
>> > - __format::_ChronoSpec<_CharT> __res{};
>> > - __res._M_localized = true;
>> > - __res._M_chrono_specs =
>> __format::_ChronoFormats<_CharT>::_S_ft();
>> > - return __res;
>> > - }();
>> > + static constexpr __format::_ChronoSpec<_CharT> __defSpec =
>> > + __format::__formatter_duration<_CharT>::
>> > + template
>> _S_spec_for<_Duration>(__format::_ChronoParts::_DateTime);
>> >
>> > - __format::__formatter_chrono<_CharT> _M_f{__defSpec};
>> > + __format::__formatter_duration<_CharT> _M_f{__defSpec};
>> > };
>> >
>> > template<typename _Duration, __format::__char _CharT>
>> > @@ -2646,7 +2972,10 @@ namespace __format
>> > {
>> > constexpr typename basic_format_parse_context<_CharT>::iterator
>> > parse(basic_format_parse_context<_CharT>& __pc)
>> > - { return _M_f._M_parse(__pc, __format::_ZonedDateTime,
>> __defSpec); }
>> > + {
>> > + using enum __format::_ChronoParts;
>> > + return _M_f.template _M_parse<_Duration>(__pc, _ZonedDateTime,
>> __defSpec);
>> > + }
>> >
>> > template<typename _Out>
>> > typename basic_format_context<_Out, _CharT>::iterator
>> > @@ -2654,19 +2983,23 @@ namespace __format
>> > basic_format_context<_Out, _CharT>& __fc) const
>> > {
>> > using namespace chrono;
>> > - return _M_f._M_format(chrono::clock_cast<system_clock>(__t),
>> __fc);
>> > + __format::_ChronoData<_CharT> __cd{};
>> > + __cd._M_fill_utc_zone();
>> > +
>> > + _Duration __ed = __t.time_since_epoch();
>> > + __cd._M_eseconds = chrono::floor<seconds>(__ed);
>> > + auto __st = chrono::clock_cast<system_clock>(__t);
>> > + __cd._M_lseconds
>> > + =
>> local_seconds(chrono::floor<seconds>(__st.time_since_epoch()));
>> > + return _M_f._M_format_time_point(__cd, __ed, __fc);
>> > }
>> >
>> > private:
>> > - static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
>> > - {
>> > - __format::_ChronoSpec<_CharT> __res{};
>> > - __res._M_localized = true;
>> > - __res._M_chrono_specs =
>> __format::_ChronoFormats<_CharT>::_S_ft();
>> > - return __res;
>> > - }();
>> > + static constexpr __format::_ChronoSpec<_CharT> __defSpec =
>> > + __format::__formatter_duration<_CharT>::
>> > + template
>> _S_spec_for<_Duration>(__format::_ChronoParts::_DateTime);
>> >
>> > - __format::__formatter_chrono<_CharT> _M_f{__defSpec};
>> > + __format::__formatter_duration<_CharT> _M_f{__defSpec};
>> > };
>> >
>> > template<typename _Duration, __format::__char _CharT>
>> > @@ -2674,29 +3007,35 @@ namespace __format
>> > {
>> > constexpr typename basic_format_parse_context<_CharT>::iterator
>> > parse(basic_format_parse_context<_CharT>& __pc)
>> > - { return _M_f._M_parse(__pc, __format::_DateTime, __defSpec); }
>> > + {
>> > + using enum __format::_ChronoParts;
>> > + return _M_f.template _M_parse<_Duration>(__pc, _DateTime,
>> __defSpec);
>> > + }
>> >
>> > template<typename _Out>
>> > typename basic_format_context<_Out, _CharT>::iterator
>> > - format(const chrono::local_time<_Duration>& __t,
>> > + format(const chrono::local_time<_Duration>& __lt,
>> > basic_format_context<_Out, _CharT>& __fc) const
>> > - { return _M_f._M_format(__t, __fc); }
>> > + {
>> > + __format::_ChronoData<_CharT> __cd{};
>> > + _Duration __ed = __lt.time_since_epoch();
>> > + __cd._M_lseconds = chrono::floor<chrono::seconds>(__lt);
>> > + __cd._M_eseconds = __cd._M_lseconds.time_since_epoch();
>> > + return _M_f._M_format_time_point(__cd, __ed, __fc);
>> > + }
>> >
>> > private:
>> > static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
>> > {
>> > - __format::_ChronoSpec<_CharT> __res{};
>> > + using enum __format::_ChronoParts;
>> > + __format::_ChronoParts __needed = _DateTime;
>> > if constexpr (is_convertible_v<_Duration, chrono::days>)
>> > - __res._M_chrono_specs =
>> __format::_ChronoFormats<_CharT>::_S_f();
>> > - else
>> > - {
>> > - __res._M_localized = true;
>> > - __res._M_chrono_specs =
>> __format::_ChronoFormats<_CharT>::_S_ft();
>> > - }
>> > - return __res;
>> > + __needed = _Date;
>> > + return __format::__formatter_duration<_CharT>::
>> > + template _S_spec_for<_Duration>(__needed);
>> > }();
>> >
>> > - __format::__formatter_chrono<_CharT> _M_f{__defSpec};
>> > + __format::__formatter_duration<_CharT> _M_f{__defSpec};
>> > };
>> >
>> > template<typename _Duration, __format::__char _CharT>
>> > @@ -2704,24 +3043,59 @@ namespace __format
>> > {
>> > constexpr typename basic_format_parse_context<_CharT>::iterator
>> > parse(basic_format_parse_context<_CharT>& __pc)
>> > - { return _M_f._M_parse(__pc, __format::_ZonedDateTime,
>> __defSpec); }
>> > + {
>> > + using enum __format::_ChronoParts;
>> > + return _M_f.template _M_parse<_Duration>(__pc, _ZonedDateTime,
>> __defSpec);
>> > + }
>> >
>> > template<typename _Out>
>> > typename basic_format_context<_Out, _CharT>::iterator
>> > - format(const chrono::__detail::__local_time_fmt<_Duration>& __t,
>> > + format(const chrono::__detail::__local_time_fmt<_Duration>& __zt,
>> > basic_format_context<_Out, _CharT>& __fc) const
>> > - { return _M_f._M_format(__t, __fc); }
>> > + {
>> > + using enum __format::_ChronoParts;
>> > + __format::_ChronoData<_CharT> __cd{};
>> > +
>> > + if (_M_f._M_spec._M_needs(_ZoneOffset))
>> > + {
>> > + if (!__zt._M_offset_sec)
>> > + std::__throw_format_error("format error: no timezone
>> available for %z");
>> > + __cd._M_zone_offset = *__zt._M_offset_sec;
>> > + }
>> > +
>> > + basic_string<_CharT> __zone_store;
>> > + if (_M_f._M_spec._M_needs(_ZoneAbbrev))
>> > + {
>> > + if (!__zt._M_abbrev)
>> > + std::__throw_format_error("format error: no timezone
>> available for %Z");
>> > +
>> > + __cd._M_zone_cstr = __zt._M_abbrev->data();
>> > + if constexpr (is_same_v<_CharT, char>)
>> > + __cd._M_zone_abbrev = *__zt._M_abbrev;
>> > + else
>> > + {
>> > + // TODO: use resize_for_override
>> > + __zone_store.resize(__zt._M_abbrev->size());
>> > + auto& __ct =
>> use_facet<ctype<_CharT>>(_M_f._M_locale(__fc));
>> > + __ct.widen(__zt._M_abbrev->data(),
>> > + __zt._M_abbrev->data() +
>> __zt._M_abbrev->size(),
>> > + __zone_store.data());
>> > + __cd._M_zone_abbrev = __zone_store;
>> > + }
>> > + }
>> > +
>> > + _Duration __ed = __zt._M_time.time_since_epoch();
>> > + __cd._M_lseconds = chrono::floor<chrono::seconds>(__zt._M_time);
>> > + __cd._M_eseconds = __cd._M_lseconds.time_since_epoch();
>> > + return _M_f._M_format_time_point(__cd, __ed, __fc);
>> > + }
>> >
>> > private:
>> > - static constexpr __format::_ChronoSpec<_CharT> __defSpec = []
>> > - {
>> > - __format::_ChronoSpec<_CharT> __res{};
>> > - __res._M_localized = true;
>> > - __res._M_chrono_specs =
>> __format::_ChronoFormats<_CharT>::_S_ftz();
>> > - return __res;
>> > - }();
>> > + static constexpr __format::_ChronoSpec<_CharT> __defSpec =
>> > + __format::__formatter_duration<_CharT>::
>> > + template
>> _S_spec_for<_Duration>(__format::_ChronoParts::_ZonedDateTime);
>> >
>> > - __format::__formatter_chrono<_CharT> _M_f{__defSpec};
>> > + __format::__formatter_duration<_CharT> _M_f{__defSpec};
>> > };
>> >
>> > #if _GLIBCXX_USE_CXX11_ABI || ! _GLIBCXX_USE_DUAL_ABI
>> > @@ -2745,18 +3119,6 @@ namespace __format
>> > };
>> > #endif
>> >
>> > - // Partial specialization needed for %c formatting of
>> __utc_leap_second.
>> > - template<typename _Duration, __format::__char _CharT>
>> > - struct formatter<chrono::__detail::__utc_leap_second<_Duration>,
>> _CharT>
>> > - : formatter<chrono::utc_time<_Duration>, _CharT>
>> > - {
>> > - template<typename _Out>
>> > - typename basic_format_context<_Out, _CharT>::iterator
>> > - format(const chrono::__detail::__utc_leap_second<_Duration>& __t,
>> > - basic_format_context<_Out, _CharT>& __fc) const
>> > - { return this->_M_f._M_format(__t, __fc); }
>> > - };
>> > -
>> > namespace chrono
>> > {
>> > /// @addtogroup chrono
>> > @@ -3514,8 +3876,7 @@ namespace __detail
>> > if (!__offset)
>> > __offset = &__off;
>> > using __format::_ChronoParts;
>> > - auto __need = _ChronoParts::_Year | _ChronoParts::_Month
>> > - | _ChronoParts::_Day | _ChronoParts::_TimeOfDay;
>> > + auto __need = _ChronoParts::_YearMonthDay |
>> _ChronoParts::_TimeOfDay;
>> > __detail::_Parser_t<_Duration> __p(__need);
>> > if (__p(__is, __fmt, __abbrev, __offset))
>> > {
>> > @@ -3573,8 +3934,7 @@ namespace __detail
>> > minutes* __offset = nullptr)
>> > {
>> > using __format::_ChronoParts;
>> > - auto __need = _ChronoParts::_Year | _ChronoParts::_Month
>> > - | _ChronoParts::_Day | _ChronoParts::_TimeOfDay;
>> > + auto __need = _ChronoParts::_YearMonthDay |
>> _ChronoParts::_TimeOfDay;
>> > __detail::_Parser_t<_Duration> __p(__need);
>> > if (__p(__is, __fmt, __abbrev, __offset))
>> > {
>> > @@ -3827,8 +4187,8 @@ namespace __detail
>> > minutes __tz_offset = __bad_min;
>> > basic_string<_CharT, _Traits> __tz_abbr;
>> >
>> > - if ((_M_need & _ChronoParts::_TimeOfDay)
>> > - && (_M_need & _ChronoParts::_Year))
>> > + if ((_M_need & _ChronoParts::_TimeOfDay) != 0
>> > + && (_M_need & _ChronoParts::_Year) != 0)
>> > {
>> > // For time_points assume "00:00:00" is implicitly present,
>> > // so we don't fail to parse if it's not (PR
>> libstdc++/114240).
>> > @@ -4101,7 +4461,7 @@ namespace __detail
>> > }
>> > else
>> > {
>> > - if (_M_need & _ChronoParts::_TimeOfDay)
>> > + if ((_M_need & _ChronoParts::_TimeOfDay) != 0)
>> > __err |= ios_base::failbit;
>> > break;
>> > }
>> > @@ -4169,7 +4529,7 @@ namespace __detail
>> > __min = minutes(__val);
>> > else
>> > {
>> > - if (_M_need & _ChronoParts::_TimeOfDay)
>> > + if ((_M_need & _ChronoParts::_TimeOfDay) != 0)
>> > __err |= ios_base::failbit;
>> > break;
>> > }
>> > @@ -4259,7 +4619,7 @@ namespace __detail
>> > auto __val = __read_unsigned(2);
>> > if (__val == -1 || __val > 23) [[unlikely]]
>> > {
>> > - if (_M_need & _ChronoParts::_TimeOfDay)
>> > + if ((_M_need & _ChronoParts::_TimeOfDay) != 0)
>> > __err |= ios_base::failbit;
>> > break;
>> > }
>> > @@ -4270,7 +4630,7 @@ namespace __detail
>> > __val = __read_unsigned(2);
>> > if (__val == -1 || __val > 60) [[unlikely]]
>> > {
>> > - if (_M_need & _ChronoParts::_TimeOfDay)
>> > + if ((_M_need & _ChronoParts::_TimeOfDay) != 0)
>> > __err |= ios_base::failbit;
>> > break;
>> > }
>> > @@ -4305,7 +4665,7 @@ namespace __detail
>> > __s = seconds(__val);
>> > else
>> > {
>> > - if (_M_need & _ChronoParts::_TimeOfDay)
>> > + if ((_M_need & _ChronoParts::_TimeOfDay) != 0)
>> > __err |= ios_base::failbit;
>> > break;
>> > }
>> > @@ -4779,23 +5139,23 @@ namespace __detail
>> >
>> > // Whether the caller wants _M_wd.
>> > // The _Weekday bit is only set for chrono::weekday.
>> > - const bool __need_wday = _M_need & _ChronoParts::_Weekday;
>> > + const bool __need_wday = (_M_need & _ChronoParts::_Weekday)
>> != 0;
>> >
>> > // Whether the caller wants _M_sys_days and _M_time.
>> > // Only true for durations and time_points.
>> > - const bool __need_time = _M_need & _ChronoParts::_TimeOfDay;
>> > + const bool __need_time = (_M_need &
>> _ChronoParts::_TimeOfDay) != 0;
>> >
>> > if (__need_wday && __wday != __bad_wday)
>> > _M_wd = __wday; // Caller only wants a weekday and we
>> have one.
>> > - else if (_M_need & _ChronoParts::_Date) // subsumes
>> __need_wday
>> > + else if ((_M_need & _ChronoParts::_Date) != 0) // subsumes
>> __need_wday
>> > {
>> > // Whether the caller wants _M_ymd.
>> > // True for chrono::year etc., false for time_points.
>> > const bool __need_ymd = !__need_wday && !__need_time;
>> >
>> > - if ((_M_need & _ChronoParts::_Year && __y == __bad_y)
>> > - || (_M_need & _ChronoParts::_Month && __m ==
>> __bad_mon)
>> > - || (_M_need & _ChronoParts::_Day && __d ==
>> __bad_day))
>> > + if (((_M_need & _ChronoParts::_Year) != 0 && __y ==
>> __bad_y)
>> > + || ((_M_need & _ChronoParts::_Month) != 0 && __m ==
>> __bad_mon)
>> > + || ((_M_need & _ChronoParts::_Day) != 0 && __d ==
>> __bad_day))
>> > {
>> > // Missing at least one of y/m/d so calculate
>> sys_days
>> > // from the other data we have available.
>> > @@ -4872,7 +5232,7 @@ namespace __detail
>> > // but check that their values are in range.
>> > // Make unwanted fields valid so that _M_ymd.ok()
>> is true.
>> >
>> > - if (_M_need & _ChronoParts::_Year)
>> > + if ((_M_need & _ChronoParts::_Year) != 0)
>> > {
>> > if (!__y.ok()) [[unlikely]]
>> > __err |= ios_base::failbit;
>> > @@ -4880,7 +5240,7 @@ namespace __detail
>> > else if (__y == __bad_y)
>> > __y = 1972y; // Leap year so that Feb 29 is valid.
>> >
>> > - if (_M_need & _ChronoParts::_Month)
>> > + if ((_M_need & _ChronoParts::_Month) != 0)
>> > {
>> > if (!__m.ok()) [[unlikely]]
>> > __err |= ios_base::failbit;
>> > @@ -4888,7 +5248,7 @@ namespace __detail
>> > else if (__m == __bad_mon)
>> > __m = January;
>> >
>> > - if (_M_need & _ChronoParts::_Day)
>> > + if ((_M_need & _ChronoParts::_Day) != 0)
>> > {
>> > if (__d < day(1) || __d > (__y/__m/last).day())
>> > __err |= ios_base::failbit;
>> > diff --git a/libstdc++-v3/include/std/chrono
>> b/libstdc++-v3/include/std/chrono
>> > index 8eb9fd9baac..cb8213e2f9f 100644
>> > --- a/libstdc++-v3/include/std/chrono
>> > +++ b/libstdc++-v3/include/std/chrono
>> > @@ -2305,8 +2305,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>> > __r *= 10;
>> > return __r;
>> > }
>> > -
>> > - template<typename _Duration> struct __utc_leap_second;
>> > }
>> > /// @endcond
>> >
>> > @@ -2481,30 +2479,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
>> > __byte_duration<ratio<1>> _M_s{};
>> > bool _M_is_neg{};
>> > __subseconds<precision> _M_ss{};
>> > -
>> > - template<typename> friend struct __detail::__utc_leap_second;
>> > };
>> >
>> > - /// @cond undocumented
>> > - namespace __detail
>> > - {
>> > - // Represents a time that is within a leap second insertion.
>> > - template<typename _Duration>
>> > - struct __utc_leap_second
>> > - {
>> > - explicit
>> > - __utc_leap_second(const sys_time<_Duration>& __s)
>> > - : _M_date(chrono::floor<days>(__s)), _M_time(__s - _M_date)
>> > - {
>> > - ++_M_time._M_s;
>> > - }
>> > -
>> > - sys_days _M_date;
>> > - hh_mm_ss<common_type_t<_Duration, days>> _M_time;
>> > - };
>> > - }
>> > - /// @endcond
>> > -
>> > // 12/24 HOURS FUNCTIONS
>> >
>> > constexpr bool
>> > diff --git a/libstdc++-v3/testsuite/std/time/format/empty_spec.cc
>> b/libstdc++-v3/testsuite/std/time/format/empty_spec.cc
>> > index 5f7b8688b8a..923df3d813c 100644
>> > --- a/libstdc++-v3/testsuite/std/time/format/empty_spec.cc
>> > +++ b/libstdc++-v3/testsuite/std/time/format/empty_spec.cc
>> > @@ -355,30 +355,30 @@ test_hh_mm_ss_cust()
>> > // +plus returns long, so formatted as long
>> > const duration<Rep<long>, std::milli> asLong(dt.count());
>> > verify( hms<milliseconds>(asLong),
>> > - WIDEN("22:24:54.123[via format]") );
>> > + WIDEN("22:24:54.123") );
>> > verify( hms<deciseconds>(asLong),
>> > - WIDEN("22:24:54.1[via format]") );
>> > + WIDEN("22:24:54.1") );
>> > verify( hms<seconds>(asLong),
>> > WIDEN("22:24:54") );
>> > verify( hms<milliseconds>(-asLong),
>> > - WIDEN("-22:24:54.123[via format]") );
>> > + WIDEN("-22:24:54.123") );
>> > verify( hms<deciseconds>(-asLong),
>> > - WIDEN("-22:24:54.1[via format]") );
>> > + WIDEN("-22:24:54.1") );
>> > verify( hms<seconds>(-asLong),
>> > WIDEN("-22:24:54") );
>> >
>> > // +asRep returns Rep<>, so formatted as Rep<>
>> > const duration<Rep<>, std::milli> asRep(dt.count());
>> > verify( hms<milliseconds>(asRep),
>> > - WIDEN("22:24:54.123[via format]") );
>> > + WIDEN("22:24:54.123") );
>> > verify( hms<deciseconds>(asRep),
>> > - WIDEN("22:24:54.1[via format]") );
>> > + WIDEN("22:24:54.1") );
>> > verify( hms<seconds>(asLong),
>> > WIDEN("22:24:54") );
>> > verify( hms<milliseconds>(-asLong),
>> > - WIDEN("-22:24:54.123[via format]") );
>> > + WIDEN("-22:24:54.123") );
>> > verify( hms<deciseconds>(-asLong),
>> > - WIDEN("-22:24:54.1[via format]") );
>> > + WIDEN("-22:24:54.1") );
>> > verify( hms<seconds>(-asLong),
>> > WIDEN("-22:24:54") );
>> > }
>> > --
>> > 2.49.0
>> >
>> >
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://gcc.gnu.org/pipermail/libstdc++/attachments/20251008/6cd79398/attachment-0001.htm>
More information about the Libstdc++
mailing list