C++11中的chrono 时间对象

     在C++11之前,一直有为如何取得高精度时间这个问题困挠,不同的平台需要用不同的方法来获得。现在C++11提供了chrono。这是一个可以解决所有对时间的需要。


    chrono中提出了三个概念:

        Durations:表示一个时间间隔,可以使用不同的时间单位,如,小时,天,最小到纳秒。也可以自定义特殊的时间间隔。

        Time points:保存一个时间点。如当前时间、明天的这个时候,老婆的生日。等等。。精度可以达到纳秒,或者自定义精度。

        Clocks:一个可以和time points互相转换的时钟。c++11定义了三个时钟:

            system_clock:提供与当前系统时间相同的时钟,每一次调用system_clock::now()将得到系统当前的时间。

            steady_clock:描述一个时间的增量,此时钟永远不减少,相对于system_clock会由于调整系统时间而变化来说,用steady_clock::now()得到的时间将不受此影响。不过可不能从steady_clock去获得当前的时间值,因为它只是一个当前系统的增量值。使用它最好的例子是用它得到一段代码的执行时间。

            high_resolution_clock:一个高精度的时钟,一般来说会等于上面两个时钟当中的一个。


    chrono还提供了两个方法,用来在不同单位的duartions和time_points之间进行转换:

         time_porint_cast:用来转换两个不同精度的time_points,如果精度不够,将会舍弃后面几位。

         duration_cast:用来转换两个不同精度的duration,如果精度不够,将会舍弃后面几位。

    

     下面是几个例子:

    1、让程序暂停一段时间:

#include <chrono>
#include <iostream>

using namespace std::chrono;
using namespace std;
int main(){
	auto t = steady_clock::now();
	do{}
    	while (steady_clock::now() < t + milliseconds(41));
	cout << "这是空41毫秒";
	
	return 0;
}

    注意上面的milliseconds(41),这是一个duartions<long long,milli>类型,同样在chrono当是定义。如果机器够好的话,也可以用纳秒(nanoseconds)。


     2、测试使用了多少时间


#include <chrono>
#include <iostream>
#include <ratio>

using namespace std::chrono;
using namespace std;

int main(){
	auto up = steady_clock::now();
	dosome();
	auto down = steady_clock::now();
	
	auto d = duration_cast<microseconds>(down - up);
	//auto d = duration_cast<duration<double,micro>>(down - up);
	
	printf("用时: %f 微秒 over!",d.count());	
	return 0;
}

     这段代码可以显示你的dosome()方法使用了多少时间。给出的是微秒级的记数。上面的microseconds是一个微秒级的长整型,试着改用注释掉的那句代码试试,会给出微秒为单位1的小数显示。


    3、这个例子显示了如何设置时间间隔的单位和时间的操作。

#include <chrono>
#include <iostream>

using namespace std::chrono;
using namespace std;

int main(){
	//设置一个单位为一天的时间间隔
	duration<int,ratio<60*60*24>> one_day(1);
	
	system_clock::time_point today = system_clock::now();
	system_clock::time_point tomorrow = today + one_day;
	
	time_t tt;
	
	tt = system_clock::to_time_t(today);
	cout << "today is: " << ctime(&tt);
	
	tt = system_clock::to_time_t(tomorrow);
	cout << "tomorrow will be: " << ctime(&tt);
	
	return 0;
}

        上面的例子先定义了一个时间间隔one_day,使用ratio这个比例单位。然后获得当前的系统时间。用当前时间加上时间间隔,就等于明天的时间。


    4、一个很简单的日志功能实现

log.cpp:

#include "log.h"
#include <iostream>
#include <chrono>

using namespace std::chrono;

//指定目录地址的位置
static const char *_dir = "log/";

static FILE *file = nullptr;
static int _level = 10;
static steady_clock::time_point startup = steady_clock::now();

tm milliJS(const long long t){
  tm tt ;
  long long tmp = t / 1000;
  
  tt.tm_sec = tmp % 60;
  tmp /= 60;
  
  tt.tm_min = tmp % 60;
  tmp /= 60;
  
  tt.tm_hour = tmp % 24;
  tmp /= 24;
  
  tt.tm_mday = (int)tmp;
  
  return tt;
}

int _log(int const level,const char *msg){
  //打开用当前年/月/日为文件名的文件。附加内容。
  if(!file){
    time_t curtime = system_clock::to_time_t(system_clock::now());
    tm t = *localtime(&curtime);
  
    char s[sizeof(_dir)/sizeof(_dir[0]) + 20];
    sprintf(s, "%s%04d%02d%02d.log",_dir,t.tm_year+1900,t.tm_mon+1,t.tm_mday);
    file = fopen(s, "a")  ;
  }

  if(level <= _level){
    auto now = steady_clock::now();
    auto d = duration_cast<milliseconds>(now - startup);
    tm notime = milliJS(d.count());
    
    fprintf(file,"%d_%02d:%02d:%02d.%d lev:%d:%s\n",notime.tm_mday,notime.tm_hour,notime.tm_min,notime.tm_sec,(int)d.count() % 1000,level,msg);   
    
    return 1;
  }
  
  return 0;
}

log.h

#ifndef __test__log__
#define __test__log__
#define NOLOG 0
#endif /* defined(__test__log__) */

//将记录一个日志,level代表此日志的等级,在设置的日志等级大于等级此等级参数时才记录日志,否则不记录日志。
//如果NOLOG定义则不产生日志
//返回0为未写入文件
int _log(int level,const char *msg);

#if NOLOG
#define log(level,msg)
#else
#define log(level,msg) _log(level,msg)
#endif

 

    上面例子简单的实现一个日志功能,必须在应用程序目录下面增加log文件夹才能正常记录。同时由于日志文件一直是处于打开状态,未考虑日志文件过大的问题。如在多线程当中使用,有可能会出现奇怪的记录。

    例子当中使用system_clock::to_time_t()转换成我们熟悉的time_t结构。

    语句:static steady_clock::time_point startup = steady_clock::now();获得程序运行时当前的增量,并以此增量做为基础值,每一次记录都会记录下程序运行的时间长度。

     方法milliJS()直接将一个时间间隔值转换成时间长度,显示了在整个结构当中实际上还是使用一个数值代表相对于有时间记录以来的时间数据。在这个程序里面,时间相对于启动程序的那一刻。在此程序当中,无论你如何修改系统时间,都将正确的记录程序运行时长。


    PS:system_clock有to_time_t方法,而steardy_clock没有此方法。虽然没什么意义,不过实在要取它的值的话,可以用steardy_clcok::now()转出来的time_porint的time_since_epoch()方法。同上例转换成需要的时间值。



     总结:C++11的chrono的确可以完成我们所需要时间的任何操作。有人说C++11就象一个全新的编程语言。我现在开始非常认可这一句话!


     参考:http://www.cplusplus.com/reference/chrono/

    

你可能感兴趣的:(C++,时间,11)