Boost C++ Libraries Home Libraries People FAQ More

PrevUpHomeNext

User's Guide

Getting Started
Tutorial
Examples
External Resources
Getting Boost.Chrono

Boost.Chrono is in the latest Boost release in the folder /boost/chrono. Documentation, tests and examples folder are at boost/libs/chrono/.

You can also access the latest (unstable?) state from the Boost trunk directories boost/chrono and libs/chrono. Just go to here and follow the instructions there for anonymous SVN access.

Where to install Boost.Chrono?

The simple way is to decompress (or checkout from SVN) the files in your BOOST_ROOT directory.

Building Boost.Chrono

Boost.Chrono can be configured as a header-only library. When BOOST_CHRONO_HEADER_ONLY is defined the Boost.Chrono is a header-only library. Otherwise is not a header only library and you need to compile it and build the library before use, for example using:

bjam libs/chrono/build
Requirements

In particular, Boost.Chrono depends on:

Boost.Config

for configuration purposes, ...

Boost.Exception

for throw_exception, ...

Boost.Integer

for cstdint conformance, ...

Boost.MPL

for MPL Assert and bool, logical ...

Boost.Operators

for operators, ...

Boost.Ratio

for ratio, milli, micro, ...

Boost.System

for error_code, ...

Boost.TypeTraits

for is_base, is_convertible, common_type, ...

Boost.Utility/EnableIf

for enable_if, ...

Building an Executable that Uses Boost.Chrono

In addition to link with the Boost.Chrono library you need also to link with the Boost.System library. Once Boost.System will be configurable to be a header only using BOOST_SYSTEM_INLINED you will no need to link with it.

Exception safety

All functions in the library are exception-neutral and provide strong guarantee of exception safety as long as the underlying parameters provide it.

Thread safety

All functions in the library are thread-unsafe except when noted explicitly.

As Boost.Chrono doesn't use mutable global variables the thread-safety analysis is limited to the access to each instance variable. It is not thread safe to use a function that modifies the access to a user variable if another can be reading or writing it.

Tested compilers

The implementation will eventually work with most C++03 conforming compilers. Currently I use to test with on:

Windows with

  • MSVC 10.0

Cygwin 1.7 with

  • GCC 4.3.4

MinGW with

  • GCC 4.5.0
  • GCC 4.5.0 -std=c++0x
  • GCC 4.5.2
  • GCC 4.5.2 -std=c++0x
  • GCC 4.6.0
  • GCC 4.6.0 -std=c++0x

OsX with

  • GCC 4.1.2
  • clang 1.6
  • clang 2.9
  • clang 2.9 -std=c++0x

The committed code is tested with much more compilers. There are two compilers (VACPP and Borland) that don't provide the needed features. Other as Intel and Sun have some issues with i/o. While everything compiles and link correctly, there are some runtime issues I have not cached yet. See the regression tests for details.

[Note] Note

Please let us know how this works on other platforms/compilers.

[Note] Note

Please send any questions, comments and bug reports to boost <at> lists <dot> boost <dot> org.

If all you want to do is to time a program's execution, here is a complete program:

#include <boost/chrono.hpp>
#include <cmath>

int main()
{
    boost::chrono::system_clock::time_point start = boost::chrono::system_clock::now();

    for ( long i = 0; i < 10000000; ++i )
    std::sqrt( 123.456L ); // burn some time

    boost::chrono::duration<double> sec = boost::chrono::system_clock::now() - start;
    std::cout << "took " << sec.count() << " seconds\n";
    return 0;
}

Output was:

took 0.832 seconds

The duration is the heart of this library. The interface that the user will see in everyday use is nearly identical to that of Boost.DateTime 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 minutes. When you construct microseconds(3), all that happens is a 3 is stored inside 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 Boost.DateTime, these units are united via inheritance. Boost.Chrono instead unites these units through the class template duration. That is, in Boost.Chrono all six of the above units are nothing but typedefs to different instantiations of duration. This change from Boost.DateTime 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, with 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 exact.

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 Boost.DateTime, 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.

Boost.Chrono 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.

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 durations is attempted. The tick period is completely ignored when simply doing arithmetic among like durations.

Example:

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

typedef boost::chrono::duration<long long, boost::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 duration's 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).

minutes m4 = m3 + us3;

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.

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

minutes m4 = boost::chrono::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. If 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.

You can use duration_cast<> to convert the duration into whatever units you desire. This facility will round down (truncate) if an exact conversion is not possible. For example:

boost::chrono::nanoseconds start;
boost::chrono::nanoseconds end;
typedef boost::chrono::milliseconds ms;
ms d = boost::chrono::duration_cast<ms>(end - start);

// d now holds the number of milliseconds from start to end.

std::cout << ms.count() << "ms\n";

We can convert to nanoseconds, or some integral-based duration which nanoseconds will always exactly convert to, then duration_cast<> is unnecessary:

typedef boost::chrono::nanoseconds ns;
ns d = end - start;
std::cout << ns.count() << "ns\n";

If you need seconds with a floating-point representation you can also eliminate the duration_cast<>:

typedef boost::chrono::duration<double> sec;  // seconds, stored with a double
sec d = end - start;
std::cout << sec.count() << "s\n";

If you're not sure if you need duration_cast<> or not, feel free to try it without. If the conversion is exact, or if the destination has a floating-point representation, it will compile: else it will not compile.

If you need to use duration_cast<>, but want to round up, instead of down when the conversion is inexact, here is a handy little helper function to do so. Writing it is actually a good starter project for understanding Boost.Chrono:

template <class ToDuration, class Rep, class Period>
ToDuration
round_up(boost::chrono::duration<Rep, Period> d)
{
    // first round down
    ToDuration result = boost::chrono::duration_cast<ToDuration>(d);
    if (result < d)  // comparisons are *always* exact
       ++result;     // increment by one tick period
    return result;
}

typedef boost::chrono::milliseconds ms;
ms d = round_up<ms>(end - start);
// d now holds the number of milliseconds from start to end, rounded up.
std::cout << ms.count() << "ms\n";

Boost.Chrono provides few simple rounding utility functions for working with durations.

// round down
template <class To, class Rep, class Period>
To
floor(const duration<Rep, Period>& d)
{
    return duration_cast<To>(d);
}

// round to nearest, to even on tie
template <class To, class Rep, class Period>
To
round(const duration<Rep, Period>& d)
{
    To t0 = duration_cast<To>(d);
    To t1 = t0;
    ++t1;
    BOOST_AUTO(diff0, d - t0);
    BOOST_AUTO(diff1, t1 - d);
    if (diff0 == diff1)
    {
        if (t0.count() & 1)
            return t1;
        return t0;
    }
    else if (diff0 < diff1)
        return t0;
    return t1;
}
// round up
template <class To, class Rep, class Period>
To
ceil(const duration<Rep, Period>& d)
{
    To t = duration_cast<To>(d);
    if (t < d)
        ++t;
    return t;
}

The beauty of the chrono library is the ease and accuracy with which such conversions can be made. For example to convert from milliseconds (1/1000 of a second), to 1/30 of a second, one must multiply the milliseconds by 0.03. It is common knowledge that you can't exactly represent 0.03 in a computer. Nevertheless round will exactly (with no round off error) detect a tie and round to even when this happens. The differences diff0 and diff1 are not approximate, but exact differences, even when d has the units of millisecond and To is 1/30 of a second. The unit of diff0 and diff1 is 1/3000 of a second which both millisecond and 1/30 of a second exactly convert to (with no truncation error).

Similarly, the comparison t < d in ceil is exact, even when there is no exact conversion between t and d. Example use of rounding functions

#include <iostream>
#include <boost/chrono/chrono_io.hpp>
#include <boost/chrono/floor.hpp>
#include <boost/chrono/round.hpp>
#include <boost/chrono/ceil.hpp>

int main()
{
    using namespace boost::chrono;
    milliseconds ms(2500);
    std::cout << floor<seconds>(ms) << '\n';
    std::cout << round<seconds>(ms) << '\n';
    std::cout << ceil<seconds>(ms) << '\n';
    ms = milliseconds(2516);
    typedef duration<long, boost::ratio<1, 30> > frame_rate;
    std::cout << floor<frame_rate>(ms) << '\n';
    std::cout << round<frame_rate>(ms) << '\n';
    std::cout << ceil<frame_rate>(ms) << '\n';

    return 0;
}

The output of this program should be

2 seconds
2 seconds
3 seconds
75 [1/30]seconds
75 [1/30]seconds
76 [1/30]seconds

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.

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

typedef boost::chrono::duration<double, ratio<60> > dminutes;
dminutes dm4 = m3 + us3;  // dm4.count() == 5.000000083333333

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.

There are several options open to the user:

  • 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(boost::chrono::duration<double> d)  // accept floating-point seconds
{
    // d.count() == 3.e-6 when passed boost::chrono::microseconds(3)
}

f(boost::chrono::microseconds(3));
  • 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(boost::chrono::nanoseconds d)
{
    // d.count() == 3000 when passed boost::chrono::microseconds(3)
}

f(boost::chrono::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.

boost::chrono::duration<double> s(1./3);  // 1/3 of a second
f(boost::chrono::duration_cast<boost::chrono::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
  • 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(boost::chrono::duration<Rep, Period> d)
{
    // convert d to nanoseconds, rounding up if it is not an exact conversion
    boost::chrono::nanoseconds ns = boost::chrono::duration_cast<boost::chrono::nanoseconds>(d);
    if (ns < d)
        ++ns;
    // ns.count() == 333333334 when passed 1/3 of a floating-point second
}

  f(boost::chrono::duration<double>(1./3));
  • 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(boost::chrono::duration<long long, Period> d)
{
    // convert d to nanoseconds, rounding up if it is not an exact conversion
    boost::chrono::nanoseconds ns = boost::chrono::duration_cast<nanoseconds>(d);
    if (ns < d)
        ++ns;
    // ns.count() == 333333334 when passed 333333333333 picoseconds
}
// About 1/3 of a second worth of picoseconds
f(boost::chrono::duration<long long, boost::pico>(333333333333));

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?

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

This depend on the representation. The default typedefs uses a representation that don't handle overflows. The user can define his own representation that manage overflow as required by its application.

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.

The standard defines three system-wide clocks that are associated to the computer time.

  • system_clock represents system-wide realtime clock that can be synchronized with an external clock.
  • steady_clock can not be changed explicitly and the time since the initial epoch increase in a steady way.
  • high_resolution_clock intend to use the system-wide clock provided by the platform with the highest resolution.

Boost.Chrono provides them when supported by the underlying platform. A given platform may not be able to supply all three of these clocks.

The library adds some clocks that are specific to a process or a thread, that is there is a clock per process or per thread.

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 boost::chrono::duration<rep, period> duration;
    typedef boost::chrono::time_point<Clock>     time_point;
    static constexpr bool is_steady =      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 = Clock::now() - t1;

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.

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:

  • 3 minutes after the computer booted.
  • 03:14:07 UTC on Tuesday, January 19, 2038
  • 20 milliseconds after I started that timer.

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 Boost.Chrono, 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.

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()
{
    boost::chrono::steady_clock::time_point start = boost::chrono::steady_clock::now();
    g();
    h();
    duration<double> sec = boost::chrono::steady_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 duration to a known duration. This insulates the code from future changes which may be made to the clock's precision in the future. For example steady_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 = boost::chrono::steady_clock::now() + boost::chrono::nanoseconds(500);
while (boost::chrono::steady_clock::now() < go)
    ;

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

system_clock is useful when you need to correlate the time with a known epoch so you can convert it to a calendar time. Note the specific functions in the system_clock class.

steady_clock is useful when you need to wait for a specific amount of time. steady_clock time can not be reset. As other steady clocks, it is usually based on the processor tick.

Here is a polling solution, but it will probably be too inefficient:

boost::chrono::steady_clock::time_point start= chrono::steady_clock::now();
boost::chrono::steady_clock::duration delay= chrono::seconds(5);
while (boost::chrono::steady_clock::now() - start <= delay) {}

When available, high_resolution_clock is usually more expensive than the other system-wide clocks, so they are used only when the provided resolution is required to the application.

Process and thread clocks are used usually to measure the time spent by code blocks, as a basic time-spent profiling of different blocks of code (Boost.Stopwatch is a clear example of this use).

You can use thread_clock whenever you want to measure the time spent by the current thread. For example:

boost::chrono::thread_clock::time_point start=boost::chrono::thread_clock::now();
// ... do something ...

typedef boost::chrono::milliseconds ms;
ms d = boost::chrono::thread_clock::now() - start;
// d now holds the number of milliseconds from start to end.
std::cout << ms.count() << "ms\n";

If you need seconds with a floating-point representation you can do:

typedef boost::chrono::duration<double> sec;  // seconds, stored with a double.
sec d = end - start;
std::cout << sec.count() << "s\n";

If you would like to programmatically inspect thread_clock::duration, you can get the representation type with thread_clock::rep, and the tick period with thread_clock::period (which should be a type ratio which has nested values ratio::num and ratio::den). The tick period of thread_clock is thread_clock::period::num / thread_clock::period::den seconds: 1/1000000000 in this case (1 billionth of a second), stored in a long long.

I/O

Any duration can be streamed out to a basic_ostream. The run-time value of the duration is formatted according to the rules and current format settings for duration::rep. This is followed by a single space and then the compile-time unit name of the duration. This unit name is built on the string returned from ratio_string<> and the data used to construct the duration_punct which was inserted into the stream's locale. If a duration_punct has not been inserted into the stream's locale, a default constructed duration_punct will be added to the stream's locale.

duration unit names come in two varieties: long and short. The default constructed duration_punct provides names in the long format. These names are English descriptions. Other languages are supported by constructing a duration_punct with the proper spellings for "hours", "minutes" and "seconds", and their abbreviations (for the short format). The short or long format can be easily chosen by streaming a duration_short() or duration_long() manipulator respectively.

A time_point is formatted by outputting its internal duration followed by a string that describes the time_point::clock epoch. This string will vary for each distinct clock, and for each implementation of the supplied clocks.

Example:

#include <iostream>
#include <boost/chrono/chrono_io.hpp>

int main()
{
    using namespace std;
    using namespace boost;

    cout << "milliseconds(3) + microseconds(10) = "
         <<  boost::chrono::milliseconds(3) + boost::chrono::microseconds(10) << '\n';

    cout << "hours(3) + minutes(10) = "
         <<  boost::chrono::hours(3) + boost::chrono::minutes(10) << '\n';

    typedef boost::chrono::duration<long long, boost::ratio<1, 2500000000> > ClockTick;
    cout << "ClockTick(3) + boost::chrono::nanoseconds(10) = "
         <<  ClockTick(3) + boost::chrono::nanoseconds(10) << '\n';

    cout << "\nSet cout to use short names:\n";
    cout << boost::chrono::duration_short;

    cout << "milliseconds(3) + microseconds(10) = "
         <<  boost::chrono::milliseconds(3) + boost::chrono::microseconds(10) << '\n';

    cout << "hours(3) + minutes(10) = "
         <<  boost::chrono::hours(3) + boost::chrono::minutes(10) << '\n';

    cout << "ClockTick(3) + nanoseconds(10) = "
         <<  ClockTick(3) + boost::chrono::nanoseconds(10) << '\n';

    cout << "\nsystem_clock::now() = " << boost::chrono::system_clock::now() << '\n';
#ifdef BOOST_CHRONO_HAS_CLOCK_STEADY
    cout << "steady_clock::now() = " << boost::chrono::steady_clock::now() << '\n';
#endif
    cout << "\nSet cout to use long names:\n"
            << boost::chrono::duration_long
            << "high_resolution_clock::now() = "
            << boost::chrono::high_resolution_clock::now() << '\n';
    return 0;
}

The output could be

milliseconds(3) + microseconds(10) = 3010 microseconds
hours(3) + minutes(10) = 190 minutes
ClockTick(3) + nanoseconds(10) = 56 [1/5000000000]seconds

Set cout to use short names:
milliseconds(3) + microseconds(10) = 3010 [mu]s
hours(3) + minutes(10) = 190 m
ClockTick(3) + nanoseconds(10) = 56 [1/5000000000]s

system_clock::now() = 129387415616250000 [1/10000000]s since Jan 1, 1970
monotonic_clock::now() = 37297387636417 ns since boot

Set cout to use long names:
high_resolution_clock::now() = 37297387655134 nanoseconds since boot

Parsing a duration follows rules analogous to the duration converting constructor. A value and a unit (short or long) are read from the basic_istream. If the duration has an integral representation, then the value parsed must be exactly representable in the target duration (after conversion to the target duration units), else failbit is set. durations based on floating-point representations can be parsed using any units that do not cause overflow.

For example a stream containing "5000 milliseconds" can be parsed into seconds, but if the stream contains "5001 milliseconds", parsing into seconds will cause failbit to be set.

Example:

#include <boost/chrono/chrono_io.hpp>
#include <sstream>
#include <cassert>

int main()
{
    using namespace std;

    istringstream in("5000 milliseconds 4000 ms 3001 ms");
    boost::chrono::seconds d(0);
    in >> d;
    assert(in.good());
    assert(d == seconds(5));
    in >> d;
    assert(in.good());
    assert(d == seconds(4));
    in >> d;
    assert(in.fail());
    assert(d == seconds(4));

    return 0;
}

Note that a duration failure may occur late in the parsing process. This means that the characters making up the failed parse in the stream are usually consumed despite the failure to successfully parse.

Parsing a time_point involves first parsing a duration and then parsing the epoch string. If the epoch string does not match that associated with time_point::clock then failbit will be set.

Example:

#include <boost/chrono/chrono_io.hpp>
#include <sstream>
#include <iostream>
#include <cassert>

int main()
{
    using namespace std;

    boost::chrono::high_resolution_clock::time_point t0 = boost::chrono::high_resolution_clock::now();
    stringstream io;
    io << t0;
    boost::chrono::high_resolution_clock::time_point t1;
    io >> t1;
    assert(!io.fail());
    cout << io.str() << '\n';
    cout << t0 << '\n';
    cout << t1 << '\n';
    boost::chrono::high_resolution_clock::time_point t = boost::chrono::high_resolution_clock::now();
    cout << t << '\n';

    cout << "That took " << t - t0 << '\n';
    cout << "That took " << t - t1 << '\n';

    return 0;
}

The output could be:

50908679121461 nanoseconds since boot
That took 649630 nanoseconds

Here's a simple example to find out how many hours the computer has been up (on this platform):

#include <boost/chrono/chrono_io.hpp>
#include <iostream>

int main()
{
    using namespace std;
    using namespace boost;

    typedef boost::chrono::time_point<boost::chrono::steady_clock, boost::chrono::duration<double, boost::ratio<3600> > > T;
    T tp = boost::chrono::steady_clock::now();
    std::cout << tp << '\n';
    return 0;
}

The output could be:

17.8666 hours since boot

Next we show how to override the duration's default constructor to do anything you want (in this case set it to zero). All we need to do is to change the representation

namespace I_dont_like_the_default_duration_behavior {

template <class R>
class zero_default
{
public:
    typedef R rep;

private:
    rep rep_;
public:
    zero_default(rep i = 0) : rep_(i) {}
    operator rep() const {return rep_;}

    zero_default& operator+=(zero_default x) {rep_ += x.rep_; return *this;}
    zero_default& operator-=(zero_default x) {rep_ -= x.rep_; return *this;}
    zero_default& operator*=(zero_default x) {rep_ *= x.rep_; return *this;}
    zero_default& operator/=(zero_default x) {rep_ /= x.rep_; return *this;}

    zero_default  operator+ () const {return *this;}
    zero_default  operator- () const {return zero_default(-rep_);}
    zero_default& operator++()       {++rep_; return *this;}
    zero_default  operator++(int)    {return zero_default(rep_++);}
    zero_default& operator--()       {--rep_; return *this;}
    zero_default  operator--(int)    {return zero_default(rep_--);}

    friend zero_default operator+(zero_default x, zero_default y) {return x += y;}
    friend zero_default operator-(zero_default x, zero_default y) {return x -= y;}
    friend zero_default operator*(zero_default x, zero_default y) {return x *= y;}
    friend zero_default operator/(zero_default x, zero_default y) {return x /= y;}

    friend bool operator==(zero_default x, zero_default y) {return x.rep_ == y.rep_;}
    friend bool operator!=(zero_default x, zero_default y) {return !(x == y);}
    friend bool operator< (zero_default x, zero_default y) {return x.rep_ < y.rep_;}
    friend bool operator<=(zero_default x, zero_default y) {return !(y < x);}
    friend bool operator> (zero_default x, zero_default y) {return y < x;}
    friend bool operator>=(zero_default x, zero_default y) {return !(x < y);}
};

typedef boost::chrono::duration<zero_default<long long>, boost::nano        > nanoseconds;
typedef boost::chrono::duration<zero_default<long long>, boost::micro       > microseconds;
typedef boost::chrono::duration<zero_default<long long>, boost::milli       > milliseconds;
typedef boost::chrono::duration<zero_default<long long>                      > seconds;
typedef boost::chrono::duration<zero_default<long long>, boost::ratio<60>   > minutes;
typedef boost::chrono::duration<zero_default<long long>, boost::ratio<3600> > hours;
}

Usage

using namespace I_dont_like_the_default_duration_behavior;

milliseconds ms;
std::cout << ms.count() << '\n';

See the source file example/i_dont_like_the_default_duration_behavior.cpp

A "saturating" signed integral type is developed. This type has +/- infinity and a NaN (like IEEE floating-point) but otherwise obeys signed integral arithmetic. This class is subsequently used as the template parameter Rep in boost::chrono::duration to demonstrate a duration class that does not silently ignore overflow.

See the source file example/saturating.cpp

Example round_up utility: converts d to To, rounding up for inexact conversions Being able to easily write this function is a major feature!

#include <boost/chrono.hpp>
#include <boost/type_traits.hpp>

#include <iostream>

template <class To, class Rep, class Period>
To
round_up(boost::chrono::duration<Rep, Period> d)
{
    To result = boost::chrono::duration_cast<To>(d);
    if (result < d)
        ++result;
    return result;
}

To demonstrate interaction with an xtime-like facility:

struct xtime
{
    long sec;
    unsigned long usec;
};

template <class Rep, class Period>
xtime
to_xtime_truncate(boost::chrono::duration<Rep, Period> d)
{
    xtime xt;
    xt.sec = static_cast<long>(boost::chrono::duration_cast<seconds>(d).count());
    xt.usec = static_cast<long>(boost::chrono::duration_cast<microseconds>(d - seconds(xt.sec)).count());
    return xt;
}

template <class Rep, class Period>
xtime
to_xtime_round_up(boost::chrono::duration<Rep, Period> d)
{
    xtime xt;
    xt.sec = static_cast<long>(boost::chrono::duration_cast<seconds>(d).count());
    xt.usec = static_cast<unsigned long>(round_up<boost::chrono::microseconds>(d - boost::chrono::seconds(xt.sec)).count());
    return xt;
}

microseconds
from_xtime(xtime xt)
{
    return boost::chrono::seconds(xt.sec) + boost::chrono::microseconds(xt.usec);
}

void print(xtime xt)
{
    std::cout << '{' << xt.sec << ',' << xt.usec << "}\n";
}

Usage

xtime xt = to_xtime_truncate(seconds(3) + boost::chrono::milliseconds(251));
print(xt);
boost::chrono::milliseconds ms = boost::chrono::duration_cast<boost::chrono::milliseconds>(from_xtime(xt));
std::cout << ms.count() << " milliseconds\n";
xt = to_xtime_round_up(ms);
print(xt);
xt = to_xtime_truncate(boost::chrono::seconds(3) + nanoseconds(999));
print(xt);
xt = to_xtime_round_up(boost::chrono::seconds(3) + nanoseconds(999));
print(xt);

See the source file xtime.cpp

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 3 1/3 nanosecond tick period) or a 3GHz clock (with a tick period of 1/3 of a nanosecond). And the resulting code will be just as efficient as if the user wrote a special purpose clock cycle counter.

#include <boost/chrono.hpp>
#include <boost/type_traits.hpp>
#include <iostream>

template <long long speed>
struct cycle_count
{
    typedef typename boost::__ratio_multiply__<boost::ratio<speed>, boost::mega>::type
        frequency;  // Mhz
    typedef typename boost::__ratio_divide__<boost::ratio<1>, frequency>::type period;
    typedef long long rep;
    typedef boost::chrono::duration<rep, period> duration;
    typedef boost::chrono::time_point<cycle_count> time_point;

    static time_point now()
    {
        static long long tick = 0;
        // return exact cycle count
        return time_point(duration(++tick));  // fake access to clock cycle count
    }
};

template <long long speed>
struct approx_cycle_count
{
    static const long long frequency = speed * 1000000;  // MHz
    typedef nanoseconds duration;
    typedef duration::rep rep;
    typedef duration::period period;
    static const long long nanosec_per_sec = period::den;
    typedef boost::chrono::time_point<approx_cycle_count> time_point;

    static time_point now()
    {
        static long long tick = 0;
        // return cycle count as an approximate number of nanoseconds
        // compute as if nanoseconds is only duration in the std::lib
        return time_point(duration(++tick * nanosec_per_sec / frequency));
    }
};

See the source file cycle_count.cpp

This example demonstrates the use of a timeval-like struct to be used as the representation type for both duration and time_point.

class xtime {
private:
    long tv_sec;
    long tv_usec;

    void fixup() {
        if (tv_usec < 0) {
            tv_usec += 1000000;
            --tv_sec;
        }
    }

public:
    explicit xtime(long sec, long usec) {
        tv_sec = sec;
        tv_usec = usec;
        if (tv_usec < 0 || tv_usec >= 1000000) {
            tv_sec += tv_usec / 1000000;
            tv_usec %= 1000000;
            fixup();
        }
    }

    explicit xtime(long long usec) {
        tv_usec = static_cast<long>(usec % 1000000);
        tv_sec  = static_cast<long>(usec / 1000000);
        fixup();
    }

    // explicit
    operator long long() const {return static_cast<long long>(tv_sec) * 1000000 + tv_usec;}

    xtime& operator += (xtime rhs) {
        tv_sec += rhs.tv_sec;
        tv_usec += rhs.tv_usec;
        if (tv_usec >= 1000000) {
            tv_usec -= 1000000;
            ++tv_sec;
        }
        return *this;
    }

    xtime& operator -= (xtime rhs) {
        tv_sec -= rhs.tv_sec;
        tv_usec -= rhs.tv_usec;
        fixup();
        return *this;
    }

    xtime& operator %= (xtime rhs) {
        long long t = tv_sec * 1000000 + tv_usec;
        long long r = rhs.tv_sec * 1000000 + rhs.tv_usec;
        t %= r;
        tv_sec = static_cast<long>(t / 1000000);
        tv_usec = static_cast<long>(t % 1000000);
        fixup();
        return *this;
    }

    friend xtime operator+(xtime x, xtime y) {return x += y;}
    friend xtime operator-(xtime x, xtime y) {return x -= y;}
    friend xtime operator%(xtime x, xtime y) {return x %= y;}

    friend bool operator==(xtime x, xtime y)
        { return (x.tv_sec == y.tv_sec && x.tv_usec == y.tv_usec); }

    friend bool operator<(xtime x, xtime y) {
        if (x.tv_sec == y.tv_sec)
            return (x.tv_usec < y.tv_usec);
        return (x.tv_sec < y.tv_sec);
    }

    friend bool operator!=(xtime x, xtime y) { return !(x == y); }
    friend bool operator> (xtime x, xtime y) { return y < x; }
    friend bool operator<=(xtime x, xtime y) { return !(y < x); }
    friend bool operator>=(xtime x, xtime y) { return !(x < y); }

    friend std::ostream& operator<<(std::ostream& os, xtime x)
        {return os << '{' << x.tv_sec << ',' << x.tv_usec << '}';}
};

Clock based on timeval-like struct.

class xtime_clock
{
public:
    typedef xtime                                  rep;
    typedef boost::micro                           period;
    typedef boost::chrono::duration<rep, period>   duration;
    typedef boost::chrono::time_point<xtime_clock> time_point;

    static time_point now()
    {
    #if defined(BOOST_CHRONO_WINDOWS_API)
        time_point t(duration(xtime(0)));
        gettimeofday((timeval*)&t, 0);
        return t;

    #elif defined(BOOST_CHRONO_MAC_API)

        time_point t(duration(xtime(0)));
        gettimeofday((timeval*)&t, 0);
        return t;

    #elif defined(BOOST_CHRONO_POSIX_API)
        //time_point t(0,0);

        timespec ts;
        ::clock_gettime( CLOCK_REALTIME, &ts );

        xtime xt( ts.tv_sec, ts.tv_nsec/1000);
        return time_point(duration(xt));

    #endif  // POSIX
    }
};

Usage of xtime_clock

std::cout << "sizeof xtime_clock::time_point = " << sizeof(xtime_clock::time_point) << '\n';
std::cout << "sizeof xtime_clock::duration = " << sizeof(xtime_clock::duration) << '\n';
std::cout << "sizeof xtime_clock::rep = " << sizeof(xtime_clock::rep) << '\n';
xtime_clock::duration delay(boost::chrono::milliseconds(5));
xtime_clock::time_point start = xtime_clock::now();
while (xtime_clock::now() - start <= delay) {}
xtime_clock::time_point stop = xtime_clock::now();
xtime_clock::duration elapsed = stop - start;
std::cout << "paused " << boost::chrono::::nanoseconds(elapsed).count() << " nanoseconds\n";

See the source file example/timeval_demo.cpp

The user can define a function returning the earliest time_point as follows:

template <class Clock, class Duration1, class Duration2>
typename boost::common_type<time_point<Clock, Duration1>,
                     time_point<Clock, Duration2> >::type
min(time_point<Clock, Duration1> t1, time_point<Clock, Duration2> t2)
{
    return t2 < t1 ? t2 : t1;
}

Being able to easily write this function is a major feature!

BOOST_AUTO(t1, system_clock::now() + seconds(3));
BOOST_AUTO(t2, system_clock::now() + nanoseconds(3));
BOOST_AUTO(t3, min(t1, t2));

See the source file example/min_time_point.cpp

#include <boost/chrono.hpp>
#include <iostream>
#include <iomanip>

using namespace boost::chrono;

template< class Clock >
class timer
{
  typename Clock::time_point start;
public:
  timer() : start( Clock::now() ) {}
  typename Clock::duration elapsed() const
  {
    return Clock::now() - start;
  }
  double seconds() const
  {
    return elapsed().count() * ((double)Clock::period::num/Clock::period::den);
  }
};

int main()
{
  timer<system_clock> t1;
  timer<steady_clock> t2;
  timer<high_resolution_clock> t3;

  std::cout << "Type the Enter key: ";
  std::cin.get();

  std::cout << std::fixed << std::setprecision(9);
  std::cout << "system_clock-----------: "
            << t1.seconds() << " seconds\n";
  std::cout << "steady_clock--------: "
            << t2.seconds() << " seconds\n";
  std::cout << "high_resolution_clock--: "
            << t3.seconds() << " seconds\n";

  system_clock::time_point d4 = system_clock::now();
  system_clock::time_point d5 = system_clock::now();

  std::cout << "\nsystem_clock latency-----------: " << (d5 - d4).count() << std::endl;

  steady_clock::time_point d6 = steady_clock::now();
  steady_clock::time_point d7 = steady_clock::now();

  std::cout << "steady_clock latency--------: " << (d7 - d6).count() << std::endl;

  high_resolution_clock::time_point d8 = high_resolution_clock::now();
  high_resolution_clock::time_point d9 = high_resolution_clock::now();

  std::cout << "high_resolution_clock latency--: " << (d9 - d8).count() << std::endl;

  std::time_t now = system_clock::to_time_t(system_clock::now());

  std::cout << "\nsystem_clock::now() reports UTC is "
    << std::asctime(std::gmtime(&now)) << "\n";

  return 0;
}

The output of this program run looks like this:

See the source file example/await_keystroke.cpp

In the example above we take advantage of the fact that time_points convert as long as they have the same clock, and as long as their internal durations convert. We also take advantage of the fact that a duration with a floating-point representation will convert from anything. Finally the I/O system discovers the more readable "hours" unit for our duration<double, ratio<3600>>.

There are many other ways to format durations and time_points. For example see ISO 8601. Instead of coding every possibility into operator<<, which would lead to significant code bloat for even the most trivial uses, this document seeks to inform the reader how to write custom I/O when desired.

As an example, the function below streams arbitrary durations to arbitrary basic_ostreams using the format:

[-]d/hh:mm:ss.cc

Where:

  • d is the number of days
  • h is the number of hours
  • m is the number of minutes
  • ss.cc is the number of seconds rounded to the nearest hundreth of a second
    1. include <boost/chrono/chrono_io.hpp>
    2. include <ostream>
    3. include <iostream>
// format duration as [-]d/hh::mm::ss.cc
template <class CharT, class Traits, class Rep, class Period>
std::basic_ostream<CharT, Traits>&
display(std::basic_ostream<CharT, Traits>& os,
        boost::chrono::duration<Rep, Period> d)
{
    using namespace std;
    using namespace boost;

    typedef boost::chrono::duration<long long, boost::ratio<86400> > days;
    typedef boost::chrono::duration<long long, boost:centi> centiseconds;

    // if negative, print negative sign and negate
    if (d < boost::chrono::duration<Rep, Period>(0))
    {
        d = -d;
        os << '-';
    }
    // round d to nearest centiseconds, to even on tie
    centiseconds cs = boost::chrono::duration_cast<centiseconds>(d);
    if (d - cs > boost::chrono::milliseconds(5)
        || (d - cs == boost::chrono::milliseconds(5) && cs.count() & 1))
        ++cs;
    // separate seconds from centiseconds
    boost::chrono::seconds s = boost::chrono::duration_cast<boost::chrono::seconds>(cs);
    cs -= s;
    // separate minutes from seconds
    boost::chrono::minutes m = boost::chrono::duration_cast<boost::chrono::minutes>(s);
    s -= m;
    // separate hours from minutes
    boost::chrono::hours h = boost::chrono::duration_cast<boost::chrono::hours>(m);
    m -= h;
    // separate days from hours
    days dy = boost::chrono::duration_cast<days>(h);
    h -= dy;
    // print d/hh:mm:ss.cc
    os << dy.count() << '/';
    if (h < boost::chrono::hours(10))
        os << '0';
    os << h.count() << ':';
    if (m < boost::chrono::minutes(10))
        os << '0';
    os << m.count() << ':';
    if (s < boost::chrono::seconds(10))
        os << '0';
    os << s.count() << '.';
    if (cs < boost::chrono::centiseconds(10))
        os << '0';
    os << cs.count();
    return os;
}

int main()
{
    using namespace std;
    using namespace boost;

    display(cout, boost::chrono::steady_clock::now().time_since_epoch()
                  + boost::chrono::duration<long, boost::mega>(1)) << '\n';
    display(cout, -boost::chrono::milliseconds(6)) << '\n';
    display(cout, boost::chrono::duration<long, boost::mega>(1)) << '\n';
    display(cout, -boost::chrono::duration<long, boost::mega>(1)) << '\n';
}

The output could be:

12/06:03:22.95
-0/00:00:00.01
11/13:46:40.00
-11/13:46:40.00

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. Next is a simulation of this interface.

The non-member sleep functions can be emulated as follows:

namespace boost { namespace this_thread {

template <class Rep, class Period>
void sleep_for(const chrono::duration<Rep, Period>& d) {
    chrono::microseconds t = chrono::duration_cast<chrono::microseconds>(d);
    if (t < d)
        ++t;
    if (t > chrono::microseconds(0))
        std::cout << "sleep_for " << t.count() << " microseconds\n";
}

template <class Clock, class Duration>
void sleep_until(const chrono::time_point<Clock, Duration>& t) {
    using namespace chrono;
    typedef time_point<Clock, Duration> Time;
    typedef system_clock::time_point SysTime;
    if (t > Clock::now()) {
        typedef typename common_type<typename Time::duration,
                                     typename SysTime::duration>::type D;
        /* auto */ D d = t - Clock::now();
        microseconds us = duration_cast<microseconds>(d);
        if (us < d)
            ++us;
        SysTime st = system_clock::now() + us;
        std::cout << "sleep_until    ";
        detail::print_time(st);
        std::cout << " which is " << (st - system_clock::now()).count() << " microseconds away\n";
    }
}

}}

Next is the boost::thread::timed_mutex modified fuctions

namespace boost {
struct timed_mutex {
    // ...

    template <class Rep, class Period>
    bool try_lock_for(const chrono::duration<Rep, Period>& d) {
        chrono::microseconds t = chrono::duration_cast<chrono::microseconds>(d);
        if (t <= chrono::microseconds(0))
            return try_lock();
        std::cout << "try_lock_for " << t.count() << " microseconds\n";
        return true;
    }

    template <class Clock, class Duration>
    bool try_lock_until(const chrono::time_point<Clock, Duration>& t)
    {
        using namespace chrono;
        typedef time_point<Clock, Duration> Time;
        typedef system_clock::time_point SysTime;
        if (t <= Clock::now())
            return try_lock();
        typedef typename common_type<typename Time::duration,
          typename Clock::duration>::type D;
        /* auto */ D d = t - Clock::now();
        microseconds us = duration_cast<microseconds>(d);
        SysTime st = system_clock::now() + us;
        std::cout << "try_lock_until ";
        detail::print_time(st);
        std::cout << " which is " << (st - system_clock::now()).count()
          << " microseconds away\n";
        return true;
    }
};
}

boost::thread::condition_variable time related function are modified as follows:

namespace boost {
struct condition_variable
{
    // ...

    template <class Rep, class Period>
    bool wait_for(mutex&, const chrono::duration<Rep, Period>& d) {
        chrono::microseconds t = chrono::duration_cast<chrono::microseconds>(d);
        std::cout << "wait_for " << t.count() << " microseconds\n";
        return true;
    }

    template <class Clock, class Duration>
    bool wait_until(mutex&, const chrono::time_point<Clock, Duration>& t) {
        using namespace boost::chrono;
        typedef time_point<Clock, Duration> Time;
        typedef system_clock::time_point SysTime;
        if (t <= Clock::now())
            return false;
        typedef typename common_type<typename Time::duration,
          typename Clock::duration>::type D;
        /* auto */ D d = t - Clock::now();
        microseconds us = duration_cast<microseconds>(d);
        SysTime st = system_clock::now() + us;
         std::cout << "wait_until     ";
        detail::print_time(st);
        std::cout << " which is " << (st - system_clock::now()).count()
          << " microseconds away\n";
        return true;
    }
};
}

Next follows how simple is the usage of this functions:

boost::mutex m;
boost::timed_mutex mut;
boost::condition_variable cv;

using namespace boost;

this_thread::sleep_for(chrono::seconds(3));
this_thread::sleep_for(chrono::nanoseconds(300));
chrono::system_clock::time_point time_limit = chrono::system_clock::now() + chrono::__seconds_(4) + chrono::milliseconds(500);
this_thread::sleep_until(time_limit);

mut.try_lock_for(chrono::milliseconds(30));
mut.try_lock_until(time_limit);

cv.wait_for(m, chrono::minutes(1));    // real code would put this in a loop
cv.wait_until(m, time_limit);  // real code would put this in a loop

// For those who prefer floating-point
this_thread::sleep_for(chrono::duration<double>(0.25));
this_thread::sleep_until(chrono::system_clock::now() + chrono::duration<double>(1.5));

See the source file example/simulated_thread_interface_demo.cpp

IO

Example use of output in French

#include <boost/chrono/chrono_io.hpp>
#include <iostream>
#include <locale>

int main()
{
    using namespace std;
    using namespace boost;
    using namespace boost::chrono;

    cout.imbue(locale(locale(), new duration_punct<char>
        (
            duration_punct<char>::use_long,
            "secondes", "minutes", "heures",
            "s", "m", "h"
        )));
    hours h(5);
    minutes m(45);
    seconds s(15);
    milliseconds ms(763);
    cout << h << ", " << m << ", " << s << " et " << ms << '\n';
}

Output is:

5 heures, 45 minutes, 15 secondes et 763 millisecondes

See the source file example/french.cpp

C++ Standards Committee's current Working Paper

The most authoritative reference material for the library is the C++ Standards Committee's current Working Paper (WP). 20.11 Time utilities "time"

N2661 - A Foundation to Sleep On

From Howard E. Hinnant, Walter E. Brown, Jeff Garland and Marc Paterno. Is very informative and provides motivation for key design decisions

LGW 934. duration is missing operator%

From Terry Golubiewski. Is very informative and provides motivation for key design decisions

LGW 935. clock error handling needs to be specified

From Beman Dawes. This issue has been stated as NAD Future.


PrevUpHomeNext