Document number: Dxxxx=xx-xxxx

Howard Hinnant
2011-07-17

chrono I/O

Introduction

This paper proposes I/O for durations and time_points. This I/O makes use of these types much more convenient. In following the "you only pay for what you use" philosophy, this extra functionality is located in a header separate from <chrono>, namely <chrono_io>.

To facilitate not only duration I/O, but the I/O of client-written types which may make use of ratio (e.g. a class representing length in meters), <ratio_io> is proposed which establishes textural representations of ratios. This textural representation uses SI prefixes whenever possible. This makes it easy for std::milliseconds to be represented by the text "milliseconds", or a hypothetical meter class to print out "millimeter".

system_clock::time_point I/O is proposed in terms of UTC timepoints, strongly guided by ISO 9899:1999, Programming languages — C, ISO 9945:2003, Information Technology — Portable Operating System Interface (POSIX) and ISO 8601:2004, Data elements and interchange formats — Information interchange — Representation of dates and times.

Examples

duration

The following demonstrates duration output for several concrete duration types:

cout << nanoseconds(123) << '\n';               // 123 nanoseconds
cout << microseconds(456) << '\n';              // 456 microseconds
cout << milliseconds(789) << '\n';              // 789 milliseconds
cout << seconds(55) << '\n';                    // 55 seconds
cout << minutes(3) << '\n';                     // 3 minutes
cout << minutes(1) << '\n';                     // 1 minute
cout << hours(24) << '\n';                      // 24 hours
typedef duration<long, ratio<2, 60>> Ticks;
cout << Ticks(44) << '\n';                      // 44 [1/30]seconds
cout << Ticks(1) << '\n';                       // 1 [1/30]second
typedef duration<long, kilo> kilosecond;
cout << kilosecond(2) << '\n';                  // 2 kiloseconds
typedef duration<double> dsec;
cout << dsec(3+1/3.) << '\n';                   // 3.33333 seconds

As can be seen, each duration type can be streamed without having to manually stream the compile-time units after the run-time value. And when the compile-time unit is known to be a "common unit", English names are used. For "uncommon units" a unit name is composed from the reduced numerator and denominator of the associated ratio. Whatever stream/locale settings are set for duration::rep are used for the value. Additionally, when the value is 1, singular forms for the units are used.

Sometimes it is desired to shorten these names by using the SI symbols instead of SI prefixes. This can be accomplished with the use of the duration_short manipulator:

cout << duration_fmt(symbol);
cout << nanoseconds(123) << '\n';               // 123 ns
cout << microseconds(456) << '\n';              // 456 µs
cout << milliseconds(789) << '\n';              // 789 ms
cout << seconds(55) << '\n';                    // 55 s
cout << minutes(3) << '\n';                     // 3 min
cout << hours(24) << '\n';                      // 24 h
typedef duration<long, ratio<2, 60>> Ticks;
cout << Ticks(44) << '\n';                      // 44 [1/30]s
typedef duration<long, kilo> kilosecond;
cout << kilosecond(2) << '\n';                  // 2 ks
typedef duration<double> dsec;
cout << dsec(3+1/3.) << '\n';                   // 3.33333 s

The µ for microsecond is specified to be U+00B5, encoded as UTF-8, UTF-16 or UTF-32 as appropriate for the stream's character size.

You can set the long form back with:

cout << duration_fmt(prefix);

durations can be read using the same format (short or long form). When parsing a duration, the duration type need only to be able to exactly represent the textual type for the parse to be successful. For example one can parse "789 milliseconds" into a duration of type microseconds. The corresponding value parsed will be 789,000. The rules mirror those already established for duration implicit conversions.

Sometimes in templated code it is difficult to know what the unit of your duration is. It is all deterministic, and inspectable. But it can be inconvenient to do so, especially if you just need to print out a "debugging" statement. For example:

// 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;
    auto diff0 = d - t0;
    cout << "diff0 = " << diff0 << '\n';
    auto diff1 = t1 - d;
    cout << "diff1 = " << diff1 << '\n';
    if (diff0 == diff1)
    {
        if (t0.count() & 1)
            return t1;
        return t0;
    }
    else if (diff0 < diff1)
        return t0;
    return t1;
}

This is where I/O for duration really shines. The compiler knows what the type of diff0 is and with this proposal that type (with proper units) will automatically be printed out for you. For example:

milliseconds ms = round<milliseconds>(nanoseconds(123));  // diff0 = 123 nanoseconds
                                                          // diff1 = 999877 nanoseconds
milliseconds ms = round<milliseconds>(Ticks(44));         // diff0 = 2 [1/3000]seconds
                                                          // diff1 = 1 [1/3000]second

This simple I/O will make duration so much more accessible to programmers.

system_clock::time_point

system_clock is special. It is the only clock that has conversions between its time_point and time_t. C subsequently relates time_t to the Gregorian calendar via ctime, gmtime, localtime, and strftime. Neither C, nor POSIX relate time_t to any calendar other than the Gregorian calendar. ISO 8601 is specified only in terms of the Gregorian calendar.

This paper proposes system_clock::time_point I/O in terms of the Gregorian calendar, and no other calendar. However as system_clock::time_point remains convertible with time_t, it is possible for clients to create other calendars which interoperate with time_t and subsequently system_clock::time_point.

Furthermore, it is existing practice for all major hosted operating systems to store system time in a format which facilitates display as Coordinated Universal Time (UTC). Therefore this paper proposes that the default output for system_clock::time_point be in a format that represents a point in time with respect to UTC.

cout << system_clock::now() << '\n';  // 2011-04-24 18:36:59.325132 +0000

This format is strongly influenced by ISO 8601, but places a ' ' between the date and time instead of a 'T'. The former appears to more accurately represent existing practice. A fully numeric format was chosen so as to be understandable to as large a group of human readers as possible. A 24 hour format was chosen for the same reasons.

Of the referenced standards, only ISO 8601 discusses the output of fractional seconds. Neither C nor POSIX have built-in functionality for this. However it appears to be universal (as of this writing) that system_clock::period is sub-second. And it seems desirable that if you stream out a system_clock::time_point, you ought to be able to stream it back in and get the same value. Therefore the streaming of fractional seconds (at least by default) appears to be unavoidable.

Finally the trailing " +0000" disambiguates the UTC-formatted system_clock::time_point from one formatted with respect to the local time zone of the computer. The latter can easily be achieved with:

cout << time_fmt(local) << system_clock::now() << '\n';  // 2011-04-24 14:36:59.325132 -0400

Note that system_clock::time_point itself is neither UTC, nor the local time. Exactly what it is, is unspecified, except to the extent we have already specified it in C++11. However in practice, system_clock::time_point is a count of ticks beyond some epoch which is synchronized with UTC. So as a mobile computer moves across time zones, the time zone traversal does not impact the value of a system_clock::time_point produced by system_clock::now(). And it is only in formatting it for human consumption that one can choose UTC or the local time zone. C and POSIX treat time_t just as this paper proposes we treat system_clock::time_point:

This proposal simply extends the C/POSIX time_t functionality to C++ syntax and system_clock::time_point.

The time_fmt() manipulator is "sticky". It will remain in effect until the stream destructs or until it is changed. The stream can be reset to its default state with:

cout << time_fmt(utc);

And the formatting can be further customized by using the time format sequences as specified in [locale.time.put.members]. For example:

cout << time_fmt(local, "%A %B %e, %Y %r");
cout << system_clock::now() << '\n';  // Sunday April 24, 2011 02:36:59 PM

When specifying formatting manipulators for wide streams, use wide strings.

You can use the same manipulators with istreams to specify parsing sequences as specified in [locale.time.get.members].

Unfortunately there are no formatting/parsing sequences which indicate fractional seconds. This paper does not propose such sequences, but also does not object to adding such sequences to [locale.time.get.members] and [locale.time.put.members]. This is a separable issue and should be treated as such. In the meantime, one can format and parse fractional seconds for system_clock::time_point by defaulting the format, or by using an empty string in time_fmt().

As already specified in [category.time], the stream's current locale may impact the parsing/format sequences supplied to the system_clock::time_point manipulators (e.g. names of days of the week, and names of months).

steady_clock::time_point

Unlike system_clock::time_point, steady_clock::time_point has no conversion with time_t. There is likely no relationship between steady_clock::time_point and UTC at all (UTC is not steady). On Apple's OS, steady_clock::time_point is simply a count of nanoseconds since the computer booted up.

The formatting for steady_clock::time_point is unspecified but should be sufficiently descriptive for a human to understand. One should also be able to parse back in the same string, and get the same value back.

Example:

cout << steady_clock::now() << '\n';  // 22644271279698 nanoseconds since boot

high_resolution_clock::time_point

high_resolution_clock may be an alias for either system_clock or steady_clock. If it is, its I/O will obviously reflect that fact. If it is not an alias, its formatting and parsing is unspecified, but should follow the style for either system_clock or steady_clock.

Example Implementation

There exists an example implementation here for <chrono_io>, chrono_io.cpp and <ratio_io>.

Proposed Wording

Text formatted like this is intended to be rationale for some of the proposed wording. It is not part of the proposed wording.

Header <ratio_io> synopsis

namespace std {

#include <ratio>
#include <string>

template <class Ratio, class charT> struct ratio_string;

template <> struct ratio_string<yocto, char>;      // conditionally supported
template <> struct ratio_string<yocto, char16_t>;  // conditionally supported
template <> struct ratio_string<yocto, char32_t>;  // conditionally supported
template <> struct ratio_string<yocto, wchar_t>;   // conditionally supported

template <> struct ratio_string<zepto, char>;      // conditionally supported
template <> struct ratio_string<zepto, char16_t>;  // conditionally supported
template <> struct ratio_string<zepto, char32_t>;  // conditionally supported
template <> struct ratio_string<zepto, wchar_t>;   // conditionally supported

template <> struct ratio_string<atto, char>;
template <> struct ratio_string<atto, char16_t>;
template <> struct ratio_string<atto, char32_t>;
template <> struct ratio_string<atto, wchar_t>;

template <> struct ratio_string<femto, char>;
template <> struct ratio_string<femto, char16_t>;
template <> struct ratio_string<femto, char32_t>;
template <> struct ratio_string<femto, wchar_t>;

template <> struct ratio_string<pico, char>;
template <> struct ratio_string<pico, char16_t>;
template <> struct ratio_string<pico, char32_t>;
template <> struct ratio_string<pico, wchar_t>;

template <> struct ratio_string<nano, char>;
template <> struct ratio_string<nano, char16_t>;
template <> struct ratio_string<nano, char32_t>;
template <> struct ratio_string<nano, wchar_t>;

template <> struct ratio_string<micro, char>;
template <> struct ratio_string<micro, char16_t>;
template <> struct ratio_string<micro, char32_t>;
template <> struct ratio_string<micro, wchar_t>;

template <> struct ratio_string<milli, char>;
template <> struct ratio_string<milli, char16_t>;
template <> struct ratio_string<milli, char32_t>;
template <> struct ratio_string<milli, wchar_t>;

template <> struct ratio_string<centi, char>;
template <> struct ratio_string<centi, char16_t>;
template <> struct ratio_string<centi, char32_t>;
template <> struct ratio_string<centi, wchar_t>;

template <> struct ratio_string<deci, char>;
template <> struct ratio_string<deci, char16_t>;
template <> struct ratio_string<deci, char32_t>;
template <> struct ratio_string<deci, wchar_t>;

template <> struct ratio_string<deca, char>;
template <> struct ratio_string<deca, char16_t>;
template <> struct ratio_string<deca, char32_t>;
template <> struct ratio_string<deca, wchar_t>;

template <> struct ratio_string<hecto, char>;
template <> struct ratio_string<hecto, char16_t>;
template <> struct ratio_string<hecto, char32_t>;
template <> struct ratio_string<hecto, wchar_t>;

template <> struct ratio_string<kilo, char>;
template <> struct ratio_string<kilo, char16_t>;
template <> struct ratio_string<kilo, char32_t>;
template <> struct ratio_string<kilo, wchar_t>;

template <> struct ratio_string<mega, char>;
template <> struct ratio_string<mega, char16_t>;
template <> struct ratio_string<mega, char32_t>;
template <> struct ratio_string<mega, wchar_t>;

template <> struct ratio_string<giga, char>;
template <> struct ratio_string<giga, char16_t>;
template <> struct ratio_string<giga, char32_t>;
template <> struct ratio_string<giga, wchar_t>;

template <> struct ratio_string<tera, char>;
template <> struct ratio_string<tera, char16_t>;
template <> struct ratio_string<tera, char32_t>;
template <> struct ratio_string<tera, wchar_t>;

template <> struct ratio_string<peta, char>;
template <> struct ratio_string<peta, char16_t>;
template <> struct ratio_string<peta, char32_t>;
template <> struct ratio_string<peta, wchar_t>;

template <> struct ratio_string<exa, char>;
template <> struct ratio_string<exa, char16_t>;
template <> struct ratio_string<exa, char32_t>;
template <> struct ratio_string<exa, wchar_t>;

template <> struct ratio_string<zetta, char>;      // conditionally supported
template <> struct ratio_string<zetta, char16_t>;  // conditionally supported
template <> struct ratio_string<zetta, char32_t>;  // conditionally supported
template <> struct ratio_string<zetta, wchar_t>;   // conditionally supported

template <> struct ratio_string<yotta, char>;      // conditionally supported
template <> struct ratio_string<yotta, char16_t>;  // conditionally supported
template <> struct ratio_string<yotta, char32_t>;  // conditionally supported
template <> struct ratio_string<yotta, wchar_t>;   // conditionally supported

}  // std

Class template <ratio_io>

namespace std {

  template <class Ratio, class charT>
  struct ratio_string
  {
      static basic_string<charT> prefix();
      static basic_string<charT> symbol();
  };

}  // std

The class template ratio_string provides textual representations of the associated ratio appropriate for the character type charT.

The primary template provides generic strings. Specializations provide the same static member functions but these functions return the English SI prefix and symbol names as specified by the General Conference on Weights and Measures.

template<class Ratio, class charT>
basic_string<charT>
ratio_string<Ratio, charT>::prefix();

Returns: A basic_string of the form: [Ratio::num/Ratio::den]

Example: ratio_string<ratio<2, 60>, wchar_t>::prefix() returns L"[1/30]".

template<class Ratio, class charT>
basic_string<charT>
ratio_string<Ratio, charT>::symbol();

Returns: prefix().

For each specialization the table gives the return value for prefix() and symbol().

The return values of specializations of ratio_string
Specializationprefix()symbol()
ratio_string<atto, char>
ratio_string<atto, char16_t>
ratio_string<atto, char32_t>
ratio_string<atto, wchar_t>
"atto"
u"atto"
U"atto"
L"atto"
"a"
u"a"
U"a"
L"a"
ratio_string<femto, char>
ratio_string<femto, char16_t>
ratio_string<femto, char32_t>
ratio_string<femto, wchar_t>
"femto"
u"femto"
U"femto"
L"femto"
"f"
u"f"
U"f"
L"f"
ratio_string<pico, char>
ratio_string<pico, char16_t>
ratio_string<pico, char32_t>
ratio_string<pico, wchar_t>
"pico"
u"pico"
U"pico"
L"pico"
"p"
u"p"
U"p"
L"p"
ratio_string<nano, char>
ratio_string<nano, char16_t>
ratio_string<nano, char32_t>
ratio_string<nano, wchar_t>
"nano"
u"nano"
U"nano"
L"nano"
"n"
u"n"
U"n"
L"n"
ratio_string<micro, char>
ratio_string<micro, char16_t>
ratio_string<micro, char32_t>
ratio_string<micro, wchar_t>
"micro"
u"micro"
U"micro"
L"micro"
u8"\u00B5"
u"\u00B5"
U"\u00B5"
L"\u00B5"
ratio_string<milli, char>
ratio_string<milli, char16_t>
ratio_string<milli, char32_t>
ratio_string<milli, wchar_t>
"milli"
u"milli"
U"milli"
L"milli"
"m"
u"m"
U"m"
L"m"
ratio_string<centi, char>
ratio_string<centi, char16_t>
ratio_string<centi, char32_t>
ratio_string<centi, wchar_t>
"centi"
u"centi"
U"centi"
L"centi"
"c"
u"c"
U"c"
L"c"
ratio_string<deci, char>
ratio_string<deci, char16_t>
ratio_string<deci, char32_t>
ratio_string<deci, wchar_t>
"deci"
u"deci"
U"deci"
L"deci"
"d"
u"d"
U"d"
L"d"
ratio_string<deca, char>
ratio_string<deca, char16_t>
ratio_string<deca, char32_t>
ratio_string<deca, wchar_t>
"deca"
u"deca"
U"deca"
L"deca"
"da"
u"da"
U"da"
L"da"
ratio_string<hecto, char>
ratio_string<hecto, char16_t>
ratio_string<hecto, char32_t>
ratio_string<hecto, wchar_t>
"hecto"
u"hecto"
U"hecto"
L"hecto"
"h"
u"h"
U"h"
L"h"
ratio_string<kilo, char>
ratio_string<kilo, char16_t>
ratio_string<kilo, char32_t>
ratio_string<kilo, wchar_t>
"kilo"
u"kilo"
U"kilo"
L"kilo"
"k"
u"k"
U"k"
L"k"
ratio_string<mega, char>
ratio_string<mega, char16_t>
ratio_string<mega, char32_t>
ratio_string<mega, wchar_t>
"mega"
u"mega"
U"mega"
L"mega"
"M"
u"M"
U"M"
L"M"
ratio_string<giga, char>
ratio_string<giga, char16_t>
ratio_string<giga, char32_t>
ratio_string<giga, wchar_t>
"giga"
u"giga"
U"giga"
L"giga"
"G"
u"G"
U"G"
L"G"
ratio_string<tera, char>
ratio_string<tera, char16_t>
ratio_string<tera, char32_t>
ratio_string<tera, wchar_t>
"tera"
u"tera"
U"tera"
L"tera"
"T"
u"T"
U"T"
L"T"
ratio_string<peta, char>
ratio_string<peta, char16_t>
ratio_string<peta, char32_t>
ratio_string<peta, wchar_t>
"peta"
u"peta"
U"peta"
L"peta"
"P"
u"P"
U"P"
L"P"
ratio_string<exa, char>
ratio_string<exa, char16_t>
ratio_string<exa, char32_t>
ratio_string<exa, wchar_t>
"exa"
u"exa"
U"exa"
L"exa"
"E"
u"E"
U"E"
L"E"

For each of the conditionally supported specializations the table gives the return value for prefix() and symbol(). If the corresponding ratio is supported, then the ratio_string is supported. Else it is not.

Conditionally supported specializations of ratio_string
Specializationprefix()symbol()
ratio_string<yocto, char>
ratio_string<yocto, char16_t>
ratio_string<yocto, char32_t>
ratio_string<yocto, wchar_t>
"yocto"
u"yocto"
U"yocto"
L"yocto"
"y"
u"y"
U"y"
L"y"
ratio_string<zepto, char>
ratio_string<zepto, char16_t>
ratio_string<zepto, char32_t>
ratio_string<zepto, wchar_t>
"zepto"
u"zepto"
U"zepto"
L"zepto"
"z"
u"z"
U"z"
L"z"
ratio_string<zetta, char>
ratio_string<zetta, char16_t>
ratio_string<zetta, char32_t>
ratio_string<zetta, wchar_t>
"zetta"
u"zetta"
U"zetta"
L"zetta"
"Z"
u"Z"
U"Z"
L"Z"
ratio_string<yotta, char>
ratio_string<yotta, char16_t>
ratio_string<yotta, char32_t>
ratio_string<yotta, wchar_t>
"yotta"
u"yotta"
U"yotta"
L"yotta"
"Y"
u"Y"
U"Y"
L"Y"

Header <chrono_io> synopsis

#include <chrono>
#include <ratio_io>

namespace std {
namespace chrono {

enum duration_style {prefix, symbol};
enum timezone {utc, local};

// facets

class durationpunct;
template <class charT> class timepunct;

// manipulators

class duration_fmt;
unspecified time_fmt(timezone tz);
template<class charT>
    unspecified time_fmt(timezone tz, basic_string<charT> f);
template<class charT>
    unspecified time_fmt(timezone tz, const charT* f);

template<class charT, class traits>
basic_ostream<charT, traits>&
operator<<(basic_ostream<charT, traits>& os, duration_fmt d);

template<class charT, class traits>
basic_istream<charT, traits>&
operator>>(basic_istream<charT, traits>& is, duration_fmt d);

// duration I/O

template <class charT, class traits, class Rep, class Period>
  basic_ostream<charT, traits>&
  operator<<(basic_ostream<charT, traits>& os,
             const duration<Rep, Period>& d);

template <class charT, class traits, class Rep, class Period>
  basic_istream<charT, traits>&
  operator>>(basic_istream<charT, traits>& is,
             duration<Rep, Period>& d);

// system_clock I/O

template <class charT, class traits, class Duration>
  basic_ostream<charT, traits>&
  operator<<(basic_ostream<charT, traits>& os,
             const time_point<system_clock, Duration>& tp);

template <class charT, class traits, class Duration>
  basic_istream<charT, traits>&
  operator>>(basic_istream<charT, traits>& is,
             time_point<system_clock, Duration>& tp);

// steady_clock I/O

template <class charT, class traits, class Duration>
  basic_ostream<charT, traits>&
  operator<<(basic_ostream<charT, traits>& os,
             const time_point<steady_clock, Duration>& tp);

template <class charT, class traits, class Duration>
  basic_istream<charT, traits>&
  operator>>(basic_istream<charT, traits>& is,
             time_point<steady_clock, Duration>& tp);

// high_resolution_clock I/O

template <class charT, class traits, class Duration>
  basic_ostream<charT, traits>&
  operator<<(basic_ostream<charT, traits>& os,
             const time_point<high_resolution_clock, Duration>& tp);

template <class charT, class traits, class Duration>
  basic_istream<charT, traits>&
  operator>>(basic_istream<charT, traits>& is,
             time_point<high_resolution_clock, Duration>& tp);

}  // chrono
}  // std

chrono facets

Class durationpunct

namespace std {
namespace chrono {

class durationpunct
    : public locale::facet
{
public:
    static locale::id id;

    explicit durationpunct(size_t refs = 0);
    explicit durationpunct(duration_style fmt, size_t refs = 0);
    
    bool is_symbol_name() const noexcept;
    bool is_prefix_name() const noexcept;
};

}  // chrono
}  // std
explicit durationpunct(size_t refs = 0);

Effects: Constructs a durationpunct by constructing the base class with refs.

Postcondition: is_symbol_name() == false and is_prefix_name() == true.

explicit durationpunct(duration_style fmt, size_t refs = 0);

Requires: fmt has a value of either symbol or prefix.

Effects: Constructs a durationpunct by constructing the base class with refs.

Postcondition: is_symbol_name() == (fmt == symbol) and is_prefix_name() == (fmt == prefix).

bool is_symbol_name() const noexcept;

Returns: true if the stored duration_style is symbol, otherwise false.

bool is_prefix_name() const noexcept;

Returns: true if the stored duration_style is prefix, otherwise false.

Class template timepunct

namespace std {
namespace chrono {

template <class charT>
class timepunct
    : public locale::facet
{
public:
    typedef basic_string<charT> string_type;

    static locale::id id;

    explicit timepunct(size_t refs = 0);
    timepunct(timezone tz, string_type fmt, size_t refs = 0);

    const string_type& fmt() const noexcept;
    chrono::timezone timezone() const noexcept;
};

}  // chrono
}  // std
explicit timepunct(size_t refs = 0);

Effects: Constructs a timepunct by constructing the base class with refs.

Postcondition: fmt() == string_type() and timezone() == utc.

timepunct(timezone tz, string_type f, size_t refs = 0);

Effects: Constructs a timepunct by constructing the base class with refs, and storing tz and fmt.

Postcondition: fmt() == f and timezone() == tz.

const string_type& fmt() const noexcept;

Returns: A reference to the stored format string_type.

chrono::timezone timezone() const noexcept;

Returns: A copy of the stored timezone tz.

Duration and time point manipulators

Class duration_fmt

namespace std {
namespace chrono {

class duration_fmt
{
public:
    explicit duration_fmt(duration_style f) noexcept;
    explicit operator duration_style() const noexcept;
};

template<class charT, class traits>
  basic_ostream<charT, traits>&
  operator<<(basic_ostream<charT, traits>& os, duration_fmt d);

template<class charT, class traits>
  basic_istream<charT, traits>&
  operator>>(basic_istream<charT, traits>& is, duration_fmt d);

}  // chrono
}  // std
explicit duration_fmt(duration_style f) noexcept;

Effects: Constructs a duration_fmt by storing f.

Postcondition: static_cast<duration_style>(*this) == f.

explicit operator duration_style() const noexcept;

Returns: The stored duration_fmt. f.

template<class charT, class traits>
  basic_ostream<charT, traits>&
  operator<<(basic_ostream<charT, traits>& s, duration_fmt d);

template<class charT, class traits>
  basic_istream<charT, traits>&
  operator>>(basic_istream<charT, traits>& s, duration_fmt d);

Effects: s.imbue(locale(s.getloc(), new durationpunct(static_cast<duration_style>(d)))).

Returns: s.

time_fmt

unspecified time_fmt(timezone tz);

Returns: An unspecified object that when streamed to a basic_ostream<charT, traits> or basic_istream<charT, traits> s will have the effects of:

s.imbue(locale(s.getloc(), new timepunct<charT>(tz, basic_string<charT>())));
template<class charT>
    unspecified time_fmt(timezone tz, basic_string<charT> f);
template<class charT>
    unspecified time_fmt(timezone tz, const charT* f);

Returns: An unspecified object that when streamed to a basic_ostream<charT, traits> or basic_istream<charT, traits> s will have the effects of:

s.imbue(locale(s.getloc(), new timepunct<charT>(tz, f)));

duration I/O

template <class charT, class traits, class Rep, class Period>
  basic_ostream<charT, traits>&
  operator<<(basic_ostream<charT, traits>& os,
             const duration<Rep, Period>& d);

Effects: Behaves as a formatted output function ([ostream.formatted.reqmts]). After constructing a sentry object, if the sentry converts to true, sets a local variable style of type duration_style to prefix which serves as a default formatting style. If the stream's locale has a durationpunct facet, then sets style to the value of the duration_style stored within that facet.

Next the units are obtained from Period::type and stored in a basic_string<charT> (e.g. units) according to the following rules:

[Note: The string literals above need to be converted to the correct literal type to be assigned to a basic_string<charT>. — end note]

Finally, as if:

os << d.count() << ' ' << units;

Returns: os.

template <class charT, class traits, class Rep, class Period>
  basic_istream<charT, traits>&
  operator>>(basic_istream<charT, traits>& is,
             duration<Rep, Period>& d);

Effects: Behaves as a formatted input function ([istream.formatted.reqmts]). After constructing a sentry object, if the sentry converts to true, computes an intermediate representation based on Rep according to the following rules:

Next a local variable ir of type intermediate representation is default constructed and extracted from the stream as if by:

IR r;
is >> r;

If the extraction is successful, then an attempt is made to consume a space character. If this fails, is.setstate(ios::failbit) is called.

Otherwise if the next character is '[', an attempt is made to consume a pattern of the form "[N/D]s", "[N/D]second" or "[N/D]seconds" (whichever is longest) where N and D have type unsigned long long. If successful, local variables record the values of N and D, otherwise is.setstate(ios::failbit) is called.

Otherwise the next character is not '['. An attempt is made to parse the longest string possible matching one of the ratio_string SI prefixes or symbols. If successful, local variables record the unsigned long long numerator and denominator associated with the parsed string. If unsuccessful, is.setstate(ios::failbit) is called.

If a unit specifier has successfully been parsed, assume it has been stored as local unsigned long long variables num and den. And in this case compute (num/den)/(Period::num/Period::den) reduced to lowest terms. If this ratio can not be stored without overflow, call is.setstate(ios::failbit). Otherwise store the result of this division in num and den.

If the division did not result in overflow, then compute r * num / den in such a way as to avoid intermediate overflow. If r has integral type and this computation would not be exact, is.setstate(ios::failbit) is called. If the result of the computation would overflow Rep, is.setstate(ios::failbit) is called. Otherwise the result of r * num / den is used to construct a duration<Rep, Period> which is assigned to d.

If at any time end-of-stream is detected, the algorithm calls is.setstate(ios::eofbit).

Returns: is.

system_clock I/O

template <class charT, class traits, class Duration>
  basic_ostream<charT, traits>&
  operator<<(basic_ostream<charT, traits>& os,
             const time_point<system_clock, Duration>& tp);

Effects: Behaves as a formatted output function ([ostream.formatted.reqmts]). After constructing a sentry object, if the sentry converts to true, sets a local variable tz of type timezone to utc which serves as a default formatting style. If the stream's locale has a timepunct facet, then sets tz to the value of the timezone stored within that facet. Additionally the format string stored within the timepunct facet is recorded as a pair of const charT*. If the stream has no timepunct facet, then this pair of const charT* shall reprent an empty range.

Next tp is converted to a time_t, and this time_t is converted to a tm. The conversion to tm shall use gmtime if the timezone is utc, else it shall use localtime.

Using the time_put facet stored in os, this inserter writes characters to the stream using the tm and the formating string stored in the timepunct facet, unless that facet was missing, or unless it provided an empty string.

If the formatting string is empty, then output as follows:

If any step fails, calls os.setstate(ios_base::failbit | ios_base::badbit).

Returns: os.

template <class charT, class traits, class Duration>
  basic_istream<charT, traits>&
  operator>>(basic_istream<charT, traits>& is,
             time_point<system_clock, Duration>& tp);

Effects: Behaves as a formatted input function ([istream.formatted.reqmts]). After constructing a sentry object, if the sentry converts to true, obtains a time_get facet from is, and obtains a formatting string in the same manner as described for insertion operator. Extract a tm using the supplied formatting string, or if empty, defaulted as described for the insertion operator. Note that extraction does not use the timezone data stored in the timepunct facet for the defaulted string as the timezone information is stored in the stream.

Given any timepunct imbued on a basic_iostream, or if the basic_iostream does not have an imbued timepunct, any time_point<system_clock, Duration> inserted, and then extracted should result in an equal time_point<system_clock, Duration>, excepting any precision that did not get inserted.

[Example:

void test(std::chrono::system_clock::time_point tp)
{
    std::stringstream s;
    s << tp;
    std::chrono::system_clock::time_point tp2;
    s >> tp2;
    assert(tp == tp2);
}

end example]

Returns: is.

steady_clock I/O

template <class charT, class traits, class Duration>
  basic_ostream<charT, traits>&
  operator<<(basic_ostream<charT, traits>& os,
             const time_point<steady_clock, Duration>& tp);

Effects: Inserts tp into the stream os in an unspecified form. The form shall be readable by the extraction operator and result in an equal value. The implementation should make the form interpretable by a human reader.

[Example:

22644271279698 nanoseconds since boot

end example]

Returns: os.

template <class charT, class traits, class Duration>
  basic_istream<charT, traits>&
  operator>>(basic_istream<charT, traits>& is,
             time_point<steady_clock, Duration>& tp);

Effects: Extracts tp from the stream os in an unspecified form. The form shall be insertable by the insertion operator and result in an equal value. The implementation should make the form interpretable by a human reader.

Returns: is.

high_resolution_clock I/O

template <class charT, class traits, class Duration>
  basic_ostream<charT, traits>&
  operator<<(basic_ostream<charT, traits>& os,
             const time_point<high_resolution_clock, Duration>& tp);

Effects: Inserts tp into the stream os in an unspecified form. The form shall be readable by the extraction operator and result in an equal value. The implementation should make the form interpretable by a human reader. If high_resolution_clock is an alias for another clock, has the same effects as the extraction operator for that clock.

Returns: os.

template <class charT, class traits, class Duration>
  basic_istream<charT, traits>&
  operator>>(basic_istream<charT, traits>& is,
             time_point<high_resolution_clock, Duration>& tp);

Effects: Extracts tp from the stream os in an unspecified form. The form shall be insertable by the insertion operator and result in an equal value. The implementation should make the form interpretable by a human reader. If high_resolution_clock is an alias for another clock, has the same effects as the insertion operator for that clock.

Returns: is.