1.概述
C++11引入了库,它提供了一组用于处理时间间隔和时间点的实用工具。该库旨在提供一种类型安全且全面的方式来处理与时间相关的操作。
2.主要关键组件
std::ratio:表示的是时间单位,例如std::ratio<1,1>表示1s,std::ratio<60,1>表示1min
std::chrono::duration:表示时间长度,可以表示一天,一个月,一年等等
std::chrono::time_point:表示时间点,定义为自纪元(1900.1.1 00:00:00)以来的持续时间
std::chrono::system_clock:表示系统范围的实时挂钟
std::chrono::steady_clock:一个不受系统时钟调整影响的单调时钟。用于测量时间间隔
std::chrono::duration_cast:在不同的持续时间类型之间进行转换
std::chrono::time_point_cast:在不同的时间点类型之间进行转换
细则
std::ratio
模板定义 template<intmax_t _Nx, intmax_t _Dx = 1> struct ratio;
ratio表示时间单位,它表示的是以Nx/Dx的值表示最小刻度的单位。
ratio<1,1> 表示以1s为最小单位
ratio<60,1> 表示以1min为最小单位
ratio<6060,1> 表示以1h为最小单位
ratio<1,1000> 表示以1毫秒为最小单位
ratio<1,10001000> 表示以1微秒为最小单位
ratio<1,100010001000> 表示以1纳秒为最小单位
std::chrono::duration
模板定义
template<class _Rep,
class _Period>
class duration
{ // represents a time duration
public:
using rep = _Rep;
using period = typename _Period::type;
static_assert(!_Is_duration_v<_Rep>,
"duration can't have duration as first template argument");
static_assert(_Is_ratio_v<_Period>,
"period not an instance of std::ratio");
static_assert(0 < _Period::num,
"period negative or zero");
.......
_Rep为数值类型_Period为ratio类型,主要表示的是一段时间距离。
直接看例子 分别表示1s、1min、 1h、1day等的不同方式
//分别表示1s、1min、 1h、1day的不同方式
std::chrono::duration<int, std::ratio<1, 1>> du_s(1);//最小单位为1秒
std::chrono::duration<int, std::ratio<60, 1>> du_m(1);//最小单位为1min
std::chrono::duration<int, std::ratio<60*60, 1>> du_h(1);//最小单位为h
std::chrono::duration<int, std::ratio<60*60*24, 1>> du_d(1);//最小单位为day
//分别表示1毫秒、1微秒、1纳秒
std::chrono::duration<int, std::ratio<1, 1000>> du_mi(1);//最小单位为1毫秒
std::chrono::duration<int, std::ratio<1, 1000000>> du_mc(1);//最小单位为1微秒
std::chrono::duration<int, std::ratio<1, 1000000000>> du_no(1);//最小单位为1纳秒
//duration还提供了对应的接口函数++ -- *=value 不过这些都是以最小单位为1刻度进行相加时间 例如
du_s * 3; //表示3秒
du_s ++; //表示2秒
du_m * 5; //表示5天
du_m * 3 * 5; //表示15天
//相同类型的duration可以直接相加减不同类型的需要借助std::chrono::duration_cast进行转换成相同类型后再相加
//相同类型
std::chrono::duration<int, std::ratio<60 * 60 * 24, 1>> du_d2(5);
du_d + du_d2; //6day
//不同类型
//(du_d += du_s; //会报错)
//会先将du_s转换成最小单位为day的类型 然后再相加
//因为是小单位转换成大单位所以精度会丢失 既相加后还是1天
du_d += std::chrono::duration_cast<std::chrono::duration<int, std::ratio<60 * 60 * 24, 1>>>(du_s);
std::chrono::time_point
表示某一个时间点 直接看源码
template<class _Clock,
class _Duration = typename _Clock::duration>
class time_point
{ // represents a point in time
public:
using clock = _Clock;
using duration = _Duration;
using rep = typename _Duration::rep;
using period = typename _Duration::period;
static_assert(_Is_duration_v<_Duration>,
"duration must be an instance of std::duration");
constexpr time_point() = default;
constexpr explicit time_point(const _Duration& _Other)
: _MyDur(_Other)
{ // construct from a duration
}
template<class _Duration2,
class = enable_if_t<is_convertible_v<_Duration2, _Duration>>>
constexpr time_point(const time_point<_Clock, _Duration2>& _Tp)
: _MyDur(_Tp.time_since_epoch())
{ // construct from another duration
}
_NODISCARD constexpr _Duration time_since_epoch() const
{ // get duration from epoch
return (_MyDur);
}
_CONSTEXPR17 time_point& operator+=(const _Duration& _Dur)
{ // increment by duration
_MyDur += _Dur;
return (*this);
}
_CONSTEXPR17 time_point& operator-=(const _Duration& _Dur)
{ // decrement by duration
_MyDur -= _Dur;
return (*this);
}
_NODISCARD static constexpr time_point (min)() noexcept // Strengthened, P0972
{ // get minimum time point
return (time_point((_Duration::min)()));
}
_NODISCARD static constexpr time_point (max)() noexcept // Strengthened, P0972
{ // get maximum time point
return (time_point((_Duration::max)()));
}
private:
_Duration _MyDur{duration::zero()}; // duration since the epoch
};
} // namespace chrono
源码内容十分简单 模板类会接收一个Clock模板从Clock模板中获取_Duration,也就是说time_point的最小单位取决于
Clock中的_Duration中的ratio。
与此同时还提供了±=(const _Duration& _Dur)接口用来计算下一时刻、下一段距离后的时刻点
其中提供了time_since_epoch返回内部的_Duration。
clock
上一个类中用到的clock分别有三种类型:system_clock、steady_clock、high_resolution_clock
system_clock
表示系统范围的实时挂钟,也就是电脑时间
上源码
struct system_clock
{ // wraps GetSystemTimePreciseAsFileTime/GetSystemTimeAsFileTime
using rep = long long;
using period = ratio_multiply<ratio<_XTIME_NSECS_PER_TICK, 1>, nano>;
using duration = chrono::duration<rep, period>;
using time_point = chrono::time_point<system_clock>;
static constexpr bool is_steady = false;
_NODISCARD static time_point now() noexcept
{ // get current time
return (time_point(duration(_Xtime_get_ticks())));
}
_NODISCARD static __time64_t to_time_t(const time_point& _Time) noexcept
{ // convert to __time64_t
return ((__time64_t)(_Time.time_since_epoch().count()
/ _XTIME_TICKS_PER_TIME_T));
}
_NODISCARD static time_point from_time_t(__time64_t _Tm) noexcept
{ // convert from __time64_t
return (time_point(duration(_Tm * _XTIME_TICKS_PER_TIME_T)));
}
};
从源码中可以看出system_clock的单位主要是以std::ratio<100,nano>为最小单位。
其中static time_point now()获取的是当前的时间点(从纪元开始算起1900年)。
还提供了两个函数to_time_t和from_time_t分别实现time_point到秒级别的转换。
to_time_t从代码上看
_Time.time_since_epoch().count()表示的是n / std::ratio<100,nano>,其中n是多少秒
例如10s的count为 10 / 100/1000000000 = 100000000
而#define _XTIME_TICKS_PER_TIME_T 10000000LL
则count/_XTIME_TICKS_PER_TIME_T =10s
steady_clock
一个不受系统时钟调整影响的单调时钟。用于测量时间间隔
struct steady_clock
{ // wraps QueryPerformanceCounter
using rep = long long;
using period = nano;
using duration = nanoseconds;
using time_point = chrono::time_point<steady_clock>;
static constexpr bool is_steady = true;
_NODISCARD static time_point now() noexcept
{ // get current time
const long long _Freq = _Query_perf_frequency(); // doesn't change after system boot
const long long _Ctr = _Query_perf_counter();
static_assert(period::num == 1, "This assumes period::num == 1.");
const long long _Whole = (_Ctr / _Freq) * period::den;
const long long _Part = (_Ctr % _Freq) * period::den / _Freq;
return (time_point(duration(_Whole + _Part)));
}
};
using high_resolution_clock = steady_clock;
} // namespace chrono
steady_clock只是用来测量时间间隔的类,简单写个了例子。
std::chrono::time_point p1 = std::chrono::steady_clock::now();
int s = 0;
for (int i = 0; i < 2000000010; i++)
{
s += i;
}
std::chrono::time_point p2 = std::chrono::steady_clock::now();
std::chrono::duration<int, std::ratio<1>> seconde = std::chrono::duration_cast<std::chrono::duration<int, std::ratio<1>>>(p2.time_since_epoch() - p1.time_since_epoch());
std::cout << "seconde: " << seconde.count();
high_resolution_clock
c++11中的high_resolution_clock 和steady_clock一致
即uing high_resolution_clock = steady_clock;
工作中可能会用到当前日期
//获取自1900.1.1 00:00:00到当前的时间点
std::chrono::time_point point = std::chrono::system_clock::now();
//获取自1900.1.1 00:00:00到当前的秒
time_t secondes = std::chrono::system_clock::to_time_t(point);
std::tm* t = std::localtime(&secondes);
std::cout << t->tm_year + 1900 << " " << t->tm_mon + 1 << " " << t->tm_mday<<" ";
std::cout << t->tm_hour << ":" << t->tm_min<< ":" << t->tm_sec;