std的时间函数——chrono

参考:

C++ 标准库 分数运算(ratio库)

再也不被时间束缚:C++ stdchrono时间库全面解析

C++11时间类

c++11 chrono全面解析(最高可达纳秒级别的精度)

C++ std::chrono库使用指南 (实现C++ 获取日期,时间戳,计时等功能)

一、std的分数ratio

    在进行时间库之前,先看看std定义的分数,顺便,看看英文.....

template<intmax_t _Num, intmax_t _Den = 1>
struct ratio
{
    static_assert(_Den != 0, "denominator cannot be zero");
    static_assert(_Num >= -__INTMAX_MAX__ && _Den >= -__INTMAX_MAX__,
		  "out of range");

    // Note: sign(N) * abs(N) == N
    static constexpr intmax_t num =
      _Num * __static_sign<_Den>::value / __static_gcd<_Num, _Den>::value;

    static constexpr intmax_t den =
      __static_abs<_Den>::value / __static_gcd<_Num, _Den>::value;

    typedef ratio<num, den> type;
};

函数原型还是很朴实的,很容易理解,也就是说ratio包括3个成员,num、den和type,num表示分子,den表示分母,type是类型,而且是最简约分形式(说到这,想起一到leetcode题,大概意思就是,给两个数,以字符串输出相除的结果,如果是无限循环小数,比如1/3,就输出0.(3) 这种形式)。

1.1 ratio的函数

例如

type返回的一个是ratio<>,2/7+2/6=13/21
typedef std::ratio_add<std::ratio<2, 7>, std::ratio<2, 6>>::type test;
 
std::cout << test::num << "/" << test::den << std::endl;
std::cout << std::ratio_equal<std::ratio<1, 3>, std::ratio<1, 3>>::value << std::endl;    // true
std::cout << std::ratio_equal<std::ratio<2, 3>, std::ratio<1, 3>>::value << std::endl;    // false
std::cout << std::ratio_greater<std::ratio<2, 3>, std::ratio<1, 3>>::value << std::endl;    // true

1.2 使用注意

  • ratio定义时,其分母不能定义为0,否则编译不通过
  • ratio定义时,如果不填分母,默认为1
  • 如果分子无-号,分母有-号,分母的-号会被移动到分子身上
  • 如果分子有-号,分母无-号,则分子的-号保持不动
  • 如果分子分母都有-号,则-号都被消除
  • 分子可以为0
  • ratio会自动对分子和分母进行约分

例如

//无法编译通过,因为1/max乘以1/2会导致溢出,分母超过了其类型所能涵盖的极限
std::ratio_multiply<std::ratio<1, std::numeric_limits<long long>::max()>, std::ratio<1, 2>>::type;



// 表达式也无法通过编译,因为其除以了0:
typedef ratio<5, 3> FiveThirds;
typedef ratio<0> zero;          //分子为0,分母默认为1
std::ratio_divide<FiveThirds, zero>::type;



// 但是下面的可以编译通过,因为下面只使用了ratio_divide<>,却没有实例化一个ratio<>对象,因此编译器检测不出来
typedef ratio<5, 3> FiveThirds;
typedef ratio<0> zero;
std::ratio_divide<FiveThirds, zero>; //只调用了ratio_divide,却没有实例化出任何ratio对象

1.3 stl的自定义类型

typedef ratio<1, 1000000000000000000LL>  atto;  // 微微微
typedef ratio<1, 1000000000000000LL>     femto; // 飞秒
typedef ratio<1, 1000000000000LL>        pico;  // 皮秒
 
typedef ratio<1, 1000000000>             nano;  // 纳秒
typedef ratio<1, 1000000>                micro; // 微秒
typedef ratio<1, 1000>                   milli; // 毫秒
typedef ratio<1, 100>                    centi; // centi:百分之一
typedef ratio<1, 10>                     deci;  // deci:十分之一
typedef ratio<10, 1>                     deca;  // deci:十倍
typedef ratio<100, 1>                    hecto; // hecto:百倍
typedef ratio<1000, 1>                   kilo;  // 千
typedef ratio<1000000, 1>                mega;  // 兆
typedef ratio<1000000000, 1>             giga;  // 吉
 
typedef ratio<1000000000000LL, 1>        tera;  // 太
typedef ratio<1000000000000000LL, 1>     peta;  // 拍
typedef ratio<1000000000000000000LL, 1>  exa;   // 百亿亿

二、chrono库

    chrono库三大组件:时间段(duration)、时间点(time_point)和时钟(clock)。

2.1 duration

    类模板原型是

template<class _Rep,class _Period>
class duration

其中,_Rep可以理解为数值,Period可以理解为数值单位。例如

std::chrono::duration<int, std::ratio<1, 1>> ts(2)

表示数值是整形,单位是s,也就是表示2s,再例如

std::chrono::duration<float, std::ratio<1, 1>> ts(2.2)

表示数值是float,单位是秒,也就是2.2s

如果想调整数值,可以使用int,float,double。如果想改变单位,就是一切以std::ratio<1, 1>(也就是std::ratio<1>)为基准,比如

std::chrono::duration<float, std::ratio<10, 1>> ts(2.2)
// 等价std::chrono::duration<float, std::deca> ts(2.2)

表示2.2个10s,就是22秒,前面标准库定义了许多比率,可以直接拿来使用。再例如

std::chrono::duration<float, std::ratio<1, 10>> ts(2.2)
// 等价std::chrono::duration<float, std::deci> ts(2.2)

表示2.2个0.1s,也就是0.22s。自然,时间表述有时、分、秒、毫秒、微妙等等,时间chrono定义了这些概念

typedef duration<long long, nano> nanoseconds;
typedef duration<long long, micro> microseconds;
typedef duration<long long, milli> milliseconds;
typedef duration<long long> seconds;
typedef duration<long long, ratio<60>> minutes;
typedef duration<long long, ratio<3600>> hours;

因此上面的0.22s可以表示为

std::chrono::seconds ts(0.22);
// 或者std::chrono::milliseconds ts(220);

2.1.1 操作方法

duration构造的方法包括默认构造,拷贝构造和传递数值构造,例如

std::chrono::duration<int, std::milli> duration0;  // 默认构造
std::chrono::duration<int, std::milli> duration1(500); // 传递数值
std::chrono::duration<double, std::ratio<1, 100>> duration2 = duration1; // 传递duration对象(即使单位不同也性)
// duration0:0  duration1:500  duration2:50

    chrono提供了对duration加减乘除以及比较的方法,例如

std::chrono::duration<int, std::milli> duration1(500);
std::chrono::duration<double, std::nano> duration2(1.5);
std::chrono::duration<float, std::micro> duration3 = duration1 + duration2; // 表示501.5微秒
// std::chrono::duration<int, std::micro> duration3 = duration1 + duration2; // 错误

数值类型int可以转换成double或float,但是double和float不能转换成int,但是double和float两者可以互相转换。

    再例如乘除:

std::chrono::duration<int, std::milli> duration4 = duration1 * 2; // 表示1000毫秒
std::chrono::duration<double, std::milli> duration5 = duration2 / 2; // 表示0.75毫秒

    duration还可以做逻辑比较(<、<=、>、>=、==、!=)例如

std::chrono::duration<int, std::milli> duration1(500);
std::chrono::duration<double, std::nano> duration2(1.5);
bool result = duration1 > duration2; // 返回true,因为500毫秒大于1.5纳秒

     duration还提供了单位转换函数duration_cast,例如

std::chrono::hours hour_time = std::chrono::hours(1);

std::chrono::minutes minutes_time = std::chrono::duration_cast<std::chrono::minutes>(hour_time);

std::chrono::seconds seconds_time = std::chrono::duration_cast<std::chrono::seconds>(hour_time);

std::chrono::milliseconds milliseconds_time = std::chrono::duration_cast<std::chrono::milliseconds>(hour_time);

std::chrono::microseconds microseconds_time = std::chrono::duration_cast<std::chrono::microseconds>(hour_time);

 也就是类型转换函数。

2.2 clock

    时间点就是某时刻的时间点,而想要获得时间点,肯定需要时钟,而chrono提供了3个时钟:system_clock、steady_clock和high_resolution_clock

2.2.1 system_clock

函数原型如下:

struct system_clock{
    typedef chrono::nanoseconds     			duration;
    typedef duration::rep    					rep;
    typedef duration::period 					period;
    typedef chrono::time_point<system_clock, duration> 	time_point;

    static_assert(system_clock::duration::min()
		    < system_clock::duration::zero(),
		    "a clock's minimum duration cannot be less than its epoch");

    static constexpr bool is_steady = false;

    static time_point now() noexcept;

      // Map to C API
    static std::time_t to_time_t(const time_point& __t) noexcept{
	    return std::time_t(duration_cast<chrono::seconds>
			   (__t.time_since_epoch()).count());
    }

    static time_point from_time_t(std::time_t __t) noexcept
    {
	    typedef chrono::time_point<system_clock, seconds>	__from;
	    return time_point_cast<system_clock::duration>(__from(chrono::seconds(__t)));
    }
};

可见system_clock的精度是纳秒,提供了now函数、to_time_t和from_time_t函数接口。

2.2.2 steady_clock

struct steady_clock{
    typedef chrono::nanoseconds 				duration;
    typedef duration::rep	  				    rep;
    typedef duration::period	  				period;
    typedef chrono::time_point<steady_clock, duration> 	time_point;

    static constexpr bool is_steady = true;

    static time_point now() noexcept;
};

 steady_clock的精度是纳秒,只提供了now接口。

2.2.3 high_resolution_clock

using high_resolution_clock = system_clock;

high_resolution_clock就是system_clock。

2.2.4 总结

auto tp0 = std::chrono::system_clock::now();
auto tp1 = std::chrono::steady_clock::now();
auto tp2 = std::chrono::high_resolution_clock::now();

std::cout << tp0.time_since_epoch().count() << std::endl;
std::cout << tp1.time_since_epoch().count() << std::endl;
std::cout << tp2.time_since_epoch().count() << std::endl;

上述输出结果,在我的电脑上 system_clock和high_resolution_clock是相同的,都是从1970年1月1日0时0分0秒开始的,以纳秒为单位的结果。而steady_clock则是从上次开机到现在递增增加的时间结果(这里我的电脑是这样的,ubuntu系统可以通过last reboot或uptime指令查看上次开机时间但是这两个数值可能不一样,只有一个是准确的),单位时纳秒。

  1. system_clock:(1)系统级别的时钟,它表示实时时钟,也就是指示当前时间的时钟。它的时间点是与系统的时钟相关联的,可能受到时钟调整和时区的影响,或者网络自动调整时间。(2)获取当前的系统时间,可以用来进行日常时间计算和显示。它通常被用作默认的时钟类型。
  2. steady_clock:是一个单调递增的时钟,不受任何时钟调整或时区的影响。它提供了一个稳定、可靠的时间基准,适合用于测量时间间隔和计算算法的执行时间。
  3. high_resolution_clock:是一个可用于测量小时间间隔的时钟。它通常使用最高分辨率的时钟源来提供更高的时间精度。在大部分平台上,high_resolution_clock是steady_clock的别名,因此也是一个单调递增的时钟。

2.3 time_point

    结构体原型:

template<typename _Clock, typename _Dur>
struct time_point
{
	typedef _Clock			  			clock;
	typedef _Dur		  				duration;
	typedef typename duration::rep	  	rep;
	typedef typename duration::period	period;

	constexpr time_point() : __d(duration::zero())
	{ }

	constexpr explicit time_point(const duration& __dur)
	    : __d(__dur)
	{ }

	// conversions
	template<typename _Dur2, typename = _Require<is_convertible<_Dur2, _Dur>>>
	constexpr time_point(const time_point<clock, _Dur2>& __t)
	    : __d(__t.time_since_epoch())
	{ }

	// observer
	constexpr duration time_since_epoch() const
	{ return __d; }

	// arithmetic
	_GLIBCXX17_CONSTEXPR time_point& operator+=(const duration& __dur)
	{
	  __d += __dur;
	  return *this;
	}

	_GLIBCXX17_CONSTEXPR time_point& operator-=(const duration& __dur)
	{
	  __d -= __dur;
	  return *this;
	}

	// special values
	static constexpr time_point	min() noexcept
	{ return time_point(duration::min()); }

	static constexpr time_point	max() noexcept
	{ return time_point(duration::max()); }

private:
	duration __d;
};

    time_point则是根据不同的时钟获取时钟的时间点。例如

system_clock::time_point now = system_clock::now();
system_clock::time_point specific_time = system_clock::time_point(seconds(100000));
system_clock::time_point specific_time(seconds(100000));

std::cout << now_sys.time_since_epoch().count() << std::endl;
std::cout << specific_time0.time_since_epoch().count() << std::endl;
std::cout << specific_time1.time_since_epoch().count() << std::endl;

输出

1721640151178784335
100000000000000
100000000000000
  • 8
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值