转载请注明出处:http://blog.csdn.net/luotuo44/article/details/46854229

C++ 11添加了三个与时间相关的类型:时间段、时钟、时间点。

以史为鉴

现有的系统API中,时间太过于碎片化了。有time_t(秒)、struct timeval(微秒)、struct timespec(纳秒)这几个时间单位,他们的接口非常不统一,点击这里能够体会一下。主要原因:是由于新业务的需求,要求提供不同精度的时间。

于是每次出现新需求就定义一个新类型。

为此,C++11提出一个”一统江湖”的做法,避免这类现象的发生。

       时间精度事实上也就是时间分辨率。

抛开时间量纲单论分辨率。事实上就是一个比率。如:10001、101、11 、110、11000。

这些比率加上距离量纲就变成距离分辨率,加上时间量纲就变成时间分辨率了。为此,C++11定义了一个新的模板类ratio。用于表示比率。定义例如以下:

//#include<ration>
template<std::intmax_t Num, std::intmax_t Denom = 1> //前者是分子,后者是分母
class ratio;

为了方便,C++标准委员会还提前定义了以下这些分辨率,供用户使用。

//#include<ratio>
typedef ratio<1, 1000000000000000000> atto;
typedef ratio<1, 1000000000000000> femto;
typedef ratio<1, 1000000000000> pico;
typedef ratio<1, 1000000000> nano;
typedef ratio<1, 1000000> micro;
typedef ratio<1, 1000> milli;
typedef ratio<1, 100> centi;
typedef ratio<1, 10> deci;
typedef ratio< 10, 1> deca;
typedef ratio< 100, 1> hecto;
typedef ratio< 1000, 1> kilo;
typedef ratio< 1000000, 1> mega;
typedef ratio< 1000000000, 1> giga;
typedef ratio< 1000000000000, 1> tera;
typedef ratio< 1000000000000000, 1> peta;
typedef ratio< 1000000000000000000, 1> exa;

时间段

30分钟。0.5秒都表示一段时间。

由此能够得到:一段时间是由”数值+时间单位”组成的。反映在编程上就是要存储两个变量。显然,数值有整数和小数两种,到底是使用整数(int)还是小数(double)应该由用户指定。无疑。用模板表示之是非常合适的。结合前面提到的时间精度,不难得出一段时间应该定义为例如以下形式:

//#include<chrono>
template<class Rep, class Period = std::ratio<1> >
class duration;

于是,30秒就有以下几种表示方式:

//Author: luotuo44   http://blog.csdn.net/luotuo44
std::chrono::duration<int, std::ratio<1,1>> a(30);//30秒
std::chrono::duration<int> b(30);//30秒
std::chrono::duration<int, std::ratio<1, 1000>> c(30000);//30 000毫秒
std::chrono::duration<double, std::ratio<60,1>> d(0.5);//半分钟

同样,C++标准委员会提前定义了以下这些类型。供我们直接使用。

std::chrono::nanoseconds    duration</*signed integer type of at least 64 bits*/, std::nano>
std::chrono::microseconds duration</*signed integer type of at least 55 bits*/, std::micro>
std::chrono::milliseconds duration</*signed integer type of at least 45 bits*/, std::milli>
std::chrono::seconds duration</*signed integer type of at least 35 bits*/>
std::chrono::minutes duration</*signed integer type of at least 29 bits*/, std::ratio<60>>
std::chrono::hours duration</*signed integer type of at least 23 bits*/, std::ratio<3600>>

又是讨厌的implementation-defined,gcc4.9.0的一个实现为:

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

当定义了一个时间段后,怎样从中得知该时间段类型的rep和period模板參数的类型呢?事实上,当我们用详细的类型实例化duration模板类后,实例化的类就会有rep和period这两个成员类型。

于是,能够借助C++11中的关键字decltype以及直接从定义中获取。

//Author: luotuo44   http://blog.csdn.net/luotuo44
typedef std::chrono::duration<int, std::ratio<60>> Minus;
Minus::rep a = 30; //a是int类型
Minus::period per;//per的类型是 std::ration<60, 1>。 即per.num 为60, per.den 为1 Minus twenty_seconds(20);
decltype(twenty_seconds.count()) b = 30;//后面会介绍count()的返回值类型, b的类型为int
decltype(twenty_seconds)::rep e = 40;//e的类型为int

duration模板类提供了一个成员函数count()用户获取该时间段的值,这个值也称为滴答数。它的返回值类型就是实例化后成员类型rep。

//Author: luotuo44   http://blog.csdn.net/luotuo44
std::chrono::seconds twenty_sec(20);
int c = twenty_sec.count();//c等于20
std::chrono::duration<double> half_sec(0.5);
double d = half_sec.count();//d等于0.5

时钟

时钟有电子表、怀表、秒表、原子钟等。这些时钟的时间精度有所不同。此外,对于电子表的时间是无法取小数的,而怀表则能够人为地取小数。这说明不同的时钟也会有前面时间段类型duration的rep和period这两个属性。而且也是以成员类型的形式出现。但时钟类本身不是模板类。

       C++11为我们提供了三种时钟类型:system_clock、steady_clock、high_resolution_clock。 这三个时间类都提供了rep、period、duration成员类型。

由于各个系统能提供的时间精度可能不同。所以period的真正类型是implementation-defined的。这三个时钟类都提供了一个静态成员函数now()用于获取当前时间,该函数的返回值是一个time_point类型。后面会介绍。

注意:。尽管这三个时钟都非常多同样的成员类型和成员函数。但它们是没有亲缘关系的。

这三个时钟类型都是类。并不是模板类。

这三个时钟有什么差别呢?system_clock就相似Windows系统右下角那个时钟。是系统时间。

明显那个时钟是能够乱设置的。

明明是早上10点,却能够设置成下午3点。steady_clock则针对system_clock能够任意设置这个缺陷而提出来的,他表示时钟是不能设置的。

想了解很多其它,能够点击这里。high_resolution_clock则是一个高分辨率时钟。

       system_clock除了now()函数外,还提供了to_time_t()静态成员函数。用于将系统时间转换成熟悉的std::time_t类型。得到了std::time_t类型的值。就能够非常方便地打印当前时间了。

//Author: luotuo44   http://blog.csdn.net/luotuo44
auto tp = std::chrono::system_clock::now();
std::time_t cur_time = std::chrono::system_clock::to_time_t(tp);
std::string str_time = std::ctime(&cur_time);
std::cout<<str_time<<std::endl;

注意:不要将steady_clock、high_resolution_clock时钟的now()返回值作为to_time_t的參数,这会导致编译通只是。由于类型不匹配。后面会详细解释。

       事实上。假设读者有把刚才那个链接点开,并去了解的steady_clock的话,不用了解now()返回值类型就能知道这样做肯定是不行的了。

steady_clock的实现是使用monotonic时间,而monotonic时间通常是从boot启动后開始计数的。

明显这不能获取日历时间(年月日时分秒)。

那么steady_clock有什么用途呢?时间比較!而且是不受用户调整系统时钟影响的时间比較。

简单的样例例如以下:

//Author: luotuo44   http://blog.csdn.net/luotuo44
auto begin = std::chrono::steady_clock::now();
for(int i = 0; i < 10000000; ++i)
{
//复杂的数学运算
}
auto end = std::chrono::steady_clock::now();
auto diff = (end - begin).count();//end-begin得到一个duration类型
std::cout<<diff<<std::endl;

即使在做数学运算的时候,有人改动了系统时间。也能准确计算出for循环消耗的时间。

时间点

前面已经指出:时钟类的now()函数的返回值是一个time_point类(型)。不言而喻。时间点(time_point)必定是时钟相关的。从怀表读取到的时间(点)唯独小时、分钟、秒,手机则能提供日期+时分秒。

此外。不同一时候钟提供的时间精度也有所不同。所以,时间点(time_point)类至少得有时钟类型、时间精度这两个属性。

同前面介绍的时间段模板类一样。这两个属性也是以模板參数的形式出现。

time_point的定义例如以下:

//#include<chrono>
template< class Clock, class Duration = typename Clock::duration >
class time_point;

时间精度是duration类,默认的时钟模板參数提供的duration。时钟模板參数除了前面介绍的那三个时钟(这是C++默认提供的)外,还能够是码农自定义的时钟类。

同前面的时间段类和时钟类一样,时间点类也提供了rep、period、duration、clock这几个成员类型。

前面已经指出,各个时钟能提供的时间精度是implementation-defined的。

所以应该如以下代码那样获取时钟的now()函数返回值。

auto tp = std::chrono::system_clock::now();
std::chrono::system_clock::time_point tp = std::chrono::system_clock::now();

以下代码是不对的,不具有可移植性。样例来自stackoverflow

std::chrono::time_point<std::chrono::system_clock,std::chrono::nanoseconds> time_point;
time_point = std::chrono::system_clock::now();

除了从时钟类的now函数中获取一个time_point,还能够直接构造一个time_point对象。

time_point模板类的构造函数有无參的、用duration作为參数这两个构造函数。对此,我感到非常奇怪:直接构造出来的time_point有什么含义呢?

time_point有一个time_since_epoch()成员函数。返回从epoch时间到此刻的时间段。

epoch时间是时钟的开启时间。

对于system_clock和high_resolution_clock来说,epoch是1970-01-01T00:00:00。熟悉C语言time()函数的读者对此应该不陌生。

steady_clock时钟则是boot启动时间,所以不应该对steady_clock::now()返回的time_point调用time_since_epoch()。以下是霸王强上弓使用,打印出来的时间是1970年的。

//Author: luotuo44   http://blog.csdn.net/luotuo44
auto tp = std::chrono::steady_clock::now();
std::time_t cur_time = std::chrono::duration_cast<std::chrono::seconds>(tp.time_since_epoch()).count();
std::string str_time = std::ctime(&cur_time);
cout<<str_time<<endl;

假设time_point不是从时钟类的now()返回值得来的,而是直接构造出来的话,那么它调用time_since_epoch()的返回值就等同于构造函数中的duration參数。

运算

一段时间的加减乘除无疑是合理的,当然关系比較也是合理的。C++标准委员会还把取模运算也变成合法的了,不只模一个数值合法,模duration类也是合法的。于是有以下这些运算:

详细的使用样例就不写了。读者能够參考en.cppreference.com

       上面的运算都是二元运算,假设參与运算的两个duration具有同样的模板參数。那直接执行就可以。假设不同,那么将发生隐式转换:int->double; 低分辨率->高分辨率。比方:

//Author: luotuo44   http://blog.csdn.net/luotuo44
std::chrono::duration<int> two(2);
std::chrono::duration<double, std::ratio<60>> thirty(0.5); auto ad = two + thirty;
cout<<sizeof(decltype(ad)::rep)<<endl;//8
cout<<ad.count()<<"\t"<<decltype(ad)::period::num<<"/"<<decltype(ad)::period::den<<endl;//32 1/1

假设參与运算的两个duration具有不同的模板參数。那么能不能进行+=和-=这里运算呢?a+=b等同于a=a+b。a+b肯定是能够的,如今问题转换为a=c是否可行?从低精度(包括Rep和Period)到高精度的隐式转换是可行的,反之则是不能够的。由于这将导致截断。丢失部分信息。

//Author: luotuo44   http://blog.csdn.net/luotuo44
std::chrono::minutes a(30);
std::chrono::seconds b = a;//OK
std::chrono::minutes c = b;//compile error std::chrono::duration<double, std::ratio<60>> d(3);
std::chrono::seconds e = d;//compile error
std::chrono::duration<double> f = d;//OK

假设确实须要进行转换的话,那么须要使用duration_cast进行显式转换。

//Author: luotuo44   http://blog.csdn.net/luotuo44
std::chrono::seconds a(30);
std::chrono::minutes b = std::chrono::duration_cast<std::chrono::minutes>(a);
cout<<b.count()<<endl;//结果是0 //以下是system_clock时钟类to_time_t函数的gcc实现
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());
}

time_point类也有一些运算,例如以下图:

gcc4.9.0实现time_point模板类时,time_point内部有一个duration类型的成员变量。所以对于tp+=d和dp-=d的实现,都是直接对内部的成员变量直接调用+=,-=。所以调用者必须保证精度的正确性,否则编译出错。

C++11时间具体解释的更多相关文章

  1. c++11 时间类 std::chrono

    概念: chrono库:主要包含了三种类型:时间间隔Duration.时钟Clocks和时间点Time point. Duration:表示一段时间间隔,用来记录时间长度,可以表示几秒钟.几分钟或者几 ...

  2. C++11时间操作

    C++11提供了chrono库,这个库可以处理和时间相关的一些事情.这个库里面主要有3个类:时间间隔Duration.时钟Clocks和时间点Time point. Duration template ...

  3. hibernate 1-1(具体解释)

    版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/qilixiang012/article/details/27870343 域模型 关系数据模型: 依 ...

  4. Tuxedo 超时时间控制(转贴)

    以下是转贴: TUXEDO超时控制全功略 摘要: 本<功略>集中了TUXEDO应用中,可能涉及到的所有时间参数,并分别对其进行详细描述,不但对其出处.取值等基本属性进行查证,而且,通过分析 ...

  5. 使用 cURL 获取站点的各类响应时间 – dns解析时间,响应时间,传输时间

    http://zhangrenfang8738.blog.163.com/blog/static/95401881201142711450245/ curl监控站点响应时间 2011-05-27 11 ...

  6. Linux系统中时间区域和API

    1.问题 在开发云平台程序的时候,经常会碰到时间区域转换的问题.比如,任何网络存储的文档的metadata都自己记录了编辑时间.但是,云平台记录时需要把这个时间转成标准时间,便于管理.但是用户使用的时 ...

  7. Java日期时间实用工具类

    Java日期时间实用工具类 1.Date (java.util.Date)    Date();        以当前时间构造一个Date对象    Date(long);        构造函数   ...

  8. 我从没理解js的闭包,直到他人向我这么解释。。。

    前段时间根据执行上下文写过一次闭包,但是写的简陋些.昨天在twitter上看到这篇文章,感觉背包的比喻挺恰当的.所以就翻译了. 这篇文章有些啰嗦,但是讲解很细,希望还是耐心看完.也欢迎指出错误. 原地 ...

  9. python 学习笔记 13 -- 经常使用的时间模块之time

    Python 没有包括相应日期和时间的内置类型.只是提供了3个相应的模块,能够採用多种表示管理日期和时间值: *    time 模块由底层C库提供与时间相关的函数.它包括一些函数用于获取时钟时间和处 ...

随机推荐

  1. HDU 4133

    注意题目中的一句话:If a number m has bigger evaluating value than all the numbers smaller than it... 这让我重新想过反 ...

  2. OC-JS交互(WebViewJavascriptBridge使用说明)

    首先确保一份已经配好功能的html文件. 1.初始化一个webview(viewdidload) UIWebView* webView = [[UIWebView alloc] initWithFra ...

  3. VMware虚拟机无法识别U盘解决方式

    1. 本机情况: Winxp操作系统(相同应该适用于win7),VMware虚拟机.虚拟机版本号:VMware 10.安装Ubuntu14.04.现要求在主机上插入U盘.在虚拟机中显示. 2. 遇到问 ...

  4. Unity3D摄像机尾随人物

    这里的镜头主要是从人物的背后尾随的. 首先新建一个C#脚本,命名为MyFollow,然后把下面代码粘贴进去.保存: using UnityEngine; using System.Collection ...

  5. redis主从复制,读写分离

    主从复制,读写分离 Master/Slave 是什么 master写入 slave读取 能干嘛 读写分离,更加安全,性能提升 怎么玩 一主二仆.薪火相传.反客为主 周明老师,能够把长篇大论总结的很精辟 ...

  6. GCD的小结

    同步和异步的区别 同步:在当前线程中执行 异步:在另一条线程中执行 有4个术语比较容易混淆:同步.异步.并发.串行 同步和异步决定了要不要开启新的线程 同步:在当前线程中执行任务,不具备开启新线程的能 ...

  7. BZOJ 4516 后缀数组+ST+set

    写了一半 没了啊啊啊 重新写的 思路: 先不考虑后缀自动机 (我不会啊) 那这道题只能用后缀数组了 先把原串倒一下 后缀->前缀 相当于每回在前面加了一个字母 求不同的子串个数 首先 正常的求子 ...

  8. 微信小程序-最新获取用户基本信息方案

    如果只是单纯的展示用户信息,那么最简单的方案就是 文档中组件: <open-data type="groupName" open-gid="xxxxxx" ...

  9. C语言“%”运算符

    C语言中运算符“%”是取余运算符,而非取模运算符.(运算符“%”在C/C++, JAVA中,为取余运算,而在Python中为取模运算) 对于一个C语言取余表达式a % b,设其值为result,有如下 ...

  10. E5中遍历数组的方法

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...