mirror of
https://github.com/HowardHinnant/date.git
synced 2024-12-27 08:31:03 +08:00
Add support down to femtosecond precision
* Requires platform specific use of 128bit integral representation (e.g. std::chrono::duration<__int128_t, std::femto>).
This commit is contained in:
parent
5f01382e24
commit
481771ef5e
130
date.h
130
date.h
@ -1014,18 +1014,86 @@ trunc(T t) NOEXCEPT
|
||||
return t;
|
||||
}
|
||||
|
||||
template <std::intmax_t Xp, std::intmax_t Yp>
|
||||
struct static_gcd
|
||||
{
|
||||
static const std::intmax_t value = static_gcd<Yp, Xp % Yp>::value;
|
||||
};
|
||||
|
||||
template <std::intmax_t Xp>
|
||||
struct static_gcd<Xp, 0>
|
||||
{
|
||||
static const std::intmax_t value = Xp;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct static_gcd<0, 0>
|
||||
{
|
||||
static const std::intmax_t value = 1;
|
||||
};
|
||||
|
||||
template <class R1, class R2>
|
||||
struct no_overflow
|
||||
{
|
||||
private:
|
||||
static const std::intmax_t gcd_n1_n2 = static_gcd<R1::num, R2::num>::value;
|
||||
static const std::intmax_t gcd_d1_d2 = static_gcd<R1::den, R2::den>::value;
|
||||
static const std::intmax_t n1 = R1::num / gcd_n1_n2;
|
||||
static const std::intmax_t d1 = R1::den / gcd_d1_d2;
|
||||
static const std::intmax_t n2 = R2::num / gcd_n1_n2;
|
||||
static const std::intmax_t d2 = R2::den / gcd_d1_d2;
|
||||
static const std::intmax_t max = -((std::intmax_t(1) <<
|
||||
(sizeof(std::intmax_t) * CHAR_BIT - 1)) + 1);
|
||||
|
||||
template <std::intmax_t Xp, std::intmax_t Yp, bool overflow>
|
||||
struct mul // overflow == false
|
||||
{
|
||||
static const std::intmax_t value = Xp * Yp;
|
||||
};
|
||||
|
||||
template <std::intmax_t Xp, std::intmax_t Yp>
|
||||
struct mul<Xp, Yp, true>
|
||||
{
|
||||
static const std::intmax_t value = 1;
|
||||
};
|
||||
|
||||
public:
|
||||
static const bool value = (n1 <= max / d2) && (n2 <= max / d1);
|
||||
typedef std::ratio<mul<n1, d2, !value>::value,
|
||||
mul<n2, d1, !value>::value> type;
|
||||
};
|
||||
|
||||
} // detail
|
||||
|
||||
// trunc towards zero
|
||||
template <class To, class Rep, class Period>
|
||||
CONSTCD11
|
||||
inline
|
||||
To
|
||||
typename std::enable_if
|
||||
<
|
||||
detail::no_overflow<Period, typename To::period>::value,
|
||||
To
|
||||
>::type
|
||||
trunc(const std::chrono::duration<Rep, Period>& d)
|
||||
{
|
||||
return To{detail::trunc(std::chrono::duration_cast<To>(d).count())};
|
||||
}
|
||||
|
||||
template <class To, class Rep, class Period>
|
||||
CONSTCD11
|
||||
inline
|
||||
typename std::enable_if
|
||||
<
|
||||
!detail::no_overflow<Period, typename To::period>::value,
|
||||
To
|
||||
>::type
|
||||
trunc(const std::chrono::duration<Rep, Period>& d)
|
||||
{
|
||||
using namespace std::chrono;
|
||||
using rep = typename std::common_type<Rep, typename To::rep>::type;
|
||||
return To{detail::trunc(duration_cast<To>(duration_cast<duration<rep>>(d)).count())};
|
||||
}
|
||||
|
||||
#ifndef HAS_CHRONO_ROUNDING
|
||||
# if defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 190023918
|
||||
# define HAS_CHRONO_ROUNDING 1
|
||||
@ -1044,7 +1112,11 @@ trunc(const std::chrono::duration<Rep, Period>& d)
|
||||
template <class To, class Rep, class Period>
|
||||
CONSTCD14
|
||||
inline
|
||||
To
|
||||
typename std::enable_if
|
||||
<
|
||||
detail::no_overflow<Period, typename To::period>::value,
|
||||
To
|
||||
>::type
|
||||
floor(const std::chrono::duration<Rep, Period>& d)
|
||||
{
|
||||
auto t = trunc<To>(d);
|
||||
@ -1053,6 +1125,21 @@ floor(const std::chrono::duration<Rep, Period>& d)
|
||||
return t;
|
||||
}
|
||||
|
||||
template <class To, class Rep, class Period>
|
||||
CONSTCD14
|
||||
inline
|
||||
typename std::enable_if
|
||||
<
|
||||
!detail::no_overflow<Period, typename To::period>::value,
|
||||
To
|
||||
>::type
|
||||
floor(const std::chrono::duration<Rep, Period>& d)
|
||||
{
|
||||
using namespace std::chrono;
|
||||
using rep = typename std::common_type<Rep, typename To::rep>::type;
|
||||
return floor<To>(floor<duration<rep>>(d));
|
||||
}
|
||||
|
||||
// round to nearest, to even on tie
|
||||
template <class To, class Rep, class Period>
|
||||
CONSTCD14
|
||||
@ -3494,18 +3581,18 @@ struct static_pow10<0>
|
||||
static CONSTDATA std::uint64_t value = 1;
|
||||
};
|
||||
|
||||
template <unsigned w, bool in_range = (w < 19)>
|
||||
template <class Rep, unsigned w, bool in_range = (w < 19)>
|
||||
struct make_precision
|
||||
{
|
||||
using type = std::chrono::duration<std::int64_t,
|
||||
using type = std::chrono::duration<Rep,
|
||||
std::ratio<1, static_pow10<w>::value>>;
|
||||
static CONSTDATA unsigned width = w;
|
||||
};
|
||||
|
||||
template <unsigned w>
|
||||
struct make_precision<w, false>
|
||||
template <class Rep, unsigned w>
|
||||
struct make_precision<Rep, w, false>
|
||||
{
|
||||
using type = std::chrono::microseconds;
|
||||
using type = std::chrono::duration<Rep, std::micro>;
|
||||
static CONSTDATA unsigned width = 6;
|
||||
};
|
||||
|
||||
@ -3516,8 +3603,9 @@ template <class Duration,
|
||||
class decimal_format_seconds
|
||||
{
|
||||
public:
|
||||
using precision = typename make_precision<w>::type;
|
||||
static auto CONSTDATA width = make_precision<w>::width;
|
||||
using rep = typename std::common_type<Duration, std::chrono::seconds>::type::rep;
|
||||
using precision = typename make_precision<rep, w>::type;
|
||||
static auto CONSTDATA width = make_precision<rep, w>::width;
|
||||
|
||||
private:
|
||||
std::chrono::seconds s_;
|
||||
@ -3561,7 +3649,7 @@ public:
|
||||
os << x.s_.count() <<
|
||||
std::use_facet<std::numpunct<char>>(os.getloc()).decimal_point();
|
||||
os.width(width);
|
||||
os << x.sub_s_.count();
|
||||
os << static_cast<std::int64_t>(x.sub_s_.count());
|
||||
return os;
|
||||
}
|
||||
};
|
||||
@ -3571,8 +3659,9 @@ class decimal_format_seconds<Duration, 0>
|
||||
{
|
||||
static CONSTDATA unsigned w = 0;
|
||||
public:
|
||||
using precision = std::chrono::seconds;
|
||||
static auto CONSTDATA width = make_precision<w>::width;
|
||||
using rep = typename std::common_type<Duration, std::chrono::seconds>::type::rep;
|
||||
using precision = std::chrono::duration<rep>;
|
||||
static auto CONSTDATA width = make_precision<rep, w>::width;
|
||||
private:
|
||||
|
||||
std::chrono::seconds s_;
|
||||
@ -4032,9 +4121,9 @@ public:
|
||||
{}
|
||||
|
||||
CONSTCD11 explicit time_of_day_storage(Duration since_midnight) NOEXCEPT
|
||||
: base(std::chrono::duration_cast<std::chrono::hours>(since_midnight),
|
||||
: base(date::trunc<std::chrono::hours>(since_midnight),
|
||||
since_midnight < Duration{0}, is24hr)
|
||||
, m_(std::chrono::duration_cast<std::chrono::minutes>(detail::abs(since_midnight) - h_))
|
||||
, m_(date::trunc<std::chrono::minutes>(detail::abs(since_midnight) - h_))
|
||||
, s_(detail::abs(since_midnight) - h_ - m_)
|
||||
{}
|
||||
|
||||
@ -5513,7 +5602,7 @@ to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
|
||||
{
|
||||
using CT = typename std::common_type<Duration, std::chrono::seconds>::type;
|
||||
auto ld = floor<days>(tp);
|
||||
fields<CT> fds{year_month_day{ld}, time_of_day<CT>{tp-ld}};
|
||||
fields<CT> fds{year_month_day{ld}, time_of_day<CT>{tp-local_seconds{ld}}};
|
||||
return to_stream(os, fmt, fds, abbrev, offset_sec);
|
||||
}
|
||||
|
||||
@ -5522,11 +5611,12 @@ std::basic_ostream<CharT, Traits>&
|
||||
to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
|
||||
const sys_time<Duration>& tp)
|
||||
{
|
||||
using CT = typename std::common_type<Duration, std::chrono::seconds>::type;
|
||||
using namespace std::chrono;
|
||||
using CT = typename std::common_type<Duration, seconds>::type;
|
||||
const std::string abbrev("UTC");
|
||||
CONSTDATA std::chrono::seconds offset{0};
|
||||
CONSTDATA seconds offset{0};
|
||||
auto sd = floor<days>(tp);
|
||||
fields<CT> fds{year_month_day{sd}, time_of_day<CT>{tp-sd}};
|
||||
fields<CT> fds{year_month_day{sd}, time_of_day<CT>{tp-sys_seconds{sd}}};
|
||||
return to_stream(os, fmt, fds, &abbrev, &offset);
|
||||
}
|
||||
|
||||
@ -7033,7 +7123,7 @@ from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
|
||||
if (!fds.ymd.ok() || !fds.tod.in_conventional_range())
|
||||
is.setstate(ios::failbit);
|
||||
if (!is.fail())
|
||||
tp = round<Duration>(sys_days(fds.ymd) + fds.tod.to_duration() - *offptr);
|
||||
tp = round<Duration>(sys_days(fds.ymd) - *offptr + fds.tod.to_duration());
|
||||
return is;
|
||||
}
|
||||
|
||||
@ -7051,7 +7141,7 @@ from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
|
||||
if (!fds.ymd.ok() || !fds.tod.in_conventional_range())
|
||||
is.setstate(ios::failbit);
|
||||
if (!is.fail())
|
||||
tp = round<Duration>(local_days(fds.ymd) + fds.tod.to_duration());
|
||||
tp = round<Duration>(local_seconds{local_days(fds.ymd)} + fds.tod.to_duration());
|
||||
return is;
|
||||
}
|
||||
|
||||
|
@ -94,7 +94,7 @@ main()
|
||||
{
|
||||
using D = decimal_format_seconds<milliseconds>;
|
||||
static_assert(D::width == 3, "");
|
||||
static_assert(is_same<D::precision, make_precision<D::width>::type>{}, "");
|
||||
static_assert(is_same<D::precision, make_precision<D::rep, D::width>::type>{}, "");
|
||||
D dfs{seconds{3}};
|
||||
assert(dfs.seconds() == seconds{3});
|
||||
assert(dfs.to_duration() == seconds{3});
|
||||
@ -106,7 +106,7 @@ main()
|
||||
{
|
||||
using D = decimal_format_seconds<milliseconds>;
|
||||
static_assert(D::width == 3, "");
|
||||
static_assert(is_same<D::precision, make_precision<D::width>::type>{}, "");
|
||||
static_assert(is_same<D::precision, make_precision<D::rep, D::width>::type>{}, "");
|
||||
D dfs{milliseconds{3}};
|
||||
assert(dfs.seconds() == seconds{0});
|
||||
assert(dfs.to_duration() == milliseconds{3});
|
||||
@ -118,7 +118,7 @@ main()
|
||||
{
|
||||
using D = decimal_format_seconds<microfortnights>;
|
||||
static_assert(D::width == 4, "");
|
||||
using S = make_precision<D::width>::type;
|
||||
using S = make_precision<D::rep, D::width>::type;
|
||||
static_assert(is_same<D::precision, S>{}, "");
|
||||
D dfs{microfortnights{3}};
|
||||
assert(dfs.seconds() == seconds{3});
|
||||
@ -132,7 +132,7 @@ main()
|
||||
using CT = common_type<seconds, microfortnights>::type;
|
||||
using D = decimal_format_seconds<CT>;
|
||||
static_assert(D::width == 4, "");
|
||||
using S = make_precision<D::width>::type;
|
||||
using S = make_precision<D::rep, D::width>::type;
|
||||
static_assert(is_same<D::precision, S>{}, "");
|
||||
D dfs{microfortnights{3}};
|
||||
assert(dfs.seconds() == seconds{3});
|
||||
|
@ -40,24 +40,24 @@ main()
|
||||
using namespace std;
|
||||
using namespace std::chrono;
|
||||
|
||||
static_assert(make_precision<0>::width == 0, "");
|
||||
static_assert(is_same<make_precision<0>::type, duration<int64_t, ratio<1, 1>>>{}, "");
|
||||
static_assert(make_precision<int64_t, 0>::width == 0, "");
|
||||
static_assert(is_same<make_precision<int64_t, 0>::type, duration<int64_t, ratio<1, 1>>>{}, "");
|
||||
|
||||
static_assert(make_precision<1>::width == 1, "");
|
||||
static_assert(is_same<make_precision<1>::type, duration<int64_t, ratio<1, 10>>>{}, "");
|
||||
static_assert(make_precision<int64_t, 1>::width == 1, "");
|
||||
static_assert(is_same<make_precision<int64_t, 1>::type, duration<int64_t, ratio<1, 10>>>{}, "");
|
||||
|
||||
static_assert(make_precision<2>::width == 2, "");
|
||||
static_assert(is_same<make_precision<2>::type, duration<int64_t, ratio<1, 100>>>{}, "");
|
||||
static_assert(make_precision<int64_t, 2>::width == 2, "");
|
||||
static_assert(is_same<make_precision<int64_t, 2>::type, duration<int64_t, ratio<1, 100>>>{}, "");
|
||||
|
||||
static_assert(make_precision<3>::width == 3, "");
|
||||
static_assert(is_same<make_precision<3>::type, duration<int64_t, ratio<1, 1000>>>{}, "");
|
||||
static_assert(make_precision<int64_t, 3>::width == 3, "");
|
||||
static_assert(is_same<make_precision<int64_t, 3>::type, duration<int64_t, ratio<1, 1000>>>{}, "");
|
||||
|
||||
static_assert(make_precision<18>::width == 18, "");
|
||||
static_assert(is_same<make_precision<18>::type, duration<int64_t, ratio<1, 1000000000000000000>>>{}, "");
|
||||
static_assert(make_precision<int64_t, 18>::width == 18, "");
|
||||
static_assert(is_same<make_precision<int64_t, 18>::type, duration<int64_t, ratio<1, 1000000000000000000>>>{}, "");
|
||||
|
||||
static_assert(make_precision<19>::width == 6, "");
|
||||
static_assert(is_same<make_precision<19>::type, microseconds>{}, "");
|
||||
static_assert(make_precision<int64_t, 19>::width == 6, "");
|
||||
static_assert(is_same<make_precision<int64_t, 19>::type, microseconds>{}, "");
|
||||
|
||||
static_assert(make_precision<20>::width == 6, "");
|
||||
static_assert(is_same<make_precision<20>::type, microseconds>{}, "");
|
||||
static_assert(make_precision<int64_t, 20>::width == 6, "");
|
||||
static_assert(is_same<make_precision<int64_t, 20>::type, microseconds>{}, "");
|
||||
}
|
||||
|
23
tz.h
23
tz.h
@ -1913,7 +1913,7 @@ to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
|
||||
auto tp = sys_time<CT>{t.time_since_epoch() - ls.second};
|
||||
auto const sd = floor<days>(tp);
|
||||
year_month_day ymd = sd;
|
||||
auto time = make_time(tp - sd);
|
||||
auto time = make_time(tp - sys_seconds{sd});
|
||||
time.seconds() += seconds{ls.first};
|
||||
fields<CT> fds{ymd, time};
|
||||
return to_stream(os, fmt, fds, &abbrev, &offset);
|
||||
@ -1947,7 +1947,7 @@ from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
|
||||
bool is_60_sec = fds.tod.seconds() == seconds{60};
|
||||
if (is_60_sec)
|
||||
fds.tod.seconds() -= seconds{1};
|
||||
auto tmp = to_utc_time(sys_days(fds.ymd) + (fds.tod.to_duration() - *offptr));
|
||||
auto tmp = to_utc_time(sys_days(fds.ymd) - *offptr + fds.tod.to_duration());
|
||||
if (is_60_sec)
|
||||
tmp += seconds{1};
|
||||
if (is_60_sec != is_leap_second(tmp).first || !fds.tod.in_conventional_range())
|
||||
@ -2028,10 +2028,10 @@ to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
|
||||
const string abbrev("TAI");
|
||||
CONSTDATA seconds offset{0};
|
||||
auto tp = sys_time<CT>{t.time_since_epoch()} -
|
||||
(sys_days(year{1970}/jan/1) - sys_days(year{1958}/jan/1));
|
||||
seconds(sys_days(year{1970}/jan/1) - sys_days(year{1958}/jan/1));
|
||||
auto const sd = floor<days>(tp);
|
||||
year_month_day ymd = sd;
|
||||
auto time = make_time(tp - sd);
|
||||
auto time = make_time(tp - sys_seconds{sd});
|
||||
fields<CT> fds{ymd, time};
|
||||
return to_stream(os, fmt, fds, &abbrev, &offset);
|
||||
}
|
||||
@ -2062,8 +2062,9 @@ from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
|
||||
is.setstate(ios::failbit);
|
||||
if (!is.fail())
|
||||
tp = tai_time<Duration>{duration_cast<Duration>(
|
||||
(sys_days(fds.ymd) + fds.tod.to_duration() + (sys_days(year{1970}/jan/1) -
|
||||
sys_days(year{1958}/jan/1)) - *offptr).time_since_epoch())};
|
||||
(sys_days(fds.ymd) +
|
||||
(sys_days(year{1970}/jan/1) - sys_days(year{1958}/jan/1)) -
|
||||
*offptr + fds.tod.to_duration()).time_since_epoch())};
|
||||
return is;
|
||||
}
|
||||
|
||||
@ -2135,10 +2136,10 @@ to_stream(std::basic_ostream<CharT, Traits>& os, const CharT* fmt,
|
||||
const string abbrev("GPS");
|
||||
CONSTDATA seconds offset{0};
|
||||
auto tp = sys_time<CT>{t.time_since_epoch()} +
|
||||
(sys_days(year{1980}/jan/sun[1]) - sys_days(year{1970}/jan/1));
|
||||
seconds(sys_days(year{1980}/jan/sun[1]) - sys_days(year{1970}/jan/1));
|
||||
auto const sd = floor<days>(tp);
|
||||
year_month_day ymd = sd;
|
||||
auto time = make_time(tp - sd);
|
||||
auto time = make_time(tp - sys_seconds{sd});
|
||||
fields<CT> fds{ymd, time};
|
||||
return to_stream(os, fmt, fds, &abbrev, &offset);
|
||||
}
|
||||
@ -2169,9 +2170,9 @@ from_stream(std::basic_istream<CharT, Traits>& is, const CharT* fmt,
|
||||
is.setstate(ios::failbit);
|
||||
if (!is.fail())
|
||||
tp = gps_time<Duration>{duration_cast<Duration>(
|
||||
(sys_days(fds.ymd) + fds.tod.to_duration() -
|
||||
(sys_days(year{1980}/jan/sun[1]) -
|
||||
sys_days(year{1970}/jan/1)) - *offptr).time_since_epoch())};
|
||||
(sys_days(fds.ymd) -
|
||||
(sys_days(year{1980}/jan/sun[1]) - sys_days(year{1970}/jan/1)) -
|
||||
*offptr + fds.tod.to_duration()).time_since_epoch())};
|
||||
return is;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user