Document number: N2661=08-0171

Howard E. Hinnant
Walter E. Brown
Jeff Garland
Marc Paterno
2008-06-11

A Foundation to Sleep On

Clocks, Points in Time, and Time Durations

Contents

Introduction

We all deal with time every day of our lives. We've intuitively known it since birth. Thus we are all very familiar with it and believe it to be a simple matter. The modeling of time in computer programs should be similarly simple.

The unfortunate truth is that this perceived simplicity is only skin deep. Fortunately however, we do not need a terribly complicated solution to meet the bulk of our needs. However, overly simplistic solutions are fraught with danger, inherent inefficiency, and lack the ability to adapt as the computer industry evolves over decades.

A Brief History of Time

(With apologies to Stephen Hawking)

The C library has had basic time facilities for several decades. It contains both the notion of a point in time, and the time duration between two points in time. It also has a clock to get the current time (point).

// A type capable of representing a point in time.
time_t

// A function returning a time duration between two points in time.
double difftime(time_t t1, time_t t2);

// A function returning the current point in time.
time_t time(time_t*);

The C library also contains functions relating points in time to the Gregorian calendar, and for performing I/O with points in time.

For a time point to have meaning, one must be able relate or compare two time points. This generally requires an epoch which is simply a special point in time against which all other points in time relate themselves to. Without an epoch (or common reference) it becomes impossible to compare two points in time. However to compare two points in time, all one needs to know is that they share the same epoch. Knowledge of when that epoch is, isn't needed.

The C committee decided to not specify the epoch to which time_t is measured against, nor the precision it is measured with. The advantage of this is that platforms can more easily change the definition of the epoch since no code can portably depend on exactly when it was. If a process needs to import or export a point in time with another process, it must first relate the point in time to an agreed upon epoch, such as that used by the Gregorian calendar.

POSIX specified time_t to represent seconds, and over the decades it has become common for time_t to be a signed 32 bit integral type which is simply a count of seconds since New Years 1970. De-facto standardizing on this definition has created some serious problems:

One solution to the time_t problem is to simply extend it to a signed 64 bit integer. This would get rid the of the range problem forever (for all practical purposes). However, the precision problem remains.

POSIX first published a solution to the precision problem with a new clock to get "now", and a new representation:

struct timeb
{
    time_t time;             // seconds
    unsigned short millitm;  // milliseconds
};

int ftime(struct timeb *tp);

This function is currently marked LEGACY in the POSIX documentation.

Next came a new clock, and a new structure with microsecond precision:

struct timeval
{
    time_t tv_sec;             // seconds
    int_least20_t tv_usec;     // microseconds
};

int gettimeofday(struct timeval *restrict tp, void *restrict tzp);

This function is still in wide use today on many platforms. However, it is not the end of the line. POSIX later released a new clock, and a new structure. This new function actually supports multiple clocks and has nanosecond precision.

struct timespec
{
    time_t tv_sec;    // seconds
    long tv_nsec;     // nanoseconds
};

int clock_gettime(clockid_t, struct timespec *);

In summary, there has been a progression of C interfaces (outside of the C standard) with precisions of second, millisecond, microsecond and nanosecond. Each requires a new interface, both for the structural representation, and for its associated clock to find the current point in time.

Is nanosecond precision the end of the line? Every computer Apple currently ships, has a monotonic clock which reports the current time point in units of a single nanosecond. Most of these machines have a cpu clock speed at or above 2GHz. The amount of time between two ticks of a 2GHz clock is only one half of a nanosecond (500 picoseconds).

The future is always hard to predict. However, over the next 10 to 20 years, should the need arise to traffic in time durations finer than nanosecond, we would not be surprised. We are already bumping up against 1 nanosecond precision.

Should the C++ committee standardize a time point / time duration representation with nanosecond precision now? And be prepared to standardize yet another representation with finer precision 10 (or even 5) years from now? In the long run, is such a plan really simple? Or does it just seem so when we only have to worry about nanoseconds today?

This paper proposes a solution that is precision neutral.

Goals

C++ offers unique opportunities in the representation of time. Other languages have had to address this problem as well. But none of them had the tools which C++ has which can be put to use in the solution of this problem. The C++0x standard library's multi-threading library requires the ability to deal with the representation of time in a manner consistent with modern C++ practices. This paper proposes a solution to both the standard library need and C++ user needs with a very simple end user interface which supports multiple clocks, multiple precisions (both coarser and finer than we will ever need), separate types for points in time and time durations, efficiency, and compile time enforced safety.

In addition to the clocks provided by the proposal, users can easily create their own clocks, with both points in time and time durations which have a representation and precision of their own choosing. For example if there is a hardware counter which simply increments a count with each cycle of the cpu, one can very easily build clocks, time points and durations on top of that, using only a few tens of lines of code. Such systems can be used to call the time-sensitive threading API's such as sleep, wait on a condition variable, or wait for a mutex lock. The API proposed herein is not sensitive as to whether this is a 300MHz clock (with a 313 nanosecond tick period) or a 3GHz clock (with a tick period of  13 of a nanosecond). And the resulting code will be just as efficient as if the user wrote a special purpose clock cycle counter.

Overview

Additionally, a minimal amount of general purpose infrastructure is proposed which will support both the interface and implementation of the clocks, time_points and durations proposed herein. It is expected that these general purpose facilities will also find utility in far ranging user applications as well.

Sold Separately

This paper does not offer calendrical services except for a minimal mapping to and from C's time_t.

As this paper does not propose a date/time library, nor specify epochs, it also does not address leap seconds. However, a date/time library will find this to be an excellent foundation on which to build.

This paper does not propose a general purpose physical quantities library.

This paper proposes a solid foundation that, in the future, could provide a compatible starting point for a general physical units library. While such a future library might take any of several forms, the present proposal stops well short of actually being a physical units library. This proposal is time-specific, and continues to be motivated by the time-related needs of the threading library.

The major goal of this proposal is to satisfy the needs of the standard library threading API in a manner which is easy to use, safe to use, efficient, and flexible enough to not be obsolete 10 or even 100 years from now. Every feature contained in this proposal is here for a specific reason with practical use cases as motivation. Things that fell into the category of "cool", or "that sounds like it might be useful", or "very useful but not needed by this interface" have not been included. Such items might appear in other proposals, and possibly target a TR.

Impact on existing code

The proposal is entirely an add-on. It will break no existing C++03 code, subject to the usual caveat that user code giving a using namespace std may see name clashes. Even that possibility is mitigated because the time portion of the proposal is in a std sub-namespace.

common_type

common_type has been a recurring theme in many places for many years. We've previously known it as promote and examples of it are spread throughout boost. It has been reinvented independently several times, because it is so useful.

Andrei Alexandrescu recently pointed us at a D library: std.traits - D Programming Language - Digital Mars, which became the motivation for this particular name, and the variadic nature of this trait.

In a nutshell, common_type is a trait that takes 1 or more types, and returns a type which all of the types will convert to. The default definition demands this conversion be implicit. However the trait can be specialized for user-defined types which want to limit their inter-type conversions to explicit, and yet still want to interoperate with the common_type facility.

Example:

template <class T, class U>
typename common_type<complex<T>, complex<U>>::type
operator+(complex<T>, complex<U>);

In the above example, "mixed-mode" complex arithmetic is allowed. The return type is described by common_type. For example the resulting type of adding a complex<int> and complex<double> might be a complex<double>. Another choice for the author might be:

template <class T, class U>
complex<typename common_type<T, U>::type>
operator+(complex<T>, complex<U>);

Here is how someone might produce a variadic comparison function:

template <class ...T>
typename common_type<T...>::type
min(T... t);

This is a very useful and broadly applicable utility. The duration and time_point facilities use it to make multi-precision arithmetic seamless and exact.

The cost of not including common_type is that it is very likely that the implementation would include it anyway, but spell it __common_type instead. This would prevent authors of arithmetic emulators from using their classes as representations with durations unless the emulator had exactly one implicit conversion to or from an arithmetic type. This would be a large loss of functionality from the user's point of view, possibly mandating a less safe interface for the user's arithmetic emulator.

common_type Proposed Wording

Insert into 20.4.2 [meta.type.synop]

template <class ...T> struct common_type;

Modify 20.4.2 [meta.type.synop] paragraph 1:

The behavior of a program that adds specializations for any of the class templates defined in this subclause is undefined unless otherwise specified.

Add a row to 20.4.7 [meta.trans.other]:

template <class ...T> struct common_type;

template <class T>
struct common_type<T>
{
    typedef T type;
};

template <class T, class U>
struct common_type<T, U>
{
private:
    static T&& t();
    static U&& u();
public:
    typedef decltype(true ? t() : u()) type;
};

template <class T, class U, class ...V>
struct common_type<T, U, V...>
{
    typedef typename common_type<typename common_type<T, U>::type, V...>::type type;
};

All types in the parameter pack T shall be complete. This trait is permitted to be specialized by a user if at least one template parameter is a user-defined type. [Note: Such specializations are required when only explicit conversions are desired among the common_type arguments. -- end note]

ratio

ratio is a general purpose utility inspired by Walter Brown allowing one to easily and safely compute rational values at compile time. The ratio class catches all errors (such as divide by zero and overflow) at compile time. It is used in the duration and time_point libraries to efficiently create units of time. It can also be used in other "quantity" libraries (both std-defined and user-defined), or anywhere there is a rational constant which is known at compile time. The use of this utility can greatly reduce the chances of run time overflow because the ratio (and any ratios resulting from ratio arithmetic) are always reduced to lowest terms.

ratio is a template taking two intmax_ts, with the second defaulted to 1. It only has two public members, both of which are static const intmax_t. One is the numerator of the ratio and the other is the denominator. The ratio is always normalized such that it is expressed in lowest terms, and the denominator is always positive. When the numerator is 0, the denominator is always 1.

Example:

typedef ratio<5, 3>   five_thirds;       // five_thirds::num == 5, five_thirds::den == 3
typedef ratio<25, 15> also_five_thirds;  // also_five_thirds::num == 5, also_five_thirds::den == 3
typedef ratio_divide<five_thirds, also_five_thirds>::type one;  // one::num == 1, one::den == 1

This facility also includes convenience typedefs for the SI prefixes atto through exa corresponding to their internationally recognized definitions (in terms of ratio). This is a tremendous syntactic convenience. It will prevent errors in specifying constants as one no longer has to double count the number of zeros when trying to write million or billion.

Example:

typedef ratio_multiply<ratio<5>, giga>::type _5giga;  // _5giga::num == 5000000000, _5giga::den == 1
typedef ratio_multiply<ratio<5>, nano>::type _5nano;  // _5nano::num == 1, _5nano::den == 200000000

The cost of not including ratio would mean that the implementor would likely have this functionality anyway, but spell it __ratio instead. This would prevent the user from using ratio in his own code. Furthermore duration would have to be templated on two long longs instead of on ratio like so:

template <class Rep, long long N, long long D> duration

This would mean that clients wanting to build a custom duration type (say a nanosecond represented by a double) would have to write:

duration<double, 1, 1000000000LL>

instead of:

duration<double, nano>

This lack of syntatic niceness, along with the loss of functionality in the reuse of ratio in user-written code seems to indicate that the loss of ratio would be a sizeable loss to user code.

ratio Proposed Wording

Insert a new section in 20 [utilities].

Compile time rational arithmetic [ratio]

This subclause describes a class template ratio which exactly represents any finite rational number with a numerator and denominator representable by intmax_t. The numerator and denominator shall be compile time integral constants.

Header <ratio> synopsis [ratio.synop]

namespace std {
  template <intmax_t N, intmax_t D = 1> class ratio;

  // ratio arithmetic
  template <class R1, class R2> struct ratio_add;
  template <class R1, class R2> struct ratio_subtract;
  template <class R1, class R2> struct ratio_multiply;
  template <class R1, class R2> struct ratio_divide;

  // ratio comparison
  template <class R1, class R2> struct ratio_equal;
  template <class R1, class R2> struct ratio_not_equal;
  template <class R1, class R2> struct ratio_less;
  template <class R1, class R2> struct ratio_less_equal;
  template <class R1, class R2> struct ratio_greater;
  template <class R1, class R2> struct ratio_greater_equal;

  // convenience SI typedefs
  typedef ratio<1, 1000000000000000000000000> yocto;  // conditionally supported
  typedef ratio<1,    1000000000000000000000> zepto;  // conditionally supported
  typedef ratio<1,       1000000000000000000> atto;
  typedef ratio<1,          1000000000000000> femto;
  typedef ratio<1,             1000000000000> pico;
  typedef ratio<1,                1000000000> nano;
  typedef ratio<1,                   1000000> micro;
  typedef ratio<1,                      1000> milli;
  typedef ratio<1,                       100> centi;
  typedef ratio<1,                        10> deci;
  typedef ratio<                       10, 1> deca;
  typedef ratio<                      100, 1> hecto;
  typedef ratio<                     1000, 1> kilo;
  typedef ratio<                  1000000, 1> mega;
  typedef ratio<               1000000000, 1> giga;
  typedef ratio<            1000000000000, 1> tera;
  typedef ratio<         1000000000000000, 1> peta;
  typedef ratio<      1000000000000000000, 1> exa;
  typedef ratio<   1000000000000000000000, 1> zetta;  // conditionally supported
  typedef ratio<1000000000000000000000000, 1> yotta;  // conditionally supported
}  // namespace std

ratio [ratio.ratio]

namespace std {
  template <intmax_t N, intmax_t D = 1>
  class ratio
  {
  public:
    static const intmax_t num;
    static const intmax_t den;
  };
}  // namespace std

A diagnostic shall be emitted if ratio is instantiated with D == 0, or if the absolute value of N or D can not be represented. [Note: These rules ensure that infinite ratios are avoided and that for any negative input, there exists a representable value of its absolute value which is positive. In a two's complement representation, this excludes the most negative value. -- end note]

Let gcd denote the greatest common divisor of N's absolute value and of D's absolute value.

num shall have the value sign(N)*sign(D)*abs(N)/gcd.

den shall have the value abs(D)/gcd.

ratio arithmetic [ratio.arithmetic]

For each of the class templates in this clause, each template parameter shall refer to a ratio. If the implementation is unable to form the indicated ratio due to overflow, a diagnostic shall be issued.

template <class R1, class R2> struct ratio_add      {typedef see below type;};
type shall alias ratio<R1::num * R2::den + R2::num * R1::den, R1::den * R2::den>.
template <class R1, class R2> struct ratio_subtract {typedef see below type;};
type shall alias ratio<R1::num * R2::den - R2::num * R1::den, R1::den * R2::den>.
template <class R1, class R2> struct ratio_multiply {typedef see below type;};
type shall alias ratio<R1::num * R2::num, R1::den * R2::den>.
template <class R1, class R2> struct ratio_divide   {typedef see below type;};
type shall alias ratio<R1::num * R2::den, R2::num * R1::den>.

ratio comparison [ratio.comparison]

template <class R1, class R2> struct ratio_equal
  : public integral_constant<bool, see below> {};
If R1::num == R2::num && R1::den == R2::den, ratio_equal derives from true_type, else derives from false_type.
template <class R1, class R2> struct ratio_less
  : public integral_constant<bool, see below> {};
If R1::num * R2::den < R2::num * R1::den, ratio_less derives from true_type, else derives from false_type. Implementations are permitted to use more complex algorithms to compute the above relationship to avoid overflow. If the implementation is not able to avoid overflow, a diagnostic shall be emitted.
template <class R1, class R2> struct ratio_not_equal
  : public integral_constant<bool, !ratio_equal<R1, R2>::value> {}; 

template <class R1, class R2> struct ratio_less_equal
  : public integral_constant<bool, !ratio_less<R2, R1>::value> {};

template <class R1, class R2> struct ratio_greater
  : public integral_constant<bool, ratio_less<R2, R1>::value> {};

template <class R1, class R2> struct ratio_greater_equal
  : public integral_constant<bool, !ratio_less<R1, R2>::value> {};

ratio SI typedefs [ratio.si]

Four of the typedefs in the synopsis are conditionally supported: yocto, zepto, zetta and yotta. If the constants specified in the synopsis are representable by intmax_t, the typedef shall be supported as shown in the synopsis, otherwise it shall not.

duration

The duration is the heart of this proposal. The interface that the user will see in everyday use is nearly identical to that of boost time durations authored by Jeff Garland, both in syntax and in behavior. This has been a very popular boost library for 7 years. There is an enormous positive history with this interface.

The library consists of six units of time duration:

These units were chosen as a subset of the boost library because they are the most common units used when sleeping, waiting on a condition variable, or waiting to obtain the lock on a mutex. Each of these units is nothing but a thin wrapper around a signed integral count. That is, when you construct minutes(3), all that happens is a 3 is stored inside of minutes. When you construct microseconds(3), all that happens is a 3 is stored inside of microseconds.

The only context in which these different types differ is when being converted to one another. At this time, unit-specific compile-time conversion constants are used to convert the source unit to the target unit. Only conversions from coarser units to finer units are allowed (in boost). This restriction ensures that all conversions are always exact. That is, microseconds can always represent any value minutes has.

In the boost library, these units are united via inheritance. This paper instead unites these units through the class template duration. That is, in this proposal all six of the above units are nothing but typedefs to different instantiations of duration. This change from the boost library has a far reaching positive impact, while not changing the syntax of the everyday use at all.

The most immediate positive impact is that the library can immediately generate any unit, any precision it needs. This is sometimes necessary when doing comparisons or arithmetic between durations of differing precision, assuming one wants the comparison and arithmetic to be exactly correct.

A secondary benefit is that by publishing the class template duration interface, user code can very easily create durations with any precision they desire. The ratio utility is used to specify the precision, so as long as the precision can be expressed by a rational constant with respect to seconds, this framework can exactly represent it (one third of a second is no problem, and neither is one third of a femto second). All of this utility and flexibility comes at no cost just by making use of the no-run-time-overhead ratio facility.

In the boost library, hours does not have the same representation as nanoseconds. The former is usually represented with a long whereas a long long is required for the latter. The reason for this is simply range. You don't need many hours to cover an extremely large range of time. But this isn't true of nanoseconds. Being able to reduce the sizeof overhead for some units when possible, can be a significant performance advantage.

This proposal continues, and generalizes that philosophy. Not only can one specify the precision of a duration, one can also specify its representation. This can be any integral type, or even a floating point type. Or it can be a user-defined type which emulates an arithmetic type. The six predefined units all use signed integral types as their representation. And they all have a minimum range of +/- 292 years. nanoseconds needs 64 bits to cover that range. hours needs only 23 bits to cover that range.

So What Exactly is a duration and How Do I Use One?

A duration has a representation and a tick period (precision).

template <class Rep, class Period = ratio<1>> class duration;

The representation is simply any arithmetic type, or an emulation of such a type. The representation stores a count of ticks. This count is the only data member stored in a duration. If the representation is floating point, it can store fractions of a tick to the precision of the representation. The tick period is represented by a ratio and is encoded into the duration's type, instead of stored. The tick period only has an impact on the behavior of the duration when a conversion between different duration's is attempted. The tick period is completely ignored when simply doing arithmetic among like durations.

Example:

typedef duration<long, ratio<60>> minutes;
minutes m1(3);                 // m1 stores 3
minutes m2(2);                 // m2 stores 2
minutes m3 = m1 + m2;          // m3 stores 5

typedef duration<long long, micro> microseconds;
microseconds us1(3);           // us1 stores 3
microseconds us2(2);           // us2 stores 2
microseconds us3 = us1 + us2;  // us3 stores 5

microseconds us4 = m3 + us3;   // us4 stores 300000005

In the final line of code above, there is an implicit conversion from minutes to microseconds, resulting in a relatively large number of microseconds.

If you need to access the tick count within a duration, there is a member count() which simply returns the stored tick count.

long long tc = us4.count();    // tc is 300000005

These durations have very simple, very predictable, and very observable behavior. After all, this is really nothing but the time tested interface of Jeff's boost time duration library (unified with templates instead of inheritance).

What happens if I assign m3 + us3 to minutes instead of microseconds?
minutes m4 = m3 + us3;

Answer: It won't compile. The rationale is that implicit truncation error should not be allowed to happen. If this were to compile, then m4 would hold 5, the same value as m3. The value associated with us3 has been effectively ignored. This is similar to the problem of assigning a double to an int: the fractional part gets silently discarded.

But what if the truncation behavior is what I want to do?

Answer: There is a duration_cast facility to explicitly ask for this behavior:

minutes m4 = duration_cast<minutes>(m3 + us3);  // m4.count() == 5

In general, one can perform duration arithmetic at will. If duration_cast isn't used, and it compiles, the arithmetic is exact. Any place one wants to override this exact arithmetic behavior, duration_cast can be used to explicitly specify that desire. The duration_cast has the same efficiency as the implicit conversion, and will even be exact as often as it can.

I'm trafficking in floating point durations. I don't want to deal with writing duration_cast all over the place. I'm content with the precision of my floating point representation.

Answer: Not a problem. When the destination of a conversion has floating point representation, all conversions are allowed to happen implicitly.

typedef duration<double, ratio<60>> dminutes;
dminutes dm4 = m3 + us3;  // dm4.count() == 5.000000083333333
How expensive is all of this?

Answer: If you were writing these conversions by hand, you could not make it more efficient. The use of ratio ensures that all conversion constants are simplified as much as possible at compile time. This usually results in the numerator or denominator of the conversion factor simplifying to 1, and being subsequently ignored in converting the run time values of the tick counts.

Has the proposal been implemented?

Answer: Yes. There is a complete example implementation of this proposal, including test suite. The duration part of it has a count of 99 semicolons. This count includes the duration_cast facility which handles all conversions, the duration class template, with all arithmetic and comparison operators, and the six pre-defined units: hours, minutes, seconds, milliseconds, microseconds and nanoseconds.

How complicated is it to build a function taking a duration parameter?

Answer: There are several options open to the user:

  1. If the author of the function wants to accept any duration, and is willing to work in floating point durations, he can simply use any floating point duration as the parameter:

    void f(duration<double> d)  // accept floating point seconds
    {
        // d.count() == 3.e-6 when passed microseconds(3)
    }
    
    f(microseconds(3));
    
  2. If the author of the function wants to traffic only in integral durations, and is content with handling nothing finer than say nanoseconds (just as an example), he can simply specify nanoseconds as the parameter:

    void f(nanoseconds d)
    {
        // d.count() == 3000 when passed microseconds(3)
    }
    
    f(microseconds(3));
    

    In this design, if the client wants to pass in a floating point duration, or a duration of finer precision than nanoseconds, then the client is responsible for choosing his own rounding mode in the conversion to nanoseconds.

    duration<double> s(1./3);  // 1/3 of a second
    f(duration_cast<nanoseconds>(s));  // round towards zero in conversion to nanoseconds
    

    In the example above, the client of f has chosen "round towards zero" as the desired rounding mode to nanoseconds. If the client has a duration that won't exactly convert to nanoseconds, and fails to choose how the conversion will take place, the compiler will refuse the call:

    f(s);  // does not compile
    
  3. If the author of the function wants to accept any duration, but wants to work with integral representations and wants to control the rounding mode internally, then he can template the function:

    template <class Rep, class Period>
    void f(duration<Rep, Period> d)
    {
        // convert d to nanoseconds, rounding up if it is not an exact conversion
        nanoseconds ns = duration_cast<nanoseconds>(d);
        if (ns < d)
            ++ns;
        // ns.count() == 333333334 when passed 1/3 of a floating point second
    }
    
    f(duration<double>(1./3));
    
  4. If the author in the example does not want to accept floating point based durations, he can enforce that behavior like so:

    template <class Period>
    void f(duration<long long, Period> d)
    {
        // convert d to nanoseconds, rounding up if it is not an exact conversion
        nanoseconds ns = duration_cast<nanoseconds>(d);
        if (ns < d)
            ++ns;
        // ns.count() == 333333334 when passed 333333333333 picoseconds
    }
    
    f(duration<long long, pico>(333333333333));  // About 1/3 of a second worth of picoseconds
    

    Clients with floating point durations who want to use f will now have to convert to an integral duration themselves before passing the result to f.

In summary, the author of f has quite a bit of flexibility and control in the interface he wants to provide his clients with, and easy options for manipulating that duration internal to his function.

Is it possible for the user to pass a duration to a function with the units being ambiguous?

Answer: No. No matter which option the author of f chooses above, the following client code will not compile:

f(3);  // Will not compile, 3 is not implicitly convertible to any duration

Clocks

While durations only have precision and representation to concern themselves, clocks and time_points are intimately related and refer to one another. Because clocks are simpler to explain, we will do so first without fully explaining time_points. Once clocks are introduced, it will be easier to then fill in what a time_point is.

A clock is a concept which bundles 3 things:

  1. A concrete duration type.
  2. A concrete time_point type.
  3. A function called now() which returns the concrete time_point.

This paper proposes 3 concrete clocks:

  1. system_clock
  2. monotonic_clock
  3. high_precision_clock

A given platform may not be able to supply all three of these clocks. The user is also able to easily create more clocks.

Given a clock named Clock, it will have:

class Clock
{
public:
    typedef an arithmetic-like type            rep;
    typedef an instantiation of ratio          period;
    typedef std::chrono::duration<rep, period> duration;
    typedef std::chrono::time_point<Clock>     time_point;
    static const bool is_monotonic =           true or false;

    static time_point now();
};

One can get the current time from Clock with:

Clock::time_point t1 = Clock::now();

And one can get the time duration between two time_points associated with Clock with:

Clock::duration d = t1 - Clock::now();

And one can specify a past or future time_point with:

Clock::time_point t2 = Clock::now() + d;

Note how even if a particular clock becomes obsolete, the next clock in line will have the same API. There is no new learning curve to come up. The only source code changes will be simply changing the type of the clock. The same duration and time_point framework continues to work as new clocks are introduced. And multiple clocks are safely and easily handled within the same program.

time_point

A time_point represents a point in time, as opposed to a duration of time. Another way of saying the same thing, is that a time_point represents an epoch plus or minus a duration. Examples of time_points include:

In each of the examples above, a different epoch is implied. Sometimes an epoch has meaning for several millennia. Other times the meaning of an epoch is lost after a while (such as the start of a timer, or when the computer booted). However, if two time_points are known to share the same epoch, they can be subtracted, yielding a valid duration, even if the definition of the epoch no longer has meaning.

In this proposal, an epoch is a purely abstract and unspecified concept. There is no type representing an epoch. It is simply an idea that relates (or doesn't) time_points to a clock, and in the case that they share a clock, time_points to one another. time_points associated with different clocks are generally not interoperable unless the relationship between the epochs associated with each clock is known.

So What Exactly is a time_point and How Do I Use One?

A time_point has a clock and a duration.

template <class Clock, class Duration = typename Clock::duration> class time_point;

The time_point's clock is not stored. It is simply embedded into the time_point's type and serves two purposes:

  1. Because time_points originating from different clocks have different types, the compiler can be instructed to fail if incompatible time_points are used in inappropriate ways.
  2. Given a time_point, one often needs to compare that time_point to "now". This is very simple as long as the time_point knows what clock it is defined with respect to.

A time_point's duration is stored as the only data member of the time_point. Thus time_points and their corresponding duration have exactly the same layout. But they have very different meanings. For example, it is one thing to say I want to sleep for 3 minutes. It is a completely different thing to say I want to sleep until 3 minutes past the time I started that timer (unless you just happened to start that timer now). Both meanings (and options for sleeping) have great practical value in common use cases for sleeping, waiting on a condition variable, and waiting for a mutex's lock. These same concepts and tools are found (for example) in Ada.

A timer example:

void f()
{
    monotonic_clock::time_point start = monotonic_clock::now();
    g();
    h();
    duration<double> sec = monotonic_clock::now() - start;
    cout << "f() took " << sec.count() << " seconds\n";
}

Note that if one is using the duration between two clock time_points in a way where the precision of the duration matters, it is good practice to convert the clock's native duration to a known duration. This insulates the code from future changes which may be made to the clock's native precision in the future. For example monotonic_clock could easily be based on the clock speed of the cpu. When you upgrade to a faster machine, you do not want your code that assumed a certain tick period of this clock to start experiencing run time failures because your timing code has silently changed meaning.

A delay loop example:

// delay for at least 500 nanoseconds:
auto go = monotonic_clock::now() + nanoseconds(500);
while (monotonic_clock::now() < go)
    ;

The above code will delay as close as possible to half a microsecond, no matter what the precision of monotonic_clock is. The more precise monotonic_clock becomes, the more accurate will be the delay to 500 nanoseconds.

Time Proposed Wording

Add a new subsection to 20.7 [date.time]:

Time utilities [time]

This subclause contains generally useful time utilities, also used in section 30 [thread].

Header <chrono> synopsis [chrono.synop]
namespace std {
namespace chrono {

template <class Rep, class Period = ratio<1>> class duration;
template <class Clock, class Duration = typename Clock::duration> class time_point;

}  // namespace chrono

// common_type traits
template <class Rep1, class Period1, class Rep2, class Period2>
  struct common_type<chrono::duration<Rep1, Period1>, chrono::duration<Rep2, Period2>>;

template <class Clock, class Duration1, class Duration2>
  struct common_type<chrono::time_point<Clock, Duration1>, chrono::time_point<Clock, Duration2>>;

namespace chrono {

// customization traits
template <class Rep> struct treat_as_floating_point;
template <class Rep> struct duration_values;

// duration arithmetic
template <class Rep1, class Period1, class Rep2, class Period2>
  typename common_type<duration<Rep1, Period1>, duration<Rep2, Period2>>::type
  operator+(const duration<Rep1, Period1>& lhs, const duration<Rep2, Period2>& rhs);
template <class Rep1, class Period1, class Rep2, class Period2>
  typename common_type<duration<Rep1, Period1>, duration<Rep2, Period2>>::type
  operator-(const duration<Rep1, Period1>& lhs, const duration<Rep2, Period2>& rhs);
template <class Rep1, class Period, class Rep2>
  duration<typename common_type<Rep1, Rep2>::type, Period>
  operator*(const duration<Rep1, Period>& d, const Rep2& s);
template <class Rep1, class Period, class Rep2>
  duration<typename common_type<Rep1, Rep2>::type, Period>
  operator*(const Rep1& s, const duration<Rep2, Period>& d);
template <class Rep1, class Period, class Rep2>
  duration<typename common_type<Rep1, Rep2>::type, Period>
  operator/(const duration<Rep1, Period>& d, const Rep2& s);
template <class Rep1, class Period1, class Rep2, class Period2>
  typename common_type<Rep1, Rep2>::type
  operator/(const duration<Rep1, Period1>& lhs, const duration<Rep2, Period2>& rhs);

// duration comparisons
template <class Rep1, class Period1, class Rep2, class Period2>
   bool operator==(const duration<Rep1, Period1>& lhs, const duration<Rep2, Period2>& rhs);
template <class Rep1, class Period1, class Rep2, class Period2>
   bool operator!=(const duration<Rep1, Period1>& lhs, const duration<Rep2, Period2>& rhs);
template <class Rep1, class Period1, class Rep2, class Period2>
   bool operator< (const duration<Rep1, Period1>& lhs, const duration<Rep2, Period2>& rhs);
template <class Rep1, class Period1, class Rep2, class Period2>
   bool operator<=(const duration<Rep1, Period1>& lhs, const duration<Rep2, Period2>& rhs);
template <class Rep1, class Period1, class Rep2, class Period2>
   bool operator> (const duration<Rep1, Period1>& lhs, const duration<Rep2, Period2>& rhs);
template <class Rep1, class Period1, class Rep2, class Period2>
   bool operator>=(const duration<Rep1, Period1>& lhs, const duration<Rep2, Period2>& rhs);

// duration_cast
template <class ToDuration, class Rep, class Period>
  ToDuration duration_cast(const duration<Rep, Period>& d);

// convenience typedefs
typedef duration<signed integral type of at least 64 bits,        nano> nanoseconds;
typedef duration<signed integral type of at least 55 bits,       micro> microseconds;
typedef duration<signed integral type of at least 45 bits,       milli> milliseconds;
typedef duration<signed integral type of at least 35 bits             > seconds;
typedef duration<signed integral type of at least 29 bits, ratio<  60>> minutes;
typedef duration<signed integral type of at least 23 bits, ratio<3600>> hours;

// time_point arithmetic
template <class Clock, class Duration1, class Rep2, class Period2>
  time_point<Clock, typename common_type<Duration1, duration<Rep2, Period2>>::type>
  operator+(const time_point<Clock, Duration1>& lhs, const duration<Rep2, Period2>& rhs);
template <class Rep1, class Period1, class Clock, class Duration2>
  time_point<Clock, typename common_type<duration<Rep1, Period1>, Duration2>::type>
  operator+(const duration<Rep1, Period1>& lhs, const time_point<Clock, Duration2>& rhs);
template <class Clock, class Duration1, class Rep2, class Period2>
  time_point<Clock, typename common_type<Duration1, duration<Rep2, Period2>>::type>
  operator-(const time_point<Clock, Duration1>& lhs, const duration<Rep2, Period2>& rhs);
template <class Clock, class Duration1, class Duration2>
  typename common_type<Duration1, Duration2>::type
  operator-(const time_point<Clock, Duration1>& lhs, const time_point<Clock, Duration2>& rhs);

// time_point comparisons
template <class Clock, class Duration1, class Duration2>
   bool operator==(const time_point<Clock, Duration1>& lhs, const time_point<Clock, Duration2>& rhs);
template <class Clock, class Duration1, class Duration2>
   bool operator!=(const time_point<Clock, Duration1>& lhs, const time_point<Clock, Duration2>& rhs);
template <class Clock, class Duration1, class Duration2>
   bool operator< (const time_point<Clock, Duration1>& lhs, const time_point<Clock, Duration2>& rhs);
template <class Clock, class Duration1, class Duration2>
   bool operator<=(const time_point<Clock, Duration1>& lhs, const time_point<Clock, Duration2>& rhs);
template <class Clock, class Duration1, class Duration2>
   bool operator> (const time_point<Clock, Duration1>& lhs, const time_point<Clock, Duration2>& rhs);
template <class Clock, class Duration1, class Duration2>
   bool operator>=(const time_point<Clock, Duration1>& lhs, const time_point<Clock, Duration2>& rhs);

// time_point_cast

template <class ToDuration, class Clock, class Duration>
  time_point<Clock, ToDuration> time_point_cast(const time_point<Clock, Duration>& t);

// Clocks
class system_clock;
class monotonic_clock;
class high_resolution_clock;

}  // namespace chrono
}  // namespace std
Clock Requirements [chrono.clock.req]

A clock represents a bundle consisting of a native duration, a native time_point, and a function now() to get the current time_point. A clock shall meet the requirements in Table ?.

In Table ? C1 and C2 denote clock types. t1 and t2 are values returned from C1::now() where the call returning t1 happens before [intro.multithread] the call returning t2 and both of these calls happen before C1::time_point::max().

Table ?: Clock Requirements
expression return type operational semantics
C1::rep An arithmetic type or class emulating an arithmetic type. The representation type of the native duration and time_point.
C1::period ratio The tick period of the clock in seconds.
C1::duration chrono::duration<C1::rep, C1::period> The native duration type of the clock.
C1::time_point chrono::time_point<C1> or chrono::time_point<C2, C1::duration> The native time_point type of the clock. Different clocks are permitted to share a time_point definition if it is valid to compare their time_points by comparing their respective durations. C1 and C2 shall refer to the same epoch.
C1::is_monotonic const bool true if t1 <= t2 is always true, else false. [Note: A clock that can be adjusted backwards is not monotonic. -- end note]
C1::now() C1::time_point Returns a time_point representing the current point in time.
Time related traits [chrono.traits]
template <class Rep> struct treat_as_floating_point
  : is_floating_point<Rep> {};

The duration template uses the treat_as_floating_point trait to help determine if a duration with one tick period can be converted to another duration with a different tick period. If treat_as_floating_point<Rep>::value is true, then Rep is a floating point type and implicit conversions are allowed among durations. Otherwise, the implicit convertibility depends on the tick periods of the durations. If Rep is a class type which emulates a floating point type, the author of Rep can specialize treat_as_floating_point so that duration will treat this Rep as if it were a floating point type. Otherwise Rep is assumed to be an integral type, or a class emulating an integral type.

template <class Rep>
struct duration_values
{
public:
    static constexpr Rep zero();
    static constexpr Rep max();
    static constexpr Rep min();
};

The duration template uses the duration_values trait to construct special values of the durations representation (Rep). This is done because the representation might be a class type with behavior which requires some other implementation to return these special values. In that case, the author of that class type should specialize duration_values to return the indicated values.

static constexpr Rep zero();

Returns: Rep(0). [Note: Rep(0) is specified instead of Rep() since Rep() may have some other meaning, such as an uninitialized value. -- end note]

Remarks: The value returned shall correspond to the additive identity.

static constexpr Rep max();

Returns: numeric_limits<Rep>::max().

Remarks: The value returned shall compare greater than zero().

static constexpr Rep min();

Returns: numeric_limits<Rep>::lowest().

Remarks: The value returned shall compare less than or equal to zero().

common_type specializations
template <class Rep1, class Period1, class Rep2, class Period2>
struct common_type<chrono::duration<Rep1, Period1>, chrono::duration<Rep2, Period2>>
{
    typedef chrono::duration<typename common_type<Rep1, Rep2>::type, see below> type;
};

The period of the duration indicated by this specialization of common_type shall be the greatest common divisor of Period1 and Period2. This can be computed by forming a ratio of the greatest common divisor of Period1::num and Period2::num, and the least common multiple of Period1::den and Period2::den.

Note: The typedef type is the duration with the largest tick period possible where both duration arguments will convert to it without requiring a division operation. The representation of this type is intended to be able to hold any value resulting from this conversion, with the possible exception of round-off error when floating point durations are involved (but not truncation error).

template <class Clock, class Duration1, class Duration2>
struct common_type<chrono::time_point<Clock, Duration1>, chrono::time_point<Clock, Duration2>>
{
    typedef chrono::time_point<Clock, typename common_type<Duration1, Duration2>::type> type;
};

The common_type of two time_points is a time_point with the same clock (both shall have the same clock), and the common_type of the two durations.

Class template duration [chrono.duration]

A duration measures time between two points in time (time_point). A duration has a representation which holds a count of ticks, and a tick period. The tick period is the amount of time which occurs from one tick to another in units of a second. It is expressed as a rational constant using ratio.

template <class Rep, class Period = ratio<1>>
class duration
{
public:
    typedef Rep    rep;
    typedef Period period;
private:
    rep rep_;  // exposition only
public:
    // construction / destruction
    duration() = default;
    template <class Rep2>
        explicit duration(const Rep2& r);
    ~duration() = default;

    // copy semantics
    duration(const duration&) = default;
    duration& operator=(const duration&) = default;

    // conversions
    template <class Rep2, class Period2>
       duration(const duration<Rep2, Period2>& d);

    // observer

    rep count() const;

    // arithmetic

    duration  operator+() const;
    duration  operator-() const;
    duration& operator++();
    duration  operator++(int);
    duration& operator--();
    duration  operator--(int);

    duration& operator+=(const duration& d);
    duration& operator-=(const duration& d);

    duration& operator*=(const rep& rhs);
    duration& operator/=(const rep& rhs);

    // special values

    static constexpr duration zero();
    static constexpr duration min();
    static constexpr duration max();
};

Rep shall be an arithmetic type, or a class emulating an arithmetic type. If duration is instantiated with the type of Rep being a duration, a diagnostic is required.

Period shall be an instantiation of ratio, diagnostic required.

Period::num shall be positive, diagnostic required.

Examples:

duration<long, ratio<60>> holds a count of minutes using a long.

duration<long long, milli> holds a count of milliseconds using a long long.

duration<double, ratio<1, 30>> holds a count using a double with a tick period of 1/30 second (a tick frequency of 30 Hz).

The following members of duration do not throw an exception unless the indicated operations on the representations throw an exception.

duration constructors
template <class Rep2>
    explicit duration(const Rep2& r);

Requires: Rep2 is implicitly convertible to rep, and

A diagnostic is required if this requirement is not met. [Note: This requirement prevents construction of an integral-based duration with a floating point representation. Such a construction could easily lead to confusion about the value of the duration. -- end note]

Example:

duration<int, milli> d(3.5);  // shall not compile
duration<int, milli> d(3);    // ok

Effects: Constructs an object of type duration.

PostConditions: count() == static_cast<rep>(r).

template <class Rep2, class Period2>
   duration(const duration<Rep2, Period2>& d);

Requires: treat_as_floating_point<rep>::value, or ratio_divide<Period2, period>::type::den == 1.

A diagnostic is required if this requirement is not met. [Note: This requirement prevents implicit truncation error when converting between integral-based durations. Such a construction could easily lead to confusion about the value of the duration. -- end note]

Example:

duration<int, milli> ms(3);
duration<int, micro> us = ms;  // ok
duration<int, milli> ms2 = us; // shall not compile

Effects: Constructs an object of type duration, constructing rep_ from duration_cast<duration>(d).count().

duration observers
rep count() const;

Returns: rep_.

duration member arithmetic
duration operator+() const;

Returns: *this.

duration operator-() const;

Returns: duration(-rep_).

duration& operator++();

Effects: ++rep_.

Returns: *this.

duration operator++(int);

Returns: duration(rep_++).

duration& operator--();

Effects: --rep_.

Returns: *this.

duration operator--(int);

Returns: duration(rep_--).

duration& operator+=(const duration& d);

Effects: rep_ += d.count().

Returns: *this.

duration& operator-=(const duration& d);

Effects: rep_ -= d.count().

Returns: *this.

duration& operator*=(const rep& rhs);

Effects: rep_ *= rhs.

Returns: *this.

duration& operator/=(const rep& rhs);

Effects: rep_ /= rhs.

Returns: *this.

duration special values
static constexpr duration zero();

Returns: duration(duration_values<rep>::zero()).

static constexpr duration min();

Returns: duration(duration_values<rep>::min()).

static constexpr duration max();

Returns: duration(duration_values<rep>::max()).

duration non-member arithmetic
template <class Rep1, class Period1, class Rep2, class Period2>
  typename common_type<duration<Rep1, Period1>, duration<Rep2, Period2>>::type
  operator+(const duration<Rep1, Period1>& lhs, const duration<Rep2, Period2>& rhs);
Returns: CD(lhs) += rhs where CD is the type of the return value.
template <class Rep1, class Period1, class Rep2, class Period2>
  typename common_type<duration<Rep1, Period1>, duration<Rep2, Period2>>::type
  operator-(const duration<Rep1, Period1>& lhs, const duration<Rep2, Period2>& rhs);
Returns: CD(lhs) -= rhs where CD is the type of the return value.
template <class Rep1, class Period, class Rep2>
  duration<typename common_type<Rep1, Rep2>::type, Period>
  operator*(const duration<Rep1, Period>& d, const Rep2& s);

Requires: Let CR represent the common_type of Rep1 and Rep2. Both Rep1 and Rep2 shall be implicitly convertible to CR, diagnostic required.

Returns: duration<CR, Period>(d) *= s.

template <class Rep1, class Period, class Rep2>
  duration<typename common_type<Rep1, Rep2>::type, Period>
  operator*(const Rep1& s, const duration<Rep2, Period>& d);

Requires: Let CR represent the common_type of Rep1 and Rep2. Both Rep1 and Rep2 shall be implicitly convertible to CR, diagnostic required.

Returns: d * s.

template <class Rep1, class Period, class Rep2>
  duration<typename common_type<Rep1, Rep2>::type, Period>
  operator/(const duration<Rep1, Period>& d, const Rep2& s);

Requires: Let CR represent the common_type of Rep1 and Rep2. Both Rep1 and Rep2 shall be implicitly convertible to CR, and Rep2 shall not be an instantiation of duration, diagnostic required.

Returns: duration<CR, Period>(d) /= s.

template <class Rep1, class Period1, class Rep2, class Period2>
  typename common_type<Rep1, Rep2>::type
  operator/(const duration<Rep1, Period1>& lhs, const duration<Rep2, Period2>& rhs);

Returns: Let CD represent the common_type of the two duration arguments. Returns CD(lhs).count() / CD(rhs).count().

duration comparisons
template <class Rep1, class Period1, class Rep2, class Period2>
   bool operator==(const duration<Rep1, Period1>& lhs, const duration<Rep2, Period2>& rhs);
Returns: Let CD represent the common_type of the two duration arguments. Returns CD(lhs).count() == CD(rhs).count()
template <class Rep1, class Period1, class Rep2, class Period2>
   bool operator!=(const duration<Rep1, Period1>& lhs, const duration<Rep2, Period2>& rhs);
Returns: !(lhs == rhs).
template <class Rep1, class Period1, class Rep2, class Period2>
   bool operator< (const duration<Rep1, Period1>& lhs, const duration<Rep2, Period2>& rhs);
Returns: Let CD represent the common_type of the two duration arguments. Returns CD(lhs).count() < CD(rhs).count()
template <class Rep1, class Period1, class Rep2, class Period2>
   bool operator<=(const duration<Rep1, Period1>& lhs, const duration<Rep2, Period2>& rhs);
Returns: !(rhs < lhs).
template <class Rep1, class Period1, class Rep2, class Period2>
   bool operator> (const duration<Rep1, Period1>& lhs, const duration<Rep2, Period2>& rhs);
Returns: rhs < lhs.
template <class Rep1, class Period1, class Rep2, class Period2>
   bool operator>=(const duration<Rep1, Period1>& lhs, const duration<Rep2, Period2>& rhs);
Returns: !(lhs < rhs).
duration_cast
template <class ToDuration, class Rep, class Period>
  ToDuration duration_cast(const duration<Rep, Period>& d);

Requires: ToDuration is an instantiation of duration, diagnostic required.

Returns: Forms CF which is a ratio resulting from ratio_divide<Period, typename ToDuration::period>::type. Let CR be the common_type of ToDuration::rep, Rep, and intmax_t.

Remarks: This function shall not rely on any implicit conversions. All conversions shall be accomplished through static_cast. The implementation shall avoid all multiplications or divisions when it is known at compile time that it can be avoided because one or more arguments are 1. All intermediate computations shall be carried out in the widest possible representation and only converted to the destination representation at the final step.

Class template time_point [chrono.time.point]

A time_point represents a point in time with respect to a specific clock.

Class template time_point
template <class Clock, class Duration = typename Clock::duration>
class time_point
{
public:
    typedef Clock                     clock;
    typedef Duration                  duration;
    typedef typename duration::rep    rep;
    typedef typename duration::period period;
private:
    duration d_;  // exposition only

public:
    time_point();  // has value "epoch"
    explicit time_point(const duration& d);  // same as time_point() + d

    // conversions
    template <class Duration2>
       time_point(const time_point<clock, Duration2>& t);

    // observer

    duration time_since_epoch() const;

    // arithmetic

    time_point& operator+=(const duration& d);
    time_point& operator-=(const duration& d);

    // special values

    static constexpr time_point min();
    static constexpr time_point max();
};

Clock shall meet the Clock Requirements [chrono.clock.req].

Duration shall be an instantiation of duration, diagnostic required.

time_point constructors
time_point();
Effects: Constructs an object of time_point, initializing d_ with duration::zero(). This time_point represents the epoch.
time_point(const duration& d);
Effects: Constructs an object of time_point, initializing d_ with d. This time_point represents the epoch + d.
template <class Duration2>
   time_point(const time_point<clock, Duration2>& t);

Requires: Duration2 shall be implicitly convertible to duration, diagnostic required.

Effects: Constructs an object of time_point, initializing d_ with t.time_since_epoch().

time_point observers
duration time_since_epoch() const;

Returns: d_.

time_point member arithmetic
time_point& operator+=(const duration& d);

Effects: d_ += d.

Returns: *this.

time_point& operator-=(const duration& d);

Effects: d_ -= d.

Returns: *this.

time_point special values
static constexpr time_point min();
Returns: time_point(duration::min()).
static constexpr time_point max();
Returns: time_point(duration::max()).
time_point non-member arithmetic
template <class Clock, class Duration1, class Rep2, class Period2>
  time_point<Clock, typename common_type<Duration1, duration<Rep2, Period2>>::type>
  operator+(const time_point<Clock, Duration1>& lhs, const duration<Rep2, Period2>& rhs);
Returns: CT(lhs) += rhs where CT is the type of the return value.
template <class Rep1, class Period1, class Clock, class Duration2>
  time_point<Clock, typename common_type<duration<Rep1, Period1>, Duration2>::type>
  operator+(const duration<Rep1, Period1>& lhs, const time_point<Clock, Duration2>& rhs);
Returns: rhs + lhs.
template <class Clock, class Duration1, class Rep2, class Period2>
  time_point<Clock, typename common_type<Duration1, duration<Rep2, Period2>>::type>
  operator-(const time_point<Clock, Duration1>& lhs, const duration<Rep2, Period2>& rhs);
Returns: lhs + (-rhs).
template <class Clock, class Duration1, class Duration2>
  typename common_type<Duration1, Duration2>::type
  operator-(const time_point<Clock, Duration1>& lhs, const time_point<Clock, Duration2>& rhs);
Returns: lhs.time_since_epoch() - rhs.time_since_epoch().
time_point comparisons
template <class Clock, class Duration1, class Duration2>
   bool operator==(const time_point<Clock, Duration1>& lhs, const time_point<Clock, Duration2>& rhs);
Returns: lhs.time_since_epoch() == rhs.time_since_epoch().
template <class Clock, class Duration1, class Duration2>
   bool operator!=(const time_point<Clock, Duration1>& lhs, const time_point<Clock, Duration2>& rhs);
Returns: !(lhs == rhs).
template <class Clock, class Duration1, class Duration2>
   bool operator< (const time_point<Clock, Duration1>& lhs, const time_point<Clock, Duration2>& rhs);
Returns: lhs.time_since_epoch() < rhs.time_since_epoch().
template <class Clock, class Duration1, class Duration2>
   bool operator<=(const time_point<Clock, Duration1>& lhs, const time_point<Clock, Duration2>& rhs);
Returns: !(rhs < lhs).
template <class Clock, class Duration1, class Duration2>
   bool operator> (const time_point<Clock, Duration1>& lhs, const time_point<Clock, Duration2>& rhs);
Returns: rhs < lhs.
template <class Clock, class Duration1, class Duration2>
   bool operator>=(const time_point<Clock, Duration1>& lhs, const time_point<Clock, Duration2>& rhs);
Returns: !(lhs < rhs).
time_point_cast
template <class ToDuration, class Clock, class Duration>
  time_point<Clock, ToDuration> time_point_cast(const time_point<Clock, Duration>& t);

Requires: ToDuration is an instantiation of duration, diagnostic required.

Returns: time_point<Clock, ToDuration>(duration_cast<ToDuration>(t.time_since_epoch())).

Clocks [chrono.clock]

The types defined in this section shall satisfy the Clock Requirements [chrono.clock.req].

system_clock

Class system_clock represents wall clock time from the system-wide realtime clock.

class system_clock
{
public:
    typedef <see below>                      rep;
    typedef ratio<unspecified, unspecified>  period;
    typedef chrono::duration<rep, period>    duration;
    typedef chrono::time_point<system_clock> time_point;
    static const bool is_monotonic =         <unspecified>;

    static time_point now();

    // Map to C API
    static time_t      to_time_t  (const time_point& t);
    static time_point  from_time_t(time_t t);
};

system_clock::duration::min() < system_clock::duration::zero() shall be true.

time_t to_time_t(const time_point& t);
Returns: A time_t such that the time_t and t represent the same point in time, truncated to the courser of the precisions among time_t and t.
time_point from_time_t(time_t t);
Returns: A time_point such that the time_point and t represent the same point in time, truncated to the courser of the precisions among time_point and t.
monotonic_clock

monotonic_clock represents a clock for which the time_point never decreases as physical time advances. This type is conditionally supported: if not provided, class monotonic_clock shall not be declared. monotonic_clock is permitted to be a separate type or a typedef of system_clock.

class monotonic_clock
{
public:
    typedef <unspecified>                             rep;
    typedef ratio<unspecified, unspecified>           period;
    typedef chrono::duration<rep, period>             duration;
    typedef chrono::time_point<unspecified, duration> time_point;
    static const bool is_monotonic =                  true;

    static time_point now();
};
high_resolution_clock

Class high_resolution_clock represents the clock with the shortest tick period. high_resolution_clock is permitted to be a separate type or a typedef of system_clock or monotonic_clock.

class high_resolution_clock
{
public:
    typedef <unspecified>                             rep;
    typedef ratio<unspecified, unspecified>           period;
    typedef chrono::duration<rep, period>             duration;
    typedef chrono::time_point<unspecified, duration> time_point;
    static const bool is_monotonic =                  <unspecified>;

    static time_point now();
};

Threads

The current time-related threading API is adapted to this proposal. An emphasis is put on ease of use, safety, efficiency, and durability with respect to advancing technology over time.

Summary of changes:

Threads Proposed Wording

Modify 30.2 [thread.threads]:

template <class Clock, class Duration>
  void sleep_until(const system_time chrono::time_point<Clock, Duration>& abs_time);
template <class Duration Rep, class Period> 
  void sleep_for(const Duration chrono::duration<Rep, Period>& rel_time);

Modify 30.2.2 [thread.thread.this]:

template <class Clock, class Duration>
  void sleep_until(const system_time chrono::time_point<Clock, Duration>& abs_time);
template <class Duration Rep, class Period> 
  void sleep_for(const Duration chrono::duration<Rep, Period>& rel_time);
...
template <class Clock, class Duration>
  void this_thread::sleep_until(const system_time chrono::time_point<Clock, Duration>& abs_time);
...
template <class Duration Rep, class Period> 
  void sleep_for(const Duration chrono::duration<Rep, Period>& rel_time);

...

[Note: Implementations should use a monotonic clock for measuring rel_time if available. -- end note]

Modify 30.3.2 [thread.timedmutex.requirements]:

A TimedMutex type shall meet the requirements for a Mutex type. In addition, it shall meet the requirements set out in this clause 30.3.2, where rel_time denotes a value of a type RelTime that meets the Duration an instantiation of duration (??) requirements and abs_time denotes a value of type std::system_time an instantiation of time_point.

The expression m.timed_locktry_lock_for(rel_time) shall be well-formed and have the following semantics:

Precondition: If the resolution tick period of RelTime rel_time is finer than not exactly convertible to the native resolution tick period, the time duration shall be rounded up to the nearest native resolution tick period.

Effects: The function attempts to obtain ownership of the mutex within the time specified by rel_time. If the time specified by rel_time is less than or equal to 0, the function attempts to obtain ownership without blocking (as if by calling try_lock()). The function shall return within the time specified by rel_time only if it has obtained ownership of the mutex object. [Note: As with try_lock(), there is no guarantee that ownership will be obtained if the lock is available, but implementations are expected to make a strong effort to do so. Implementations should use a monotonic clock for measuring rel_time if available. -- end note]

Return type: bool

Returns: true if ownership was obtained, otherwise false.

Synchronization: If timed_locktry_lock_for() returns true, prior unlock() operations on the same object synchronize with (1.10) this operation.

Throws: Nothing.

The expression m.timed_locktry_lock_until(abs_time) shall be well-formed and have the following semantics:

Effects: The function attempts to obtain ownership of the mutex by the time specified by abs_time. If abs_time has already passed, the function attempts to obtain ownership without blocking (as if by calling try_lock()). The function shall return before the time specified by abs_time only if it has obtained ownership of the mutex object. [ Note: As with try_lock(), there is no guarantee that ownership will be obtained if the lock is available, but implementations are expected to make a strong effort to do so. -- end note]

Return type: bool

Returns: true if ownership was obtained, otherwise false.

Synchronization: If timed_locktry_lock_until() returns true, prior unlock() operations on the same object synchronize with (1.10) this operation.

Throws: Nothing.

Modify 30.3.2.1 [thread.timedmutex.class]:

namespace std { 
  class timed_mutex { 
  public: 
    timed_mutex(); 
    ~timed_mutex(); 

    timed_mutex(const timed_mutex&) = delete; 
    timed_mutex& operator=(const timed_mutex&) = delete; 

    void lock(); 
    bool try_lock(); 
    template <class Duration Rep, class Period> 
      bool timed_locktry_lock_for(const Duration chrono::duration<Rep, Period>& rel_time); 
    template <class Clock, class Duration>
      bool timed_locktry_lock_until(const system_time chrono::time_point<Clock, Duration>& abs_time); 
    void unlock(); 

    typedef implementation-defined native_handle_type; // See 30.1.3 
    native_handle_type native_handle();                // See 30.1.3 
  }; 
}

The class timed_mutex provides a non-recursive mutex with exclusive ownership semantics. If one thread owns a timed_mutex object, attempts by another thread to acquire ownership of that object will fail (for try_lock()) or block (for lock(), try_lock_for() and timed_lock try_lock_until()) until the owning thread has released ownership with a call to unlock() or the call to timed_lock try_lock_for() or try_lock_until() times out (having failed to obtain ownership).

The class timed_mutex shall satisfy all of the TimedMutex requirements (30.3.2). It shall be a standard-layout class (9).

The behavior of a program is undefined if:

Modify 30.3.2.2 [thread.timedmutex.recursive]:

namespace std { 
  class recursive_timed_mutex { 
  public: 
    recursive_timed_mutex(); 
    ~recursive_timed_mutex(); 

    recursive_timed_mutex(const recursive_timed_mutex&) = delete; 
    recursive_timed_mutex& operator=(const recursive_timed_mutex&) = delete; 

    void lock(); 
    bool try_lock(); 
    template <class Duration Rep, class Period> 
      bool timed_locktry_lock_for(const Duration chrono::duration<Rep, Period>& rel_time); 
    template <class Clock, class Duration>
      bool timed_locktry_lock_until(const system_time chrono::time_point<Clock, Duration>& abs_time); 
    void unlock(); 

    typedef implementation-defined native_handle_type; // See 30.1.3 
    native_handle_type native_handle();                // See 30.1.3 
  }; 
}

The class recursive_timed_mutex provides a non-recursive mutex with exclusive ownership semantics. If one thread owns a recursive_timed_mutex object, attempts by another thread to acquire ownership of that object will fail (for try_lock()) or block (for lock(), try_lock_for() and timed_lock try_lock_until()) until the owning thread has released ownership with a call to unlock() or the call to timed_lock try_lock_for() or try_lock_until() times out (having failed to obtain ownership).

The class recursive_timed_mutex shall satisfy all of the TimedMutex requirements (30.3.2). It shall be a standard-layout class (9).

A thread that owns a recursive_timed_mutex object may acquire additional levels of ownership by calling lock(), try_lock(), try_lock_for() or timed_lock() try_lock_until() on that object. It is unspecified how many levels of ownership may be acquired by a single thread. If a thread has already acquired the maximum level of ownership for a recursive_timed_mutex object, additional calls to try_lock(), try_lock_for() or timed_lock() try_lock_until() shall fail, and additional calls to lock() shall throw an exception of type std::system_error. A thread shall call unlock() once for each level of ownership acquired by calls to lock(), try_lock(), try_lock_for() and timed_lock() try_lock_until(). Only when all levels of ownership have been released may ownership of the object be acquired by another thread.

The behavior of a program is undefined if:

Modify 30.3.3.2 [thread.lock.unique]:

namespace std { 
template <class Mutex> 
class unique_lock { 
public: 
    typedef Mutex mutex_type; 

    // 30.3.3.2.1 construct/copy/destroy 
    unique_lock(); 
    explicit unique_lock(mutex_type& m); 
    unique_lock(mutex_type& m, defer_lock_t);
    unique_lock(mutex_type& m, try_to_lock_t); 
    unique_lock(mutex_type& m, adopt_lock_t);
    template <class Clock, class Duration>
      unique_lock(mutex_type& m, const system_time chrono::time_point<Clock, Duration>& abs_time); 
    template <class Duration Rep, class Period> 
      unique_lock(mutex_type& m, const Duration chrono::duration<Rep, Period>& rel_time); 
    ~unique_lock(); 

    unique_lock(unique_lock const&) = delete; 
    unique_lock& operator=(unique_lock const&) = delete; 

    unique_lock(unique_lock&& u); 
    unique_lock& operator=(unique_lock&& u); 

    // 30.3.3.2.2 locking 
    void lock(); 
    bool try_lock(); 
    template <class Duration Rep, class Period> 
      bool timedtry_lock_for(const Duration chrono::duration<Rep, Period>& rel_time); 
    template <class Clock, class Duration>
      bool timedtry_lock_until(const system_time chrono::time_point<Clock, Duration>& abs_time); 
    void unlock(); 

    // 30.3.3.2.3 modifiers 
    void swap(unique_lock&& u); 
    mutex_type* release(); 

    // 30.3.3.2.4 observers 
    bool owns_lock() const; 
    explicit operator bool () const; 
    mutex_type* mutex() const; 

private: 
    // exposition only: 
    mutex_type* pm; 
    bool owns; 
};

...

Modify 30.3.3.2.1 [thread.lock.unique.cons]:

template <class Clock, class Duration>
  unique_lock(mutex_type& m, const system_time chrono::time_point<Clock, Duration>& abs_time);

Precondition: If mutex_type is not a recursive mutex the calling thread does not own the mutex.

Effects: Constructs an object of type unique_lock and calls m.timedtry_lock_until(abs_time).

Postconditions: pm == &m and owns == res, where res is the value returned by the call to timedtry_lock_until(abs_time).

Throws: Nothing.

template <class Duration Rep, class Period> 
  unique_lock(mutex_type& m, const Duration chrono::duration<Rep, Period>& rel_time); 

Remark: The implementation shall ensure that only Duration types (") will bind to this constructor.

Precondition: If mutex_type is not a recursive mutex the calling thread does not own the mutex.

Effects: Constructs an object of type unique_lock and calls m.timedtry_lock_for(rel_time).

Postconditions: pm == &m and owns == res, where res is the value returned by the call to m.timedtry_lock_for(rel_time).

Throws: Nothing.

Modify 30.3.3.2.2 [thread.lock.unique.locking]:

template <class Clock, class Duration>
  bool timedtry_lock_until(const system_time chrono::time_point<Clock, Duration>& abs_time);

Effects: pm->timedtry_lock_until(abs_time)

Returns: The value returned by the call to timedtry_lock_until(abs_time).

Postcondition: owns == res, where res is the value returned by the call to timedtry_lock_until(abs_time).

Throws: lock_error if on entry owns is true or pm is null.

template <class Duration Rep, class Period> 
  bool timedtry_lock_for(const Duration chrono::duration<Rep, Period>& rel_time);

Effects: pm->timedtry_lock_for(rel_time)

Returns: The value returned by the call to timedtry_lock_for(rel_time).

Postcondition: owns == res, where res is the value returned by the call to timedtry_lock_for(rel_time).

Throws: lock_error if on entry owns is true or pm is null.

Modify 30.4 [thread.condition]:

...

Condition variables permit concurrent invocation of the wait, timed_wait_for, timed_wait_until, notify_one and notify_all member functions.

...

The implementation shall behave as if notify_one, notify_all, and each part of the wait, wait_for and timed_wait_until executions are executed in some unspecified total order.

...

Modify 30.4.1 [thread.condition.condvar]:

namespace std { 
class condition_variable { 
public: 

    condition_variable(); 
    ~condition_variable(); 

    condition_variable(const condition_variable&) = delete; 
    condition_variable& operator=(const condition_variable&) = delete; 

    void notify_one(); 
    void notify_all(); 
    void wait(unique_lock<mutex>& lock); 
    template <class Predicate> 
      void wait(unique_lock<mutex>& lock, Predicate pred); 
    template <class Duration> 
      bool timed_wait(unique_lock<mutex>& lock, const Duration& rel_time); 
    bool timed_wait(unique_lock<mutex>& lock, const system_time& abs_time); 
    template <class Predicate> 
      bool timed_wait(unique_lock<mutex>& lock, const system_time& abs_time, 
                      Predicate pred); 
    template <class Duration, class Predicate> 
      bool timed_wait(unique_lock<mutex>& lock, const Duration& rel_time, Predicate pred);

    template <class Clock, class Duration>
        bool wait_until(unique_lock<mutex>& lock,
                        const chrono::time_point<Clock, Duration>& abs_time);
    template <class Clock, class Duration, class Predicate>
        bool wait_until(unique_lock<mutex>& lock,
                        const chrono::time_point<Clock, Duration>& abs_time,
                        Predicate pred);

    template <class Rep, class Period>
        bool wait_for(unique_lock<mutex>& lock, const chrono::duration<Rep, Period>& rel_time);
    template <class Rep, class Period, class Predicate>
        bool wait_for(unique_lock<mutex>& lock,  const chrono::duration<Rep, Period>& rel_time,
                      Predicate pred);

    typedef implementation-defined native_handle_type; // See 30.1.3 
    native_handle_type native_handle(); // See 30.1.3 
}; 
}

...

template <class Clock, class Duration>
  bool timed_wait_until(unique_lock<mutex>& lock, const system_time chrono::time_point<Clock, Duration>& abs_time);

Precondition: lock is locked by the calling thread, and either

  • no other thread is waiting on this condition_variable object or
  • lock.mutex() returns the same value for each of the lock arguments supplied by all concurrently waiting threads (via wait, wait_for or timed_wait_until).

Effects:

  • Atomically calls lock.unlock() and blocks on *this.
  • When unblocked, calls lock.lock() (possibly blocking on the lock) and returns.
  • The function will unblock when signaled by a call to notify_one(), a call to notify_all(), by the current time exceeding abs_time, or spuriously.
  • If the function exits via an exception, lock.unlock() shall be called prior to exiting the function scope.

Postcondition: lock is locked by the calling thread.

Returns: Clock::now() < abs_time false if the call is returning because the time specified by abs_time was reached, otherwise true.

Throws: std::system_error when the returned value, effects, or postcondition cannot be achieved.

template <class Clock, class Duration, class Predicate> 
  bool timed_wait_until(unique_lock<mutex>& lock,
                        const system_time chrono::time_point<Clock, Duration>& abs_time, 
                        Predicate pred);

Effects:

while (!pred()) 
    if (!timed_wait_until(lock, abs_time)) 
        return pred(); 
return true;

...

template <class Duration Rep, class Period> 
  bool timed_wait_for(unique_lock<mutex>& lock, const Duration chrono::duration<Rep, Period>& rel_time);

Effects: As if timed_wait_until(lock, std::get_system_time() chrono::monotonic_clock::now() + rel_time)

Returns: false if the call is returning because the time duration specified by rel_time has elapsed, otherwise true.

Note: A monotonic clock is preferred but not required for measuring rel_time in this function.

template <class Duration Rep, class Period, class Predicate> 
  bool timed_wait_for(unique_lock<mutex>& lock,
                      const Duration chrono::duration<Rep, Period>& rel_time,
                      Predicate pred);

Effects:

timed_wait_until(lock, std::get_system_time() chrono::monotonic_clock::now() + rel_time, std::move(pred))

[Note: There is no blocking if pred() is initially true, even if the timeout has already expired. A monotonic clock is preferred but not required for measuring rel_time in this function. -- end note]

...

Modify 30.4.2 [thread.condition.condvarany]:

namespace std { 
class condition_variable_any { 
public: 
    condition_variable_any(); 
    ~condition_variable_any(); 

    condition_variable_any(const condition_variable_any&) = delete; 
    condition_variable_any& operator=(const condition_variable_any&) = delete; 

    void notify_one(); 
    void notify_all(); 

    template <class Lock> 
      void wait(Lock& lock); 
    template <class Lock, class Predicate> 
      void wait(Lock& lock, Predicate pred); 

    template <class Lock> 
      bool timed_wait(Lock& lock, const system_time& abs_time); 
    template <class Lock, class Duration> 
      bool timed_wait(Lock& lock, const Duration& rel_time); 
    template <class Lock, class Predicate> 
      bool timed_wait(Lock& lock, const system_time& abs_time, Predicate pred); 
    template <class Lock, class Duration, class Predicate> 
      bool timed_wait(Lock& lock, const Duration& rel_time, Predicate pred);

    template <class Lock, class Clock, class Duration>
        bool wait_until(Lock& lock, const chrono::time_point<Clock, Duration>& abs_time);
    template <class Lock, class Clock, class Duration, class Predicate>
        bool wait_until(Lock& lock, const chrono::time_point<Clock, Duration>& abs_time,
                        Predicate pred);

    template <class Lock, class Rep, class Period>
        bool wait_for(Lock& lock, const chrono::duration<Rep, Period>& rel_time);
    template <class Lock, class Rep, class Period, class Predicate>
        bool wait_for(Lock& lock, const chrono::duration<Rep, Period>& rel_time, Predicate pred);

    typedef implementation-defined native_handle_type; // See 30.1.3 
    native_handle_type native_handle(); // See 30.1.3 
}; 
}

...

template <class Lock, class Clock, class Duration>
  bool timed_wait_until(Lock& lock, const system_time chrono::time_point<Clock, Duration>& abs_time);

Effects:

  • Atomically calls lock.unlock() and blocks on *this.
  • When unblocked, calls lock.lock() (possibly blocking on the lock) and returns.
  • The function will unblock when signaled by a call to notify_one(), a call to notify_all(), by the current time exceeding abs_time, or spuriously.
  • If the function exits via an exception, lock.unlock() shall be called prior to exiting the function scope.

Postcondition: lock is locked by the calling thread.

Returns: Clock::now() < abs_time false if the call is returning because the time specified by abs_time was reached, otherwise true.

Throws: std::system_error when the returned value, effects, or postcondition cannot be achieved.

template <class Lock, class Clock, class Duration, class Predicate> 
  bool timed_wait_until(Lock& lock,
                        const system_time chrono::time_point<Clock, Duration>& abs_time, 
                        Predicate pred);

Effects:

while (!pred()) 
    if (!timed_wait_until(lock, abs_time)) 
        return pred(); 
return true;

...

template <class Lock, class Duration Rep, class Period> 
  bool timed_wait_for(Lock& lock, const Duration chrono::duration<Rep, Period>& rel_time);

Effects: As if timed_wait_until(lock, std::get_system_time() chrono::monotonic_clock::now() + rel_time)

Returns: false if the call is returning because the time duration specified by rel_time has elapsed, otherwise true.

Note: A monotonic clock is preferred but not required for measuring rel_time in this function.

template <class Lock, class Duration Rep, class Period, class Predicate> 
  bool timed_wait_for(Lock& lock,
                      const Duration chrono::duration<Rep, Period>& rel_time,
                      Predicate pred);

Effects:

timed_wait_until(lock, std::get_system_time() chrono::monotonic_clock::now() + rel_time, std::move(pred))

[Note: There is no blocking if pred() is initially true, even if the timeout has already expired. A monotonic clock is preferred but not required for measuring rel_time in this function. -- end note]

...

Acknowledgements

The help of many people in preparing the technical background of this paper is much appreciated. Special thanks to Andrei Alexandrescu, Lawrence Crowl, Beman Dawes, Peter Dimov, Terry Golubiewski, Daniel Krügler and Anthony Williams.