Commit d34ea4e7 authored by jan.koester's avatar jan.koester
Browse files

test

parent 64542e1c
Loading
Loading
Loading
Loading
+466 −13
Changes for include/cxx/chrono: 466 added lines, 13 removed lines.
Original line number Diff line number Diff line
@@ -311,12 +311,24 @@ constexpr time_point<Clock, ToDuration> round(const time_point<Clock, Duration>&
    return time_point<Clock, ToDuration>(round<ToDuration>(tp.time_since_epoch()));
}

/* time_point +/- duration is a time_point in the common Duration, as in
 * the standard: sys_days + hours(13) must not truncate back to whole days
 * (real gap: sys_seconds built as sys_days + hours + minutes). With a
 * floating-point Rep on either side the time_point's own Duration is
 * kept, since __common_duration is integral. */
template<class D1, class D2>
using __tp_sum_duration = conditional_t<is_floating_point<typename D1::rep>::value || is_floating_point<typename D2::rep>::value,
                                        D1, typename __common_duration<D1, D2>::type>;

template<class Clock, class Duration, class Rep, class Period>
constexpr time_point<Clock, Duration> operator+(const time_point<Clock, Duration>& tp, const duration<Rep, Period>& d) {
    return time_point<Clock, Duration>(tp.time_since_epoch() + duration_cast<Duration>(d));
constexpr time_point<Clock, __tp_sum_duration<Duration, duration<Rep, Period>>>
operator+(const time_point<Clock, Duration>& tp, const duration<Rep, Period>& d) {
    typedef __tp_sum_duration<Duration, duration<Rep, Period>> CD;
    return time_point<Clock, CD>(duration_cast<CD>(tp.time_since_epoch()) + duration_cast<CD>(d));
}
template<class Clock, class Duration, class Rep, class Period>
constexpr time_point<Clock, Duration> operator+(const duration<Rep, Period>& d, const time_point<Clock, Duration>& tp) {
constexpr time_point<Clock, __tp_sum_duration<Duration, duration<Rep, Period>>>
operator+(const duration<Rep, Period>& d, const time_point<Clock, Duration>& tp) {
    return tp + d;
}
/* Real gap found compiling LLVM: llvm/lib/Support/Chrono.cpp subtracts
@@ -343,8 +355,10 @@ constexpr typename __common_duration<Duration1, Duration2>::type operator-(const
 * time_point above (which returns a Duration, not a time_point) --
 * distinguishable by the second operand's real type, no ambiguity. */
template<class Clock, class Duration, class Rep, class Period>
constexpr time_point<Clock, Duration> operator-(const time_point<Clock, Duration>& tp, const duration<Rep, Period>& d) {
    return time_point<Clock, Duration>(tp.time_since_epoch() - duration_cast<Duration>(d));
constexpr time_point<Clock, __tp_sum_duration<Duration, duration<Rep, Period>>>
operator-(const time_point<Clock, Duration>& tp, const duration<Rep, Period>& d) {
    typedef __tp_sum_duration<Duration, duration<Rep, Period>> CD;
    return time_point<Clock, CD>(duration_cast<CD>(tp.time_since_epoch()) - duration_cast<CD>(d));
}

/* time_point had no comparison operators at all -- a real gap
@@ -533,26 +547,465 @@ __parse_manip<Duration> parse(const string& fmt, sys_time<Duration>& tp) { retur
template<class Duration>
__parse_manip<Duration> parse(const char* fmt, sys_time<Duration>& tp) { return {string(fmt), &tp}; }

template<class Duration>
istream& operator>>(istream& is, const __parse_manip<Duration>& m) {
/* reads as many whitespace-separated words as fmt has and strptime()s
 * them into t; false (failbit set unless the stream ran dry) on a mismatch */
inline bool __parse_tm(istream& is, const string& fmt, tm& t) {
    size_t words = 1;
    for (size_t i = 1; i < m.fmt.size(); i++)
        if (m.fmt[i] == ' ' && m.fmt[i - 1] != ' ') words++;
    for (size_t i = 1; i < fmt.size(); i++)
        if (fmt[i] == ' ' && fmt[i - 1] != ' ') words++;
    string text, word;
    for (size_t i = 0; i < words; i++) {
        if (!(is >> word)) return is;
        if (!(is >> word)) return false;
        if (i) text += ' ';
        text += word;
    }
    tm t = {};
    const char* end = strptime(text.c_str(), m.fmt.c_str(), &t);
    t = tm{};
    const char* end = strptime(text.c_str(), fmt.c_str(), &t);
    if (!end || *end) {
        is.setstate(ios_base::failbit);
        return is;
        return false;
    }
    return true;
}

template<class Duration>
istream& operator>>(istream& is, const __parse_manip<Duration>& m) {
    tm t;
    if (__parse_tm(is, m.fmt, t))
        *m.tp = time_point_cast<Duration>(system_clock::from_time_t(timegm(&t)));
    return is;
}

/* The C++20 calendar types: day, month, year, year_month and
 * year_month_day, with year/month/day composition, conversion to and
 * from sys_days (proleptic Gregorian, Howard Hinnant's days_from_civil
 * algorithms), comparisons, operator<< and from_stream() (real gap:
 * blogi's sitemap keys its <lastmod> on year_month_day, parsed from the
 * database's "%Y-%m-%d"). No weekday/year_month_day_last family and no
 * months/years arithmetic on year_month_day yet. */

class day {
public:
    day() = default;
    constexpr explicit day(unsigned d) noexcept : _d((unsigned char)d) {}
    constexpr explicit operator unsigned() const noexcept { return _d; }
    constexpr bool ok() const noexcept { return _d >= 1 && _d <= 31; }
    constexpr day& operator++() noexcept { ++_d; return *this; }
    constexpr day operator++(int) noexcept { day t = *this; ++_d; return t; }
    constexpr day& operator--() noexcept { --_d; return *this; }
    constexpr day operator--(int) noexcept { day t = *this; --_d; return t; }
    constexpr day& operator+=(const days& d) noexcept { _d = (unsigned char)(_d + d.count()); return *this; }
    constexpr day& operator-=(const days& d) noexcept { _d = (unsigned char)(_d - d.count()); return *this; }
private:
    unsigned char _d;
};

class month {
public:
    month() = default;
    constexpr explicit month(unsigned m) noexcept : _m((unsigned char)m) {}
    constexpr explicit operator unsigned() const noexcept { return _m; }
    constexpr bool ok() const noexcept { return _m >= 1 && _m <= 12; }
    /* modular, like the standard's: December + 1 is January */
    constexpr month& operator+=(const months& m) noexcept {
        long long v = ((long long)_m - 1 + m.count()) % 12;
        _m = (unsigned char)((v < 0 ? v + 12 : v) + 1);
        return *this;
    }
    constexpr month& operator-=(const months& m) noexcept { return *this += months(-m.count()); }
    constexpr month& operator++() noexcept { return *this += months(1); }
    constexpr month operator++(int) noexcept { month t = *this; ++*this; return t; }
    constexpr month& operator--() noexcept { return *this -= months(1); }
    constexpr month operator--(int) noexcept { month t = *this; --*this; return t; }
private:
    unsigned char _m;
};

class year {
public:
    year() = default;
    constexpr explicit year(int y) noexcept : _y((short)y) {}
    constexpr explicit operator int() const noexcept { return _y; }
    constexpr bool ok() const noexcept { return _y != -32768; }
    constexpr bool is_leap() const noexcept { return _y % 4 == 0 && (_y % 100 != 0 || _y % 400 == 0); }
    constexpr year operator+() const noexcept { return *this; }
    constexpr year operator-() const noexcept { return year(-_y); }
    constexpr year& operator++() noexcept { ++_y; return *this; }
    constexpr year operator++(int) noexcept { year t = *this; ++_y; return t; }
    constexpr year& operator--() noexcept { --_y; return *this; }
    constexpr year operator--(int) noexcept { year t = *this; --_y; return t; }
    constexpr year& operator+=(const years& y) noexcept { _y = (short)(_y + y.count()); return *this; }
    constexpr year& operator-=(const years& y) noexcept { _y = (short)(_y - y.count()); return *this; }
    static constexpr year min() noexcept { return year(-32767); }
    static constexpr year max() noexcept { return year(32767); }
private:
    short _y;
};

constexpr bool operator==(const day& a, const day& b) noexcept { return (unsigned)a == (unsigned)b; }
constexpr bool operator!=(const day& a, const day& b) noexcept { return !(a == b); }
constexpr bool operator<(const day& a, const day& b) noexcept { return (unsigned)a < (unsigned)b; }
constexpr bool operator<=(const day& a, const day& b) noexcept { return !(b < a); }
constexpr bool operator>(const day& a, const day& b) noexcept { return b < a; }
constexpr bool operator>=(const day& a, const day& b) noexcept { return !(a < b); }
constexpr day operator+(const day& d, const days& n) noexcept { return day((unsigned)((long long)(unsigned)d + n.count())); }
constexpr day operator+(const days& n, const day& d) noexcept { return d + n; }
constexpr day operator-(const day& d, const days& n) noexcept { return d + days(-n.count()); }
constexpr days operator-(const day& a, const day& b) noexcept { return days((long long)(unsigned)a - (long long)(unsigned)b); }

constexpr bool operator==(const month& a, const month& b) noexcept { return (unsigned)a == (unsigned)b; }
constexpr bool operator!=(const month& a, const month& b) noexcept { return !(a == b); }
constexpr bool operator<(const month& a, const month& b) noexcept { return (unsigned)a < (unsigned)b; }
constexpr bool operator<=(const month& a, const month& b) noexcept { return !(b < a); }
constexpr bool operator>(const month& a, const month& b) noexcept { return b < a; }
constexpr bool operator>=(const month& a, const month& b) noexcept { return !(a < b); }
constexpr month operator+(const month& m, const months& n) noexcept { month r = m; r += n; return r; }
constexpr month operator+(const months& n, const month& m) noexcept { return m + n; }
constexpr month operator-(const month& m, const months& n) noexcept { month r = m; r -= n; return r; }
constexpr months operator-(const month& a, const month& b) noexcept {
    long long v = ((long long)(unsigned)a - (long long)(unsigned)b) % 12;
    return months(v < 0 ? v + 12 : v);
}

constexpr bool operator==(const year& a, const year& b) noexcept { return (int)a == (int)b; }
constexpr bool operator!=(const year& a, const year& b) noexcept { return !(a == b); }
constexpr bool operator<(const year& a, const year& b) noexcept { return (int)a < (int)b; }
constexpr bool operator<=(const year& a, const year& b) noexcept { return !(b < a); }
constexpr bool operator>(const year& a, const year& b) noexcept { return b < a; }
constexpr bool operator>=(const year& a, const year& b) noexcept { return !(a < b); }
constexpr year operator+(const year& y, const years& n) noexcept { return year((int)((int)y + n.count())); }
constexpr year operator+(const years& n, const year& y) noexcept { return y + n; }
constexpr year operator-(const year& y, const years& n) noexcept { return year((int)((int)y - n.count())); }
constexpr years operator-(const year& a, const year& b) noexcept { return years((int)a - (int)b); }

inline constexpr month January{1}, February{2}, March{3}, April{4}, May{5}, June{6},
    July{7}, August{8}, September{9}, October{10}, November{11}, December{12};

class year_month {
public:
    year_month() = default;
    constexpr year_month(const chrono::year& y, const chrono::month& m) noexcept : _y(y), _m(m) {}
    constexpr chrono::year year() const noexcept { return _y; }
    constexpr chrono::month month() const noexcept { return _m; }
    constexpr bool ok() const noexcept { return _y.ok() && _m.ok(); }
private:
    chrono::year _y;
    chrono::month _m;
};

constexpr bool operator==(const year_month& a, const year_month& b) noexcept { return a.year() == b.year() && a.month() == b.month(); }
constexpr bool operator!=(const year_month& a, const year_month& b) noexcept { return !(a == b); }
constexpr bool operator<(const year_month& a, const year_month& b) noexcept {
    return a.year() != b.year() ? a.year() < b.year() : a.month() < b.month();
}
constexpr bool operator<=(const year_month& a, const year_month& b) noexcept { return !(b < a); }
constexpr bool operator>(const year_month& a, const year_month& b) noexcept { return b < a; }
constexpr bool operator>=(const year_month& a, const year_month& b) noexcept { return !(a < b); }

constexpr year_month operator/(const year& y, const month& m) noexcept { return year_month(y, m); }
constexpr year_month operator/(const year& y, int m) noexcept { return year_month(y, month((unsigned)m)); }

/* days in month m of year y (m.ok()) */
constexpr unsigned __last_day(const year& y, const month& m) noexcept {
    constexpr unsigned char d[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    unsigned mi = (unsigned)m;
    return mi == 2 && y.is_leap() ? 29 : d[mi - 1];
}

class year_month_day {
public:
    year_month_day() = default;
    constexpr year_month_day(const chrono::year& y, const chrono::month& m, const chrono::day& d) noexcept
        : _y(y), _m(m), _d(d) {}
    /* civil_from_days */
    constexpr year_month_day(const sys_days& dp) noexcept : _y(), _m(), _d() {
        long long z = dp.time_since_epoch().count() + 719468;
        long long era = (z >= 0 ? z : z - 146096) / 146097;
        unsigned doe = (unsigned)(z - era * 146097);
        unsigned yoe = (doe - doe / 1460 + doe / 36524 - doe / 146096) / 365;
        long long y = (long long)yoe + era * 400;
        unsigned doy = doe - (365 * yoe + yoe / 4 - yoe / 100);
        unsigned mp = (5 * doy + 2) / 153;
        unsigned d = doy - (153 * mp + 2) / 5 + 1;
        unsigned m = mp < 10 ? mp + 3 : mp - 9;
        _y = chrono::year((int)(y + (m <= 2)));
        _m = chrono::month(m);
        _d = chrono::day(d);
    }
    constexpr chrono::year year() const noexcept { return _y; }
    constexpr chrono::month month() const noexcept { return _m; }
    constexpr chrono::day day() const noexcept { return _d; }
    constexpr bool ok() const noexcept {
        return _y.ok() && _m.ok() && (unsigned)_d >= 1 && (unsigned)_d <= __last_day(_y, _m);
    }
    /* days_from_civil */
    constexpr operator sys_days() const noexcept {
        long long y = (int)_y;
        unsigned m = (unsigned)_m, d = (unsigned)_d;
        y -= m <= 2;
        long long era = (y >= 0 ? y : y - 399) / 400;
        unsigned yoe = (unsigned)(y - era * 400);
        unsigned doy = (153 * (m > 2 ? m - 3 : m + 9) + 2) / 5 + d - 1;
        unsigned doe = yoe * 365 + yoe / 4 - yoe / 100 + doy;
        return sys_days(days(era * 146097 + (long long)doe - 719468));
    }
private:
    chrono::year _y;
    chrono::month _m;
    chrono::day _d;
};

constexpr bool operator==(const year_month_day& a, const year_month_day& b) noexcept {
    return a.year() == b.year() && a.month() == b.month() && a.day() == b.day();
}
constexpr bool operator!=(const year_month_day& a, const year_month_day& b) noexcept { return !(a == b); }
constexpr bool operator<(const year_month_day& a, const year_month_day& b) noexcept {
    if (a.year() != b.year()) return a.year() < b.year();
    if (a.month() != b.month()) return a.month() < b.month();
    return a.day() < b.day();
}
constexpr bool operator<=(const year_month_day& a, const year_month_day& b) noexcept { return !(b < a); }
constexpr bool operator>(const year_month_day& a, const year_month_day& b) noexcept { return b < a; }
constexpr bool operator>=(const year_month_day& a, const year_month_day& b) noexcept { return !(a < b); }

constexpr year_month_day operator/(const year_month& ym, const day& d) noexcept { return year_month_day(ym.year(), ym.month(), d); }
constexpr year_month_day operator/(const year_month& ym, int d) noexcept { return ym / day((unsigned)d); }

/* the calendar fields of a tm, for strftime() */
inline tm __to_tm(const year_month_day& ymd) {
    tm t = {};
    t.tm_year = (int)ymd.year() - 1900;
    t.tm_mon = (int)(unsigned)ymd.month() - 1;
    t.tm_mday = (int)(unsigned)ymd.day();
    if (ymd.ok()) {
        long long dn = sys_days(ymd).time_since_epoch().count();
        t.tm_wday = (int)(dn >= -4 ? (dn + 4) % 7 : (dn + 5) % 7 + 6);
        t.tm_yday = (int)(dn - sys_days(year_month_day(ymd.year(), January, day(1))).time_since_epoch().count());
    }
    return t;
}

inline ostream& operator<<(ostream& os, const day& d) {
    char b[16];
    snprintf(b, sizeof b, "%02u", (unsigned)d);
    os << b;
    if (!d.ok()) os << " is not a valid day";
    return os;
}
inline ostream& operator<<(ostream& os, const month& m) {
    static const char* const n[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
                                      "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
    if (m.ok()) return os << n[(unsigned)m - 1];
    return os << (unsigned)m << " is not a valid month";
}
inline ostream& operator<<(ostream& os, const year& y) {
    char b[16];
    int v = (int)y;
    snprintf(b, sizeof b, v < 0 ? "-%04d" : "%04d", v < 0 ? -v : v);
    os << b;
    if (!y.ok()) os << " is not a valid year";
    return os;
}
inline ostream& operator<<(ostream& os, const year_month& ym) { return os << ym.year() << '/' << ym.month(); }
inline ostream& operator<<(ostream& os, const year_month_day& ymd) {
    char b[24];
    int v = (int)ymd.year();
    snprintf(b, sizeof b, v < 0 ? "-%04d-%02u-%02u" : "%04d-%02u-%02u", v < 0 ? -v : v,
             (unsigned)ymd.month(), (unsigned)ymd.day());
    os << b;
    if (!ymd.ok()) os << " is not a valid date";
    return os;
}

/* from_stream(is, fmt, x): parses through strptime() like parse() above
 * (whole words, UTC); on failure failbit is set and x keeps its value */
inline istream& from_stream(istream& is, const char* fmt, year_month_day& ymd,
                            string* abbrev = nullptr, minutes* offset = nullptr) {
    (void)abbrev; (void)offset;
    tm t;
    if (__parse_tm(is, fmt, t))
        ymd = year_month_day(year(t.tm_year + 1900), month((unsigned)t.tm_mon + 1), day((unsigned)t.tm_mday));
    return is;
}
template<class Duration>
istream& from_stream(istream& is, const char* fmt, sys_time<Duration>& tp,
                     string* abbrev = nullptr, minutes* offset = nullptr) {
    (void)abbrev; (void)offset;
    tm t;
    if (__parse_tm(is, fmt, t))
        tp = time_point_cast<Duration>(system_clock::from_time_t(timegm(&t)));
    return is;
}

}
}

/* std::formatter for sys_time and year_month_day (real gap: blogi's
 * std::format("{:%Y-%m-%d %T}", system_clock::now())). The chrono spec
 * is [[fill]align][width][.precision][L][%-conversions]; conversions go
 * through strftime() on the UTC calendar fields, except %S/%T, which
 * carry the sub-second digits of a finer-than-seconds Duration as the
 * standard has them, and %Z/%z, which are UTC. With no conversions,
 * sys_time formats as "%F %T" and year_month_day as "%F". */
#include <format>

namespace std __attribute__((__visibility__("default"))) {

namespace __format_detail {

    struct chrono_spec {
        spec s;
        string conv;   // the %-conversions, empty for the default
    };

    template<class ParseCtx>
    const char* parse_chrono_spec(const char* p, const char* end, chrono_spec& cs, ParseCtx& pc) {
        if (p == end || *p == '}') return p;
        size_t cl = utf8_len((unsigned char)*p);
        auto align_of = [](char c) {
            return c == '<' ? align_t::left : c == '>' ? align_t::right : c == '^' ? align_t::center : align_t::none;
        };
        if (p + cl < end && align_of(p[cl]) != align_t::none) {
            memcpy(cs.s.fill, p, cl); cs.s.fill[cl] = 0; cs.s.fill_len = cl;
            cs.s.align = align_of(p[cl]);
            p += cl + 1;
        } else if (align_of(*p) != align_t::none) {
            cs.s.align = align_of(*p);
            ++p;
        }
        if (p < end && *p == '{') { ++p; cs.s.width_arg = parse_arg_ref(p, end, pc); }
        else if (p < end && is_digit(*p)) {
            int w = 0;
            while (p < end && is_digit(*p)) w = w * 10 + (*p++ - '0');
            cs.s.width = w;
        }
        if (p < end && *p == '.') {
            ++p;
            if (p < end && *p == '{') { ++p; cs.s.prec_arg = parse_arg_ref(p, end, pc); }
            else while (p < end && is_digit(*p)) ++p;
        }
        if (p < end && *p == 'L') ++p;
        const char* b = p;
        while (p < end && *p != '}') {
            if (*p == '{') fail("invalid chrono format spec");
            if (*p == '%' && ++p == end) fail("incomplete chrono conversion");
            ++p;
        }
        if (b != p && *b != '%') fail("chrono format spec must start with '%'");
        cs.conv.assign(b, (size_t)(p - b));
        return p;
    }

    /* expands conv for the calendar fields t; sub is the sub-second
     * part ("" for none, else ".123..."), has_time whether %H etc. are
     * meaningful for this argument */
    inline string chrono_expand(const string& conv, const tm& t, const string& sub, bool has_time) {
        string r;
        char buf[128];
        for (size_t i = 0; i < conv.size(); i++) {
            char c = conv[i];
            if (c != '%') { r += c; continue; }
            c = conv[++i];
            if (c == 'E' || c == 'O') c = conv[++i];   // no alternative representations
            switch (c) {
                case '%': r += '%'; continue;
                case 'n': r += '\n'; continue;
                case 't': r += '\t'; continue;
                case 'Z': r += "UTC"; continue;
                case 'z': r += conv[i - 1] == 'E' || conv[i - 1] == 'O' ? "+00:00" : "+0000"; continue;
                case 'H': case 'I': case 'M': case 'S': case 'T': case 'R': case 'p': case 'r': case 'X': case 'c':
                    if (!has_time) fail("chrono format spec asks for the time of a date");
                    break;
            }
            if (c == 'S' || c == 'T') {
                snprintf(buf, sizeof buf, c == 'S' ? "%02d" : "%02d:%02d:%02d",
                         c == 'S' ? t.tm_sec : t.tm_hour, t.tm_min, t.tm_sec);
                r += buf;
                r += sub;
                continue;
            }
            char f[3] = {'%', c, 0};
            size_t n = strftime(buf, sizeof buf, f, &t);
            r.append(buf, n);
        }
        return r;
    }

    /* decimal digits of the sub-second part of a Duration: as many as
     * its period needs, if exact within 18, else 6 (the standard's rule) */
    template<class Period>
    constexpr int subsecond_digits() {
        long long a = Period::num, b = Period::den;
        while (b) { long long t = a % b; a = b; b = t; }
        long long den = Period::den / a;
        if (den == 1) return 0;
        long long p = 1;
        for (int n = 1; n <= 18; n++) {
            p *= 10;
            if (p % den == 0) return n;
        }
        return 6;
    }

    template<class Ctx>
    typename Ctx::iterator write_chrono(Ctx& fc, chrono_spec cs, const string& body) {
        resolve(cs.s, fc);
        auto out = write_padded(fc.out(), cs.s, body.data(), body.size(), align_t::left);
        fc.advance_to(out);
        return fc.out();
    }

} // namespace __format_detail

template<class Duration>
struct formatter<chrono::time_point<chrono::system_clock, Duration>, char> {
    __format_detail::chrono_spec _cs;
    constexpr format_parse_context::iterator parse(format_parse_context& pc) {
        return __format_detail::parse_chrono_spec(pc.begin(), pc.end(), _cs, pc);
    }
    template<class Ctx>
    typename Ctx::iterator format(const chrono::time_point<chrono::system_clock, Duration>& tp, Ctx& fc) const {
        typedef typename Duration::period P;
        /* exact integer split into days, seconds of the day and the
         * sub-second remainder (duration_cast goes through double for
         * nanoseconds -> days) */
        __int128 tot = (__int128)(long long)tp.time_since_epoch().count() * P::num;   // 1/den seconds
        __int128 secs = tot / P::den;
        if (secs * P::den > tot) secs--;
        __int128 rem = tot - secs * P::den;
        long long dn = (long long)(secs / 86400);
        if ((__int128)dn * 86400 > secs) dn--;
        long long sod = (long long)(secs - (__int128)dn * 86400);
        tm t = chrono::__to_tm(chrono::year_month_day(chrono::sys_days(chrono::days(dn))));
        t.tm_hour = (int)(sod / 3600);
        t.tm_min = (int)(sod / 60 % 60);
        t.tm_sec = (int)(sod % 60);
        string sub;
        constexpr int digits = __format_detail::subsecond_digits<P>();
        if constexpr (digits > 0) {
            __int128 scale = 1;
            for (int i = 0; i < digits; i++) scale *= 10;
            char buf[24];
            snprintf(buf, sizeof buf, ".%0*lld", digits, (long long)(rem * scale / P::den));
            sub = buf;
        }
        return __format_detail::write_chrono(fc, _cs,
            __format_detail::chrono_expand(_cs.conv.empty() ? string("%F %T") : _cs.conv, t, sub, true));
    }
};

template<>
struct formatter<chrono::year_month_day, char> {
    __format_detail::chrono_spec _cs;
    constexpr format_parse_context::iterator parse(format_parse_context& pc) {
        return __format_detail::parse_chrono_spec(pc.begin(), pc.end(), _cs, pc);
    }
    template<class Ctx>
    typename Ctx::iterator format(const chrono::year_month_day& ymd, Ctx& fc) const {
        tm t = chrono::__to_tm(ymd);
        return __format_detail::write_chrono(fc, _cs,
            __format_detail::chrono_expand(_cs.conv.empty() ? string("%F") : _cs.conv, t, string(), false));
    }
};

}
+5 −0

File changed.

Preview size limit exceeded, changes collapsed.

+24 −0

File changed.

Preview size limit exceeded, changes collapsed.

+116 −0

File added.

Preview size limit exceeded, changes collapsed.