Document number: P0092R0


Howard E. Hinnant
2015-09-23

Polishing <chrono>

Contents

Introduction

This paper proposes a few minor additions to the chrono library to make it easier to use and more uniform:

These are minor additions that make chrono easier to use. They have been implemented and used for years. They should have been part of the original chrono proposal for C++11, but simply slipped through the cracks by no one's fault but my own.

The rounding modes differ from duration_cast and time_point_cast in that these existing rounding functions truncate towards zero: downwards for postive values and upwards for negative values.

Implementation

The implementation is shown below for the utility functions. This presentation is meant to:

This implementation is consistent with that which has been up on my personal website for years.

namespace std { namespace chrono {

namespace detail
{

template <class T>
struct is_duration
    : public false_type
    {};

template <class Rep, class Period>
struct is_duration<duration<Rep, Period>>
    : public true_type
    {};

}  // namespace detail

template <class To, class Rep, class Period,
          class = enable_if_t<detail::is_duration<To>{}>>
constexpr
To
floor(const duration<Rep, Period>& d)
{
    To t = duration_cast<To>(d);
    if (t > d)
        --t;
    return t;
}

template <class To, class Rep, class Period,
          class = enable_if_t<detail::is_duration<To>{}>>
constexpr
To
ceil(const duration<Rep, Period>& d)
{
    To t = duration_cast<To>(d);
    if (t < d)
        ++t;
    return t;
}

template <class To, class Rep, class Period,
          class = enable_if_t<detail::is_duration<To>{}
             && !treat_as_floating_point<typename To::rep>{}>>
constexpr
To
round(const duration<Rep, Period>& d)
{
    To t0 = floor<To>(d);
    To t1 = t0 + To{1};
    auto diff0 = d - t0;
    auto diff1 = t1 - d;
    if (diff0 == diff1)
    {
        if (t0.count() & 1)
            return t1;
        return t0;
    }
    else if (diff0 < diff1)
        return t0;
    return t1;
}

template <class To, class Clock, class FromDuration,
          class = enable_if_t<detail::is_duration<To>{}>>
constexpr
time_point<Clock, To>
floor(const time_point<Clock, FromDuration>& tp)
{
    return time_point<Clock, To>{floor<To>(tp.time_since_epoch())};
}

template <class To, class Clock, class FromDuration,
          class = enable_if_t<detail::is_duration<To>{}>>
constexpr
time_point<Clock, To>
ceil(const time_point<Clock, FromDuration>& tp)
{
    return time_point<Clock, To>{ceil<To>(tp.time_since_epoch())};
}

template <class To, class Clock, class FromDuration,
          class = enable_if_t<detail::is_duration<To>{}
             && !treat_as_floating_point<typename To::rep>{}>>
constexpr
time_point<Clock, To>
round(const time_point<Clock, FromDuration>& tp)
{
    return time_point<Clock, To>{round<To>(tp.time_since_epoch())};
}

template <class Rep, class Period,
          class = enable_if_t
          <
              duration<Rep, Period>::min() < duration<Rep, Period>::zero()
          > >
constexpr
duration<Rep, Period>
abs(duration<Rep, Period> d)
{
    return d >= d.zero() ? d : -d;
}

} }  // namespace std::chrono

Wording