std::chrono时间

头文件:#include <chrono>

c++11的时间库chrono均位于名字空间std::chrono下。

命名空间:using namespace std::chrono;

宏定义:

#define _XTIME_NSECS_PER_TICK 100
#define _XTIME_TICKS_PER_TIME_T (long long)10000000

时钟

 c++11的时间库chrono简化了时间、日期、时间间隔的计算的编程开发;主要体现于:

    1、基于system_clock、steady_clock、high_resolution_clock的时钟(clock)的确凿时间点(time_point)的获取;

    2、基于不同时间单位、不同时间点之差的时间间隔(duration)的计算;

c++11的时间库chrono均位于名字空间std::chrono下。

 一、clock:

    包括system_clock、steady_clock、high_resolution_clock;

    1、system_clock:系统提供的实时时钟,全部进程使用now()方法获取到的时间都是一样的;

    2、steady_clock:不会被调整的单调时钟, 保证即便进程运行时修改了系统实际,再次调用now()方法,依然能获取到按之前系统时间为基准的当前时间;

    3、high_resolution_clock:是system_clock和steady_clock的typedef

chrono::system_clock::now()
对于system_clock,其起点是epoch,即1970-01-01 00:00:00 UTC,其刻度是1个tick,也就是_XTIME_NSECS_PER_TICK纳秒。

steady_clock这个时钟和system_clock不同,system_clock与系统时间相对应,如果手工调整或者操作系统自动与网络时钟同步时调用system_clock.now()获得的时间也会收到影响,两次调用时,可能第二次调用时获取的时间反而更早。steady_clock保证时间是匀速前进的,不受系统时钟调整的影响。

steady_clock::duration d = steady_clock::now().time_since_epoch();得到的是当前时间与1970.1.1之间的时间间隔。通过类型转换,可以转成各种精度的表示。

该函数的精度是1个tick,即100纳秒;

二、time_point:

    基于clock,可获取时间点time_point,所谓时间点是指某一个确定的时刻,如2018.4.17 17:13:15;

    time_point分为两种形式出现:

    1、名字空间std::chrono下的time_point:

          std::chrono::time_point是一个模板类,需要指定所使用的时钟类(system_clock/steady_clock/high_resolution_clock)和精度(默认为hour级,可自行由std::ratio指定);

//std::chrono::time_point is a template class, not used usually.
std::chrono::time_point<std::chrono::high_resolution_clock, std::chrono::duration<int, std::ratio<60 * 60 * 24>>> now_daylevel = std::chrono::time_point_cast<std::chrono::duration<int, std::ratio<60 * 60 * 24>>>(std::chrono::high_resolution_clock::now());
std::chrono::time_point<std::chrono::high_resolution_clock, std::chrono::duration<int, std::ratio<60 * 60>>> now_hourlevel = std::chrono::time_point_cast<std::chrono::duration<int, std::ratio<60 * 60>>>(std::chrono::high_resolution_clock::now());
std::chrono::time_point<std::chrono::high_resolution_clock, std::chrono::duration<int, std::ratio<60>>> now_minutelevel = std::chrono::time_point_cast<std::chrono::duration<int, std::ratio<60>>>(std::chrono::high_resolution_clock::now());
std::chrono::time_point<std::chrono::high_resolution_clock, std::chrono::duration<int, std::ratio<1>>> now_secondlevel = std::chrono::time_point_cast<std::chrono::duration<int, std::ratio<1>>>(std::chrono::high_resolution_clock::now());
std::chrono::time_point<std::chrono::high_resolution_clock> now_deflevel = std::chrono::time_point_cast<std::chrono::duration<int, std::ratio<60 * 60 * 24>>>(std::chrono::high_resolution_clock::now());

上面分别获取了小时级、分钟级、秒级、默认的4种方式获取的当前时间,然后转为unixtime时间戳:

std::time_t ut_day = std::chrono::high_resolution_clock::to_time_t(now_daylevel);
ut_hour = std::chrono::high_resolution_clock::to_time_t(now_hourlevel);
ut_minute = std::chrono::high_resolution_clock::to_time_t(now_minutelevel);
ut_second = std::chrono::high_resolution_clock::to_time_t(now_secondlevel);
ut_def = std::chrono::high_resolution_clock::to_time_t(now_deflevel);

然后用ctime转化为日期时间格式:

    std::cout << ut_day << std::endl;
    std::cout << ctime(&ut_day) << std::endl;
 
    std::cout << ut_hour << std::endl;
    std::cout << ctime(&ut_hour) << std::endl;
 
    std::cout << ut_minute << std::endl;
    std::cout << ctime(&ut_minute) << std::endl;
 
    std::cout << ut_second << std::endl;
    std::cout << ctime(&ut_second) << std::endl;
 
    std::cout << ut_def << std::endl;
    std::cout << ctime(&ut_def) << std::endl;

观察结果:

 1523923200

            Tue Apr 17 08:00:00 2018------------------day

            1523955600

            Tue Apr 17 17:00:00 2018------------------hour

            1523957460

            Tue Apr 17 17:31:00 2018------------------minute

            1523957497

            Tue Apr 17 17:31:37 2018------------------second

            1523923200

            Tue Apr 17 08:00:00 2018------------------default

   需要掌握的点:

            1、定义一个时间点的方法

                1.1、模板类std::chrono::time_point:

                需要模板实例化:时钟类型(必选,system_clock/steady_clock/high_resolution_clock),精度级别(可选)

               如:std::chrono::time_point<std::chrono::high_resolution_clock, std::chrono::duration<int, std::ratio<60 * 60 * 24>>> now_daylevel = std::chrono::time_point_cast<std::chrono::duration<int, std::ratio<60 * 60 * 24>>>(std::chrono::high_resolution_clock::now());

                这个方式比较麻烦

                1.2、std::chrono::时钟类型::time_point

                  包括:

                    std::chrono::system_clock::time_point

                    std::chrono::steady_clock::time_point

                    std::chrono::high_resolution_clock::time_point

                    如:std::chrono::high_resolution_clock::time_point now = std::chrono::high_resolution_clock::now();

                    这个方式比较简单

            2、time_point到unixtime时间戳的转换:

                方式:std::chrono::时钟类型::to_time_t(time_point)方法

                如:

                std::chrono::high_resolution_clock::time_point now = std::chrono::high_resolution_clock::now();

                std::time_t ut_now = std::chrono::high_resolution_clock::to_time_t(now);

                可以再通过stl的ctime,实现unixtime时间戳,到日期时间格式的转换:

                std::cout << "now: " << ctime(&ut_now);

            3、time_since_epoch方法

                计算从1970年1月1日到现在,经历了多少天、小时、分钟、秒

            4、通过duration实现增量时间的计算

                通过一个时间time_point_1,加减duration,得到另一个时间time_point_2

                见下面duration的介绍
 

#include <chrono>   
using namespace std;
using namespace chrono;

auto start = system_clock::now();
// do something...
auto end   = system_clock::now();
auto duration = duration_cast<microseconds>(end - start);
cout <<  "花费了" 
     << double(duration.count()) * microseconds::period::num / microseconds::period::den   << "秒" << endl;

duration_cast< > 表示类型转换
microseconds 表示微妙。除此之外,还有五种时间单位:hours, minutes, seconds, milliseconds, nanoseconds
num 和 den分别表示分子(numerator)和分母(denominator)。在我给出的代码中,num等于1, den等于1,000,000
count( ) 用来返回时间

steady_clock::duration d = steady_clock::now().time_since_epoch();
minutes min = duration_cast<minutes>(d);
seconds sec = duration_cast<seconds>(d);
milliseconds mil = duration_cast<milliseconds>(d);
microseconds mic = duration_cast<microseconds>(d);
nanoseconds nan = duration_cast<nanoseconds>(d);
cout << min.count() << "分钟" << endl;
cout << sec.count() << "秒" << endl;
cout << mil.count() << "毫秒" << endl;
cout << mic.count() << "微妙" << endl;
cout << nan.count() << "纳秒" << endl;

steady_clock

用在需要得到时间间隔,并且这个时间间隔不会因为修改系统时间而受影响的场景

auto tp1 = std::chrono::steady_clock::now();
//do something
auto tp2 = std::chrono::steady_clock::now();
std::cout << std::chrono::duration_caststd::chrono::microseconds(tp2 - tp1).count() << “microseconds” << std::endl;

获取时间戳

std::time_t getTimeStamp()
{
    std::chrono::time_point<std::chrono::system_clock,std::chrono::milliseconds> tp = std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::system_clock::now());
    auto tmp=std::chrono::duration_cast<std::chrono::milliseconds>(tp.time_since_epoch());
    std::time_t timestamp = tmp.count();
    //std::time_t timestamp = std::chrono::system_clock::to_time_t(tp);
    return timestamp;
}

时间戳转日期

其中int64 为自定义跨平台的数据类型

std::tm* gettm(int64 timestamp)
{
    int64 milli = timestamp+ (int64)8*60*60*1000;//此处转化为东八区北京时间,如果是其它时区需要按需求修改
    auto mTime = std::chrono::milliseconds(milli);
    auto tp=std::chrono::time_point<std::chrono::system_clock,std::chrono::milliseconds>(mTime);
    auto tt = std::chrono::system_clock::to_time_t(tp);
    std::tm* now = std::gmtime(&tt);
    printf("%4d年%02d月%02d日 %02d:%02d:%02d\n",now->tm_year+1900,now->tm_mon+1,now->tm_mday,now->tm_hour,now->tm_min,now->tm_sec);
   return now;
}

三、duration

核心点:

            1、duration表示一个时间段,如"100毫秒"、"一秒"、"2分钟"、"5小时"、"10天"......

            2、duration以秒为基准,通过std::ratio衍生出各自自定义的时间单位,包括不限于:天、小时、分钟、秒、毫秒、微秒、纳秒,stl默认提供了:小时、分钟、秒、毫秒、微秒、纳秒;

            3、duration自身可以做加减运算,如:时间段d3 = 时间段d1 - 时间段d2

            4、duration可以提供duration_cast,由一种时间单位,转换为另一种时间单位,如1小时和60分钟可以互相转换

            5、时刻time_point通过加减duration,可以得到另一个时刻;

            1和2、duration介绍

            std::ratio代表一个比例,或者说比率,它是一个模板类,定义是:

template<intmax_t _Nx, intmax_t _Dx = 1>  
struct ratio  
{    // holds the ratio of _Nx to _Dx  
    static_assert(_Dx != 0, "zero denominator");  
    static_assert(-INTMAX_MAX <= _Nx, "numerator too negative");  
    static_assert(-INTMAX_MAX <= _Dx, "denominator too negative");  
      
    static constexpr intmax_t num = _Sign_of<_Nx>::value  
            * _Sign_of<_Dx>::value * _Abs<_Nx>::value / _Gcd<_Nx, _Dx>::value;  
      
    static constexpr intmax_t den = _Abs<_Dx>::value / _Gcd<_Nx, _Dx>  
            ::value;  
      
    typedef ratio<num, den> type;  
};

                PS: intmax_t是long long

                简言之,_Nx =60且_Dx = 1,那么比率为60,这可以用于代表分钟:               

std::chrono::duration<int, std::ratio<60>> one_minute(1);
std::chrono::duration<int, std::ratio<60>> three_minute(3);

                i. std::chrono::duratio表示时间间隔,基准是1秒;

                ii. 模板实例化的第一个参数int,代表时间间隔的长度是用整型数表示;

                iii. 模板实例化的第二个参数std::ratio<60>,代表时间间隔对秒的比率是60:1,注意ratio的_Dx默认实例化为1,即std::ratio<60>相当于std::ratio<60, 1>;60:1的比率相当于,std::chrono::duration<int, std::ratio<60>>是一个代表一分钟长度的时间间隔的数据结构;

                iv. 根据这个数据结构,构造了对象one_minute,构造参数为1,代表对象one_minute代表了一分钟的时间间隔;又构造了对象three_minute且构造参数为3,代表对象three_minute代表了3分钟的时间间隔;

                如果清楚了分钟的构造原理,那么构造任意时间长度的时间间隔都可行了;

                代码:   

std::chrono::duration<int, std::ratio<3>> three_second(1);
     
    std::chrono::high_resolution_clock::time_point t1 = std::chrono::high_resolution_clock::now();  std::this_thread::sleep_for(three_second);   std::chrono::high_resolution_clock::time_point t2 = std::chrono::high_resolution_clock::now();
     
    std::time_t ut1 = std::chrono::high_resolution_clock::to_time_t(t1), ut2 = std::chrono::high_resolution_clock::to_time_t(t2);
    std::cout << "t1: " << ctime(&ut1);
    std::cout << "t2: " << ctime(&ut2);

                上面的代码意思是,构造一个3秒的时间间隔three_minute,然后记录此时此刻的时间时刻(time_point)t1,然后令当前线程睡眠3秒,线程恢复运行后再次记录此时此刻的时间时刻(time_point)t2,然后输出t1和t2,观察t1和t2是否相差的是3秒;

                前面提到了,time_point可以通过加减duration,得到不同的时刻:   

    std::chrono::high_resolution_clock::time_point now = std::chrono::high_resolution_clock::now();
     
    std::chrono::duration<int, std::ratio<60>> one_minute(1);
    std::chrono::duration<int, std::ratio<60 * 60 * 24>> one_day(1);

    std::chrono::high_resolution_clock::time_point next_minute = now + one_minute;   

    std::chrono::high_resolution_clock::time_point last_minute = now - one_minute;  

    std::chrono::high_resolution_clock::time_point next_day = now + one_day;
    std::chrono::high_resolution_clock::time_point last_day = now - one_day;
     
    std::time_t ut_now = std::chrono::high_resolution_clock::to_time_t(now);
    std::time_t ut_next_minute =  std::chrono::high_resolution_clock::to_time_t(next_minute);
    std::time_t ut_last_minute = std::chrono::high_resolution_clock::to_time_t(last_minute);
    std::time_t ut_next_day = std::chrono::high_resolution_clock::to_time_t(next_day);
    std::time_t ut_last_day = std::chrono::high_resolution_clock::to_time_t(last_day);
     
    std::cout << "now: " << ctime(&ut_now);
    std::cout << "next minute: " << ctime(&ut_last_minute);
    std::cout << "last minute: " << ctime(&ut_next_minute);
    std::cout << "next day: " << ctime(&ut_last_day);
    std::cout << "last day: " << ctime(&ut_next_day);

                上面的代码,首先获取了当前时刻(time_point)now,然后分别构造了时间间隔对象one_minute和one_day,分别代表一分钟和一天,然后通过当前时间分别加减one_minute和one_day,得到了上一分钟、下一分钟、昨天此时此刻、明天此时此刻的时刻(time_point);


  stl已经构造了小时、分钟、秒、毫秒、微秒、纳秒的数据结构,不需要自己通过std::ratio自行构造:

typedef duration <Rep, ratio<3600,1>> hours;
typedef duration <Rep, ratio<60,1>> minutes;
typedef duration <Rep, ratio<1,1>> seconds;
typedef duration <Rep, ratio<1,1000>> milliseconds;
typedef duration <Rep, ratio<1,1000000>> microseconds;
typedef duration <Rep, ratio<1,1000000000>> nanoseconds;

            如下面例子,分别代表令当前线程睡眠一秒钟、1000毫秒、1微秒:

std::this_thread::sleep_for(std::chrono::seconds(1));
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
std::this_thread::sleep_for(std::chrono::microseconds(1));

            时间间隔duration不仅可以被时刻time_point用于加减运算,duration之间也可以做加减运算,如:

std::chrono::seconds tm_span1(10);
std::chrono::minutes tm_span2(1);
std::chrono::seconds tm_span3 = tm_span2 - tm_span1;
std::cout << tm_span3.count() << std::endl;

                首先按秒为单位定义了10秒tm_span1,然后以分钟为单位定义了1分钟tm_span2,两者的差值是50秒,tm_span2 - tm_span1 = 50秒赋值给以秒为单位定义的tm_span3;

               注意:tm_span2 - tm_span1直接赋值给以分钟为单位定义的tm_span4,则会产生编译错误,如果要赋值需要通过duration_cast做结构转换:   

std::chrono::seconds tm_span1(10);
std::chrono::minutes tm_span2(1);
std::chrono::minutes tm_span4 = std::chrono::duration_cast<std::chrono::minutes>(tm_span2 - tm_span1);
std::cout << tm_span4.count() << std::endl;

     duration的count方法,是该duration代表的时间间隔长度,除以其标称单位的结果。如上面例子的tm_span3代表的是50秒的长度,它的时间单位是1秒,所以count方法获取的结果是50。

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值