Copyright 2007 - CrystalClear Software, Inc -- Date: 2007-09-07
Table of Contents
This paper is a update to N2328 with mostly minor wording clarifications and simplifications. Overall the interfaces defined in N2328 remain mostly unchanged. Some specific kinds of changes in this paper include:
Following this paragraph, the paper provides delta information from N2328 using underlines for additions and striketrhough for removals so prior reviewers can quickly see differences from N2328.
This paper proposes a set of date-time types to support sophisticated temporal interfaces for threading in the next C++ standard. The intent is to replace xtime types in proposal N2285 and its successors (N2320) while giving a smooth evolution path to a full date-time library in TR2 as outlined in N1900 and N2058. Most of the elements of this proposal are fully implemented as part of the Boost Date-Time Library. A draft implementation of the proposal is available at n2328_impl.tar.gz.
Overall, the goal is to support code like this:
std::this_thread::sleep(std::seconds(1)); Lock l; std::condition::timed_wait(l, std::microseconds(100)); std::recursive_timed_mutex rtm; rtm.timed_lock(std::milliseconds(20)); std::utc_time now = std::hiresolution_clock::universal_time(); now += std::nanoseconds(500); std::unique_lock<std::mutex> lk(mut); // Wait for 2 seconds on a condition variable std::utc_time time_out = std::hiresolution_clock::universal_time() + std::seconds(2); { bool timed_out = !cv.timed_wait(lk, time_out); if (timed_out) // deal with time out }
This proposal introduces 3 kinds of types into the standard. These are
A time point represents an instant in the time continuum (dimensionless). A time duration is a length of time unattached to a any time point. Time durations are signed. A clock type is an interface to a device that can return a time point. These three types work together to provide a high level programming interface for C++ developers.
Time durations and time points operate much like built-in integers except that their purpose is to provide calculations in time. To behave like built-int types they provide all of the usual valuetype concepts including: EqualityComparable, LessThanComparable, CopyConstructable, DefaultConstructable, and Assignable. Duration types are behave like signed integers while time points are more like unsigned integers.
Table 2 summarizes the types introduced in the proposal.
description | type | Notes |
---|---|---|
utc_time | time point | Point in time representing a nanosecond resolution time. Epoch for UTC time is same as time_t 1970-01-01 00:00:00.000000000 |
hiresolution_clock | clock | Clock that can produce the current utc_time. |
hours | time duration | Duration type that represents a count of hours. |
minutes | time duration | Duration type that represents a count of minutes. |
seconds | time duration | Duration type that represents a count of seconds. |
milliseconds | time duration | Duration type that represents a count of milliseconds. |
microseconds | time duration | Duration type that represents a count of microseconds. |
nanoseconds | time duration | Duration type that represents a count of nanoseconds. |
utc_time is a simple time_point type that can be used to represent a current time much like time_t but with nanosecond resolution. It represents a time in UTC (Coordinated Universal Time). UTC is a widely used standard based on the solar time at the Prime Meridian (formerly known as Greenwich Mean Time-GMT). The utc_time class works in conjunction with the hiresolution_clock to provide the current time. The various duration types provide for specification and calculations with utc_time.
These temporal types form the foundation for enabling sophisticated calculations using dates and times and well defined. For example, no matter the resolution of time points and durations we can say that the following calculations apply where --> means 'results in'. Note that date-time calculations should be free from 'floating point round-off'.
Rule --> Result Type | Notes |
---|---|
Timepoint + Duration --> Timepoint | Valid only for timepoints of equal or greater resolution than the Duration. |
Timepoint - Duration --> Timepoint | Valid only for timepoints of equal or greater resolution than the Duration. |
Timepoint - Timepoint --> Duration | Timepoints of the same resolution only. |
Duration + Duration --> Duration | In mixed resolution durations, higher resolution duration must the result. |
Duration - Duration --> Duration | In mixed resolution durations, higher resolution duration must the result. |
Duration * Integer --> Duration | Results in a duration. |
Integer * Duration --> Duration | Results in a duration. |
Duration / Integer --> Duration | Integer Division rules. |
Duration + Timepoint --> Timepoint | Valid only for timepoints of equal or greater resolution than the Duration. |
Duration - Timepoint --> Undefined | Compilation error. |
Timepoint + Timepoint --> Undefined | Compilation error. |
As an example, we can see that these rules support code like this:
//duration based calculations std::nanoseconds ns = std::nanoseconds(3) + std::microseconds(3) - std::seconds(3); ns += std::nanoseconds(3); ns = -ns; std::utc_time now = std::hiresolution_clock::universal_time() + std::seconds(1); now += std::nanoseconds(500);
Conversion between duration types is either automatic or results in a compilation error if the conversion would result in a loss of resolution. This is illustrated below:
std::hours h(1); h += std::minutes(10); //compile error -- loss of resolution std::minutes m; m += std::hours(1); //ok, hours can be converted to minutes if (std::minutes(60) > std::hours(1)) //ok, returns false
To support the needed resolution conversions all time points and durations provide resolution trait information. For time durations less than one second the traits provide information to allow conversion to seconds. For time durations greater than one second the traits provide the number of seconds in a duration. The traits functions include is_subsecond, ticks_per_second, and seconds_per_tick. Types with resolutions below 1 second return true to is_subsecond and a decimal based number the provides the ticks_per_second. So, for example, milliseconds returns '1000' for ticks_per_second.
This proposal provides some support for conversion to and from C time types. In particular utc_time can be constructed from a time_t and can provide a time_t value by calling seconds_since_epoch. This seemingly minimal interface provides enough capability for interaction with C and other non-native programs for time handling.
This proposal provides just enough C compatibility to allow users to convert to and from C types -- primarily time_t. The introduction of additional C interfaces or a broader interface raises many hard to resolve issues with the current C APIs and distracts from the intent of this proposal which is to provide support for a rich time interfaces to support multi-threading.
The utc_time class is a very minimal time_point type type as compared to the primary timepoint (datetime) specified for the TR2 proposal. This is intended to keep this proposal for C++0x as small as possible and focused on support for threading.
The proposal provides no input-output functions whereas the TR2 proposal has an extensive input-output specification. This is a simplification to keep the proposal minimal. Before TR2 becomes available, users can convert the types in this proposal to fundamental types to perform input-output.
This proposal, like the TR2 proposal, is careful to separate the representation of a point in time from the clock types that measure a point in time. This decision has several significant advantages as outlined in N1900.
Although utc_time is specified with a resolution of nanoseconds most platforms do not provide hardware and operating system support this resolution. Typical modern platforms can support clock resolutions of microseconds. This proposal does not mandate a particular clock resolution requirement.
Since the tr2 proposal will likely use a different namespace for time types (either tr2 or tr2::datetime), this may create some confusion since the duration types proposed here will already be in namespace std.
It's unclear if Datetime should become it's own chapter or just extend section 20.7 which is the current date and time section under General utilities library.
Text in notes is meant as explanatory information about the proposal. It is not to be added to the standard.
This is an example of a note that is NOT part of the standard text.
All dates and times in this proposal are supplied in ISO extended form unless
otherwise specified. Specifically year-month-day hour:minute:second.fractional_seconds.
So the 15th day of September 2006 is specified as 2006-09-15
.
This clause contains components that C++ programs may use to manipulate dates, times, and timezones.
Time Point: An instant in the time continuum (dimensionless).
Time Duration: A length of time unattached to a any time point. Time durations have an assigned maximum resolution (eg: 1 second).
Epoch: The start of a given time scale. For time_t the epoch is 1970-01-01 00:00:00. In this text the epoch may be called a 'minimum date' or 'minimum time'.
namespace std { //duration types class hours; class minutes; class seconds; class milliseconds; class microseconds; class nanoseconds; //timepoint class utc_time; template<class time_type> class hiresolution_clock;
class utc_time { public: utc_time(); //epoch utc_time(time_t, nanoseconds ns); ~utc_time(); time_t seconds_since_epoch() const; nanoseconds nanoseconds_since_epoch() const; //traits typedef 'implementation defined' tick_type; static tick_type ticks_per_second(); static tick_type seconds_per_tick(); static bool is_subsecond(); //comparison functions bool operator==(const utc_time& rhs) const; bool operator!=(const utc_time& rhs) const; bool operator>(const utc_time& rhs) const; bool operator>=(const utc_time& rhs) const; bool operator<(const utc_time& rhs) const; bool operator<=(const utc_time& rhs) const; //arithmetic functions nanoseconds operator-(const utc_time& rhs) const template<typename time_duration_type> utc_time operator+(const time_duration_type& td) const; template<typename time_duration_type> utc_time& operator+=(const time_duration_type& td); template<typename time_duration_type> utc_time operator-(const time_duration_type& td) const; template<typename time_duration_type> utc_time& operator-=(const time_duration_type& td) };
The class utc_time provides a timepoint that represents the current UTC time. utc_time mustshall provide an epoch timeminimum range of 1970-01-01 00:00:00.000000000 and a maximum time value of at least epoch time + 292 years.
292 years represents the number of nanoseconds that can be represented in a signed 64 bit integer.
utc_time();//epoch
Effects: Constructs a utc_time object representing the epoch time point 1970-01-01 00:00:00.000000000
Throws: Nothing
utc_time(time_t secs, nanoseconds ns);
Effects: Constructs a utc time object where representing the time point that is secs + 1,000,000,000*ns seconds after the epoch represents seconds since 1970-01-01 00:00:00.000000000 and nanoseconds provides an additional nanosecond offset
Remarks: If the total nanoseconds > 1 second the seconds are incremented appropriately
Throws: Nothing
~utc_time();
Effects: Destroys the time point.
Throws: Nothing
time_t seconds_since_epoch() const;
Returns: Returns the count of seconds since 1970-01-01 00:00:00.
Throws: Nothing
nanoseconds nanoseconds_since_epoch() const;
Returns: Returns the count of nanoseconds since 1970-01-01 00:00:00.
Throws: Nothing
static tick_type ticks_per_second();
Returns: Returns 1000000000
Throws: Nothing
static tick_type seconds_per_tick();
Returns: Returns 0
Remarks: Since this is a subsecond type it returns 0 for seconds_per_tick
Throws: Nothing
static bool is_subsecond();
Returns: true.
Throws: Nothing
bool operator==(const utc_time& rhs) const;
Returns: Returns true if rhs is the same timetime represented by *this is equal to the time represented by rhs.
Throws: Nothing
bool operator!=(const utc_time& rhs) const;
Returns: Returns true if rhs is not the same timetime represented by *this is not equal to the time represented by rhs
Throws: Nothing
bool operator>(const utc_time& rhs) const;
Returns: Returns true if time is greater than rhs timerepresented by *this is greater than the time represented by rhs.
Throws: Nothing
bool operator>=(const utc_time& rhs) const;
Returns: Returns true if timeis greater or equal than rhs timerepresented by *this is greater or equal than the time represented by rhs.
Throws: Nothing
bool operator<(const utc_time& rhs) const;
Returns: Returns true if time is less than rhs timerepresented by *this is less than the time represented by rhs.
Throws: Nothing
bool operator<=(const utc_time& rhs) const;
Returns: Returns true if time is less than rhs timerepresented by *this is less or equal than the time represented by rhs.
Throws: Nothing
nanoseconds operator-(const utc_time& rhs) const
Returns: Returns the difference between two times in a nanosecond count. Returns the difference in nanoseconds between the time represented by *this and the time represented by rhs.
Remarks: If rhs is greater the result will be a negative nanosecond count.
Throws: Nothing
template<typename time_duration_type> utc_time operator+(const time_duration_type& td) const;
Returns: Returns the duration converted to nanosecond resolution and added to the time represented by *this.
Throws: Nothing
template<typename time_duration_type> utc_time& operator+=(const time_duration_type& td);
Effects: Convert the duration to nanosecond resolution add to nanoseconds to the time represented by *this.
Returns: Modified value of this.
Throws: Nothing
template<typename time_duration_type> utc_time operator-(const time_duration_type& td) const;
Returns: Returns the duration converted to nanosecond resolution and subtracted from the time represented by *this.
Throws: Nothing
template<typename time_duration_type> utc_time& operator-=(const time_duration_type& td)
Effects: Convert the duration to nanosecond resolution subtract from the time represented by *this and return *this.
Returns: Modified value of this.
Throws: Nothing
template<class time_type> class hiresolution_clock { public: static time_type universal_time(); static tick_type ticks_per_second(); };
The hiresolution_clock provides access to the operating system clock at a resolution up to nanoseconds. The actual resolution will may vary from platform to platform. The time_type parameter provides compatibility for user defined time types as specified in the TR2 proposal.
Typical personal computer platforms currently achieve microsecond level resolution from calls to the clock. The Boost Date-Time Library has a class that portably implements the proposed interface, but it uses different C-level interfaces depending on the operating system.
static time_type universal_time();
Returns: The Current UTC time - equivalent of time_t with fractional sections. An object of time_type that represents the current UTC time as measured from the computer clock.
universal_time is the equivalent of the iso C time call, but with a higher resolution as defined by the platform.
Remarks: Function is thread-safe on platforms supporting threading. Successive Every calls to this function will produce return and value that is equal or greater time value in all casesthan the value returned by any previous call.
Throws: Nothing
static tick_type ticks_per_second();
Returns: The number of ticks in one second provided by the clock implementation.
Throws: Nothing
The following functions are common functions to all durations types. These functions provide the basis for durations to be EqualityComparable, LessThanComparable as well as the usual arithmetic operations.
In the following text duration_type refers to the containing duration type.
class duration_type { //where duration_type== nanoseconds, microseconds, etc //comparison operators template<typename rhs_duration_type> bool operator< (const rhs_duration_type&) const; template<typename rhs_duration_type> bool operator<= (const rhs_duration_type&) const; template<typename rhs_duration_type> bool operator> (const rhs_duration_type&) const; template<typename rhs_duration_type> bool operator>= (const rhs_duration_type&) const; template<typename rhs_duration_type> bool operator== (const rhs_duration_type&) const; template<typename rhs_duration_type> bool operator!= (const rhs_duration_type&) const; //sign inversion duration_type operator-() const //arithmetic operations template<typename rhs_duration_type> duration_type operator- (const rhs_duration_type& d) const template<typename rhs_duration_type> duration_type operator-=(const rhs_duration_type& d) template<typename rhs_duration_type> duration_type operator+ (const rhs_duration_type& d) const template<typename rhs_duration_type> duration_type operator+=(const rhs_duration_type& d) duration_type operator/ (int divisor) const duration_type operator/=(int divisor) duration_type operator* (int rhs) const duration_type operator*=(int divisor) tick_type get_count() const
The following details each of these functions.
template<typename rhs_duration_type> bool operator==(const rhs_duration_type& rhs) const;
Returns: Returns true if rhs duration is greater.
Throws: Nothing
template<typename rhs_duration_type> bool operator!=(const rhs_duration_type& rhs) const;
Returns: Returns true if rhs is not the same time.
Throws: Nothing
template<typename rhs_duration_type> bool operator>(const rhs_duration_type& rhs) const;
Returns: Returns true if the rhs duration is larger.
Throws: Nothing
template<typename rhs_duration_type> bool operator>=(const rhs_duration_type& rhs) const;
Returns: Returns true if greater or equal than the rhs duration.
Throws: Nothing
template<typename rhs_duration_type> bool operator<(const rhs_duration_type& rhs) const;
Returns: Returns true if less than the rhs duration.
Throws: Nothing
template<typename rhs_duration_type> bool operator<=(const rhs_duration_type& rhs) const;
Returns: Returns true if less or equal to the rhs duration.
Throws: Nothing
//sign inversion duration_type operator-() const
Returns: Negated value of the duration.
Throws: Nothing
//arithmetic operations template<typename rhs_duration_type> duration_type operator- (const rhs_duration_type& d) const
Returns: A duration value equal to this-rhs_duration.
Remarks: This will fail to compiler if the rhs_duration_type is of higher resolution.
Throws: Nothing
template<typename rhs_duration_type> duration_type operator-=(const rhs_duration_type& d)
Effects: Modifies to value equal to this-rhs_duration.
Returns: this
Remarks: This will fail to compiler if the rhs_duration_type is of higher resolution.
Throws: Nothing
template<typename rhs_duration_type> duration_type operator+ (const rhs_duration_type& d) const
Returns: Duration equal to this+rhs_duration.
Remarks: This will fail to compiler if the rhs_duration_type is of higher resolution.
Throws: Nothing
template<typename rhs_duration_type> duration_type operator+=(const rhs_duration_type& d)
Effects: Modifies to value equal to this+rhs_duration.
Returns: this
Remarks: This will fail to compiler if the rhs_duration_type is of higher resolution.
Throws: Nothing
duration_type operator/ (int divisor) const
Returns: Duration with value equal to this/divisor according to integer arithmetic rules.
Throws: Nothing
duration_type operator/=(int divisor)
Effects: Change value of this by this/divisor according to integer arithmetic rules.
Returns: this
Throws: Nothing
duration_type operator* (int rhs) const
Returns: Duration with value equal to this*rhs
Throws: Nothing
duration_type operator*=(int rhs)
Effects: Modifies to value equal to this*rhs.
Returns: this
Throws: Nothing
tick_type get_count() const
Returns: Returns the count at the resolution of the time duration type.
Throws: Nothing
class nanoseconds { public: nanoseconds(long long=0); nanoseconds(const nanoseconds& rhs); ~nanoseconds(); //traits information static tick_type ticks_per_second(); static tick_type seconds_per_tick(); static bool is_subsecond(); typedef 'implementation-defined' tick_type; //+ common functions ;
Class nanoseconds represents a count of nanoseconds.
nanoseconds(long long=0);
Effects: Constructs an object with a count of nanoseconds - default is zero.
Throws: Nothing
nanoseconds(const nanoseconds& rhs);
Effects: Copy construction.
Throws: Nothing
~nanoseconds();
Effects: Destruct count.
Throws: Nothing
static tick_type ticks_per_second();
Returns: 1000000000
Throws: Nothing
static tick_type seconds_per_tick();
Returns: 0
Throws: Nothing
static bool is_subsecond();
Returns: true
Throws: Nothing
class microseconds { public: microseconds(long long=0); microseconds(const microseconds& rhs); ~microseconds(); //conversions operator nanoseconds() const //traits information static tick_type ticks_per_second(); static tick_type seconds_per_tick(); static bool is_subsecond(); typedef 'implementation-defined' tick_type; ;
Class microseconds represents a count of microseconds.
microseconds(long long=0);
Effects: Constructs an object with a count of microseconds - default is zero.
Throws: Nothing
microseconds(const microseconds& rhs);
Effects: Copy construction.
Throws: Nothing
~microseconds();
Effects: Destruct count.
Throws: Nothing
//conversions operator nanoseconds() const
Returns: microsecond count converted to nanoseconds
Throws: Nothing
static tick_type ticks_per_second();
Returns: 1000000
Throws: Nothing
static tick_type seconds_per_tick();
Returns: 0
Throws: Nothing
static bool is_subsecond();
Returns: true
Throws: Nothing
class milliseconds { public: milliseconds(int_type=0); milliseconds(const milliseconds& rhs); ~milliseconds(); //conversions operator nanoseconds() const; operator microseconds() const; //traits information static tick_type ticks_per_second(); static tick_type seconds_per_tick(); static bool is_subsecond(); typedef 'implementation-defined' tick_type; };
Class milliseconds represents a count of milliseconds.
milliseconds(long long=0);
Effects: Constructs an object with a count of milliseconds - default is zero.
Throws: Nothing
milliseconds(const milliseconds& rhs);
Effects: Copy construction.
Throws: Nothing
~milliseconds();
Effects: Destruct count.
Throws: Nothing
operator nanoseconds() const
Returns: millisecond count converted to nanoseconds
Throws: Nothing
operator microseconds() const
Returns: millisecond count converted to microseconds
Throws: Nothing
static tick_type ticks_per_second();
Returns: 1000
Throws: Nothing
static tick_type seconds_per_tick();
Returns: 0
Throws: Nothing
static bool is_subsecond();
Returns: true
Throws: Nothing
class seconds { public: seconds(int_type s=0); seconds(const seconds& rhs); ~seconds(); //conversions operator nanoseconds() const operator microseconds() const operator milliseconds() const //traits information static tick_type ticks_per_second(); static tick_type seconds_per_tick(); static bool is_subsecond(); typedef 'implementation-defined' tick_type; };
Class seconds represents a count of seconds.
seconds(long long=0);
Effects: Constructs an object with a count of seconds - default is zero.
Throws: Nothing
seconds(const seconds& rhs);
Effects: Copy construction.
Throws: Nothing
~seconds();
Effects: Destruct count.
Throws: Nothing
operator nanoseconds() const
Returns: second count converted to nanoseconds
Throws: Nothing
operator microseconds() const
Returns: second count converted to microseconds
Throws: Nothing
operator milliseconds() const
Returns: second count converted to milliseconds
Throws: Nothing
static tick_type ticks_per_second();
Returns: 1
Throws: Nothing
static tick_type seconds_per_tick();
Returns: 1
Throws: Nothing
static bool is_subsecond();
Returns: false
Throws: Nothing
class minutes { public: minutes(int_type s=0); minutes(const minutes& rhs); ~minutes(); //conversions operator nanoseconds() const operator microseconds() const operator milliseconds() const operator seconds() const //traits information static tick_type ticks_per_second(); static tick_type seconds_per_tick(); static bool is_subsecond(); typedef 'implementation-defined' tick_type; };
Class minutes represents a count of minutes.
minutes(long long=0);
Effects: Constructs an object with a count of minutes - default is zero.
Throws: Nothing
minutes(const minutes& rhs);
Effects: Copy construction.
Throws: Nothing
~minutes();
Effects: Destruct count.
Throws: Nothing
operator nanoseconds() const
Returns: minute count converted to nanoseconds
Throws: Nothing
operator microseconds() const
Returns: minute count converted to microseconds
Throws: Nothing
operator milliseconds() const
Returns: minute count converted to milliseconds
Throws: Nothing
operator seconds() const
Returns: minute count converted to seconds
Throws: Nothing
static tick_type ticks_per_second();
Returns: 0
Throws: Nothing
static tick_type seconds_per_tick();
Returns: 60
Throws: Nothing
static bool is_subsecond();
Returns: false
Throws: Nothing
class hours { public: hours(int_type s=0); hours(const hours& rhs); ~hours(); //conversions operator nanoseconds() const operator microseconds() const operator milliseconds() const operator seconds() const operator minutes() const //traits information static tick_type ticks_per_second(); static tick_type seconds_per_tick(); static bool is_subsecond(); typedef 'implementation-defined' tick_type; };
Class hours represents a count of hours.
hours(long long=0);
Effects: Constructs an object with a count of hours - default is zero.
Throws: Nothing
hours(const hours& rhs);
Effects: Copy construction.
Throws: Nothing
~hours();
Effects: Destruct count.
Throws: Nothing
operator nanoseconds() const
Returns: hour count converted to nanoseconds
Throws: Nothing
operator microseconds() const
Returns: hour count converted to microseconds
Throws: Nothing
operator milliseconds() const
Returns: hour count converted to milliseconds
Throws: Nothing
operator seconds() const
Returns: hour count converted to seconds
Throws: Nothing
operator minutes() const
Returns: hour count converted to seconds
Throws: Nothing
static tick_type ticks_per_second();
Returns: 0
Throws: Nothing
static tick_type seconds_per_tick();
Returns: 3600
Throws: Nothing
static bool is_subsecond();
Returns: false
Throws: Nothing
First thanks goes to the Boost Community for all the constructive suggestions for evolving Boost Date-Time Library into a great C++ date-time library. Thanks to Howard Hinnant for taking and interest and helping mold this into a reasonable proposal. Additional thanks to Pete Becker and Alisdiar Meredith for comments on N2328 that led to clarifications in this paper. Special thanks goes to my family for allowing me to work on this.