(笔记)处理日期和时间的方法(chrono 库,time
文章目录
- 0 摘要
- 1 chrono 库
- 1.1 时间间隔duration
- 1.2 时间点time point
- 1.3 时钟clocks
- 1.3.1 system_clock
- 1.3.2 steady_clock
- 1.4 转换函数
- 1.4.1 duration_cast
- 1.4.2 time_point_cast
- 联系实际问题解决
- 2 Linux时间相关
- 2.1 结构体
- 2.1.1 `time_t` 和`timeval`
- 2.1.2 `tm`
- 2.2 时间函数
- 2.2.1 `time` (获取 time_t)
- 2.2.2 `gettimeofday` (获取 timeval)
- 2.2.3 `difftime` (获取 两time_t间)
- 2.2.4 `ctime` (time_t 转 字符串)
- 2.2.5 `actime` (tm 转 字符串)
- 2.2.6 `gmtime` (time_t 转 tm)
- 2.2.7 `mktime` (tm 转 time_t)
- 联系实际问题解决
0 摘要
需求:“看来是同类型的替身”
需要处理时间的地方可太多了,当然了方法也有很多,有C++11 中提供了日期和时间相关的库 chrono,还有Linux中经常用time_t,处理高精度的如timeval。(chrono库中还有函数可以与time_t相转换)
1 chrono 库
chrono 库参考:苏丙榅
详细说明请参考上述两篇,以下为简要概述
chrono 库主要包含三种类型的类:时间间隔duration、时间点time point、时钟clocks
关系:由钟来确定时间点,时间点可通过时间间隔来计算,而时间间隔= 时钟周期 X 周期次数 。
1.1 时间间隔duration
// 定义于头文件 <chrono>
template<class Rep, //表示时钟数(周期数)的类型(默认为整形)class Period = std::ratio<1> //时钟的周期长度
> class duration;
ratio
表示每个时钟周期的秒数(一个分子除以分母的数值,分母默认为1)。
如ratio< 60 > 代表一分钟,ratio< 60 * 60 * 24 > 代表一天,ratio<1,1000 > 代表的是 1/1000 秒,也就是 1 毫秒。(当然也有定义了一些常用的时间间隔,看参考里面)。
- 构造函数原型 和 操作符重载 看参考。
- 获取时间间隔的时钟周期数 方法:
duration 类还提供了获取时间间隔的时钟周期数的方法count ()
,函数原型:constexpr rep count() const;
使用示例:
#include <chrono>
#include <iostream>
using namespace std;
int main()
{chrono::hours h(1); // 一小时 :时钟周期为 1 小时,共有 1 个时钟周期chrono::milliseconds ms{ 3 }; // 3 毫秒 :时钟周期为 1 毫秒,共有 3 个时钟周期chrono::duration<int, ratio<1000>> ks(3); // 3000 秒// chrono::duration<int, ratio<1000>> d3(3.5); // error,指明了int还用浮点,错了。应当改为doublechrono::duration<double> dd(6.6); // 6.6 秒// 使用小数表示时钟周期的次数chrono::duration<double, std::ratio<1, 30>> hz(3.5); //1/30*3.5 秒 :时钟周期为 1/30 秒,共有 3.5 个时钟周期
}
由于在 duration 类内部做了操作符重载,因此时间间隔之间可以直接进行算术运算。
注意事项:duration 的加减运算有一定的规则,当两个 duration 时钟周期不相同的时候,会先统一成一种时钟,然后再进行算术运算,具体看参考。
1.2 时间点time point
// 定义于头文件 <chrono>
template<class Clock, //此时间点在此时钟上计量class Duration = typename Clock::duration //用于计量从纪元起时间的 std::chrono::duration 类型
> class time_point;
- 构造函数原型 和 操作符重载 看参考
- 获取新纪元到现在的时间间隔 方法
time_since_epoch()
函数:用来获得 1970 年 1 月 1 日到 time_point 对象中记录的时间经过的时间间隔
使用示例:
跟下面 钟 一起说。
1.3 时钟clocks
chrono 库中提供了获取当前的系统时间的时钟类,包含的时钟一共有三种:
system_clock
:系统的时钟,系统的时钟可以修改,甚至可以网络对时,因此使用系统时间计算时间差可能不准。steady_clock
:是固定的时钟,相当于秒表。开始计时后,时间只会增长并且不能修改,适合用于记录程序耗时- high_resolution_clock:和时钟类 steady_clock 是等价的(是它的别名)。
在使用chrono提供的时钟类的时候,不需要创建类对象,直接调用类的静态方法就可以得到想要的时间了
1.3.1 system_clock
时钟类 system_clock 是一个系统范围的实时时钟。system_clock 提供了对当前时间点 time_point 的访问,将得到时间点转换为 time_t 类型的时间对象,就可以基于这个时间对象获取到当前的时间信息了。
- rep:时钟周期次数是通过整形来记录的 long long
- period:一个时钟周期是 100 纳秒 ratio<1, 10’000’000>
(源码看参考)
三个静态成员函数
now()
// 返回表示当前时间的时间点
static std::chrono::time_point<std::chrono::system_clock> now() noexcept;
to_time_t( const time_point& t )
// 将 time_point 时间点类型转换为 std::time_t 类型 :
static std::time_t to_time_t( const time_point& t ) noexcept;
from_time_t( std::time_t t )
// 将 std::time_t 类型转换为 time_point 时间点类型 :
static std::chrono::system_clock::time_point from_time_t( std::time_t t ) noexcept;
其中二三函数就是跟 Linux的time_t相联系的地方。
使用方法:
#include <chrono>
#include <iostream>
using namespace std;
using namespace std::chrono;
int main()
{// 新纪元1970.1.1时间system_clock::time_point epoch;duration<int, ratio<60*60*24>> day(1);// 新纪元1970.1.1时间 + 1天system_clock::time_point ppt(day);using dday = duration<int, ratio<60 * 60 * 24>>;// 新纪元1970.1.1时间 + 10天time_point<system_clock, dday> t(dday(10));// 系统当前时间system_clock::time_point today = system_clock::now();// 转换为time_t时间类型time_t tm = system_clock::to_time_t(today);cout << "今天的日期是: " << ctime(&tm);time_t tm1 = system_clock::to_time_t(today+day);cout << "明天的日期是: " << ctime(&tm1);time_t tm2 = system_clock::to_time_t(epoch);cout << "新纪元时间: " << ctime(&tm2);time_t tm3 = system_clock::to_time_t(ppt);cout << "新纪元时间+1天: " << ctime(&tm3);time_t tm4 = system_clock::to_time_t(t);cout << "新纪元时间+10天: " << ctime(&tm4);
}
1.3.2 steady_clock
如果我们通过时钟不是为了获取当前的系统时间,而是进行程序耗时的时长,此时使用 syetem_clock 就不合适了,因为这个时间可以跟随系统的设置发生变化。
在 C++11 中提供的时钟类 steady_clock 相当于秒表,只要启动就会进行时间的累加,并且不能被修改,非常适合于进行耗时的统计。
- rep:时钟周期次数是通过整形来记录的 long long
- period:一个时钟周期是 1 纳秒 nano
(源码看参考)
一个静态成员函数
now()
// 返回表示当前时间的时间点
static std::chrono::time_point<std::chrono::steady_clock> now() noexcept;
假设要测试某一段程序的执行效率,可以计算它执行期间消耗的总时长
#include <chrono>
#include <iostream>
using namespace std;
using namespace std::chrono;
int main()
{// 获取开始时间点steady_clock::time_point start = steady_clock::now();// 执行业务流程cout << "print 1000 stars ...." << endl;for (int i = 0; i < 1000; ++i){cout << "*";}cout << endl;// 获取结束时间点steady_clock::time_point last = steady_clock::now();// 计算差值auto dt = last - start;cout << "总共耗时: " << dt.count() << "纳秒" << endl;
}
1.4 转换函数
过程中要对时钟周期和周期次数进行修改,且不能直接用重载的操作符处理,就需要用到转换函数
1.4.1 duration_cast
作用是:通过这个函数可以对 duration 类对象内部的时钟周期 Period,和周期次数的类型 Rep 进行修改。
以下条件都可以隐式处理,若不满足,那么就需要使用 duration_cast 进行显示转换。
- 如果是对时钟周期进行转换:源时钟周期必须能够整除目的时钟周期(比如:小时到分钟)。
- 如果是对时钟周期次数的类型进行转换:低等类型默认可以向高等类型进行转换(比如:int 转 double)。
- 如果时钟周期和时钟周期次数类型都变了,根据第二点进行推导(也就是看时间周期次数类型)。
示例说明:
#include <iostream>
#include <chrono>
using namespace std;
using namespace std::chrono;
void f()
{cout << "print 1000 stars ...." << endl;for (int i = 0; i < 1000; ++i){cout << "*";}cout << endl;
}int main()
{auto t1 = steady_clock::now(); // steady_clock的周期是1 纳秒f();auto t2 = steady_clock::now();// 整数时长:时钟周期纳秒转毫秒,要求 duration_castauto int_ms = duration_cast<chrono::milliseconds>(t2 - t1);// 小数时长:不要求 duration_castduration<double, ratio<1, 1000>> fp_ms = t2 - t1;cout << "f() took " << fp_ms.count() << " ms, "<< "or " << int_ms.count() << " whole milliseconds\n";
}
1.4.2 time_point_cast
作用是:对时间点进行转换。因为不同的时间点对象内部的时钟周期 Period,和周期次数的类型 Rep 可能也是不同的,一般情况下它们之间可以进行隐式类型转换,也可以通过该函数显示的进行转换。
示例说明
#include <chrono>
#include <iostream>
using namespace std;using Clock = chrono::high_resolution_clock;
using Ms = chrono::milliseconds;
using Sec = chrono::seconds;
template<class Duration>
using TimePoint = chrono::time_point<Clock, Duration>;void print_ms(const TimePoint<Ms>& time_point)
{std::cout << time_point.time_since_epoch().count() << " ms\n";
}int main()
{TimePoint<Sec> time_point_sec(Sec(6));// 无精度损失, 可以进行隐式类型转换TimePoint<Ms> time_point_ms(time_point_sec); //将time_point_sec的周期从秒改为微秒print_ms(time_point_ms); // 6000 mstime_point_ms = TimePoint<Ms>(Ms(6789));// error,会损失精度,不允许进行隐式的类型转换TimePoint<Sec> sec(time_point_ms);// 显示类型转换,会损失精度。6789 truncated to 6000time_point_sec = std::chrono::time_point_cast<Sec>(time_point_ms);print_ms(time_point_sec); // 6000 ms
}
联系实际问题解决
uint64_t getTimeHost(void)
函数需要获取本地时间,并返回
{//创建system_clock类型的时间点 t,并通过now()获取当前时间的时间点,将其赋值给t。std::chrono::system_clock::time_point t = std::chrono::system_clock::now();//创建system_clock类型的时间间隔 t_s。并通过time_since_epoch获取从1970到时间点 t 的 时间间隔//注 system_clock类型的:rep时钟周期次数是整形来记录的 long long// :period时钟周期是 100 纳秒 ratio<1, 10'000'000>std::chrono::system_clock::duration t_s = t.time_since_epoch();//创建时间间隔t_us,并将 经过转换处理时间周期的t_s 赋值给t_us//通过转换函数duration_cast,将system_clock类型的时间间隔 t_s:// rep时钟周期次数类型:uint64_t// period时钟周期:100 纳秒 ratio<1, 10'000'000>//转换为// rep时钟周期次数类型:uint64_t// period时钟周期:1 微秒 ratio<1, 1'000'000> //将处理好的t_us赋值给t_s。(因为100纳秒转1微秒,有精度丢失,要显式转)。std::chrono::duration<uint64_t, std::ratio<1l, 1000000l>> t_us = std::chrono::duration_cast<std::chrono::duration<uint64_t, std::ratio<1l, 1000000l>>>(t_s);//通过count()返回时间间隔t_us的周期次数(单位为uint64_t)return t_us.count();
}
2 Linux时间相关
参考:Linux时间相关函数
参考:c++ 时间类型详解 time_t
开发中经常会用到时间,针对不同应用,对时间的需求有所不同:
- 时间精度(计时等,秒级、毫秒级、微秒级、纳秒级);
- 时间格式(RTC显示等,年、月、日、时、分、秒的常用不同排列组合);
- 时间计时(周期报文的发送等);
- 时间点(闹钟等);
- 时间段(进程运行时间统计等);
世界协调时(UTC:CoordinatdeUniversalTime)。UTC的表示方式为:年(y)、月(m)、日(d)、时(h)、分(min)、秒(s),均用数字表示。
linux下存储时间常见的有两种存储方式:
- 从1970年到现在经过了多少秒。
如time_t
,或者准确到微妙的structtimeval
。 - 用一个结构来分别存储年月日时分秒的。
如tm
。
其余的如到毫秒的timeb
,到纳秒的timespec
,整型表示的clockid_t
…都不做详细说明,可以看参考文章。
下面主要介绍time_t
,timeval
,tm
。
2.1 结构体
2.1.1 time_t
和timeval
time_t 就是长整型long int
。(此外还有整型等类型表示的)
timeval
精确到微妙,用结构体表示
struct timeval
{long tv_sec; /*秒*/long tv_usec; /*微秒*/
};
2.1.2 tm
struct tm
{int tm_sec; /*秒,正常范围0-59, 但允许至61*/int tm_min; /*分钟,0-59*/int tm_hour; /*小时, 0-23*/int tm_mday; /*日,即一个月中的第几天,1-31*/int tm_mon; /*月, 从一月算起,0-11*/ 1+p->tm_mon;int tm_year; /*年, 从1900至今已经多少年*/ 1900+ p->tm_year;int tm_wday; /*星期,一周中的第几天, 从星期日算起,0-6*/int tm_yday; /*从今年1月1日到目前的天数,范围0-365*/int tm_isdst; /*日光节约时间的旗标*/
};
注:
- 年份是从1900年起
- 月份从0开始的,0表示一月,星期也是从0开始的, 0表示星期日,1表示星期一。
2.2 时间函数
2.2.1 time
(获取 time_t)
一般跟time_t一起用。
作用:取得从1970年1月1日至今的秒数。
头文件:time.h
//原型
time_t time(time_t *t);//使用方法
time_t timep;
time(&timep); //或 timep = time(NULL);
2.2.2 gettimeofday
(获取 timeval)
一般跟timeval一起用。
作用:返回当前距离1970年的秒数和微妙数,后面的tz是时区,一般不用。(也常常跟settimeofday一起用)
头文件:sys/time.h
//原型
int gettimeofday(struct timeval *tv, struct timezone *tz);//使用方法
struct timeval tv;
gettimeofday(&tv,NULL);
2.2.3 difftime
(获取 两time_t间)
一般跟time_t一起用。
作用:返回两个时间相差的秒数。
//原型
double difftime(time_t time1, time_t time2);
2.2.4 ctime
(time_t 转 字符串)
一般跟time_t一起用。
作用:将time_t转换为真实世界的时间,以字符串显示。
//原型
char *ctime(const time_t *timep);
2.2.5 actime
(tm 转 字符串)
一般跟tm一起用。
作用:将tm转换为真实世界的时间,以字符串显示。
//原型
char *asctime(const struct tm* timeptr);
2.2.6 gmtime
(time_t 转 tm)
一般跟tm,time_t一起用。
作用:将time_t表示的时间转换为没有经过时区转换的UTC时间,是一个struct tm结构指针。(还有种stuct tm* localtime(const time_t *timep)
但是它是经过时区转换的时间)
//原型
struct tm* gmtime(const time_t *timep);
2.2.7 mktime
(tm 转 time_t)
一般跟tm,time_t一起用。
作用:将struct tm 结构的时间转换为从1970年至今的秒数
//原型
time_t mktime(struct tm* timeptr);
联系实际问题解决
#include <time.h>time_t timep;//获取time_t类型的当前时间time(&timep); //用gmtime将time_t类型的时间转换为struct tm类型的时间(没有经过时区转换的UTC时间)//然后再用asctime转换为字符串printf("%s", asctime(gmtime(&timep)));}
(笔记)处理日期和时间的方法(chrono 库,time
文章目录
- 0 摘要
- 1 chrono 库
- 1.1 时间间隔duration
- 1.2 时间点time point
- 1.3 时钟clocks
- 1.3.1 system_clock
- 1.3.2 steady_clock
- 1.4 转换函数
- 1.4.1 duration_cast
- 1.4.2 time_point_cast
- 联系实际问题解决
- 2 Linux时间相关
- 2.1 结构体
- 2.1.1 `time_t` 和`timeval`
- 2.1.2 `tm`
- 2.2 时间函数
- 2.2.1 `time` (获取 time_t)
- 2.2.2 `gettimeofday` (获取 timeval)
- 2.2.3 `difftime` (获取 两time_t间)
- 2.2.4 `ctime` (time_t 转 字符串)
- 2.2.5 `actime` (tm 转 字符串)
- 2.2.6 `gmtime` (time_t 转 tm)
- 2.2.7 `mktime` (tm 转 time_t)
- 联系实际问题解决
0 摘要
需求:“看来是同类型的替身”
需要处理时间的地方可太多了,当然了方法也有很多,有C++11 中提供了日期和时间相关的库 chrono,还有Linux中经常用time_t,处理高精度的如timeval。(chrono库中还有函数可以与time_t相转换)
1 chrono 库
chrono 库参考:苏丙榅
详细说明请参考上述两篇,以下为简要概述
chrono 库主要包含三种类型的类:时间间隔duration、时间点time point、时钟clocks
关系:由钟来确定时间点,时间点可通过时间间隔来计算,而时间间隔= 时钟周期 X 周期次数 。
1.1 时间间隔duration
// 定义于头文件 <chrono>
template<class Rep, //表示时钟数(周期数)的类型(默认为整形)class Period = std::ratio<1> //时钟的周期长度
> class duration;
ratio
表示每个时钟周期的秒数(一个分子除以分母的数值,分母默认为1)。
如ratio< 60 > 代表一分钟,ratio< 60 * 60 * 24 > 代表一天,ratio<1,1000 > 代表的是 1/1000 秒,也就是 1 毫秒。(当然也有定义了一些常用的时间间隔,看参考里面)。
- 构造函数原型 和 操作符重载 看参考。
- 获取时间间隔的时钟周期数 方法:
duration 类还提供了获取时间间隔的时钟周期数的方法count ()
,函数原型:constexpr rep count() const;
使用示例:
#include <chrono>
#include <iostream>
using namespace std;
int main()
{chrono::hours h(1); // 一小时 :时钟周期为 1 小时,共有 1 个时钟周期chrono::milliseconds ms{ 3 }; // 3 毫秒 :时钟周期为 1 毫秒,共有 3 个时钟周期chrono::duration<int, ratio<1000>> ks(3); // 3000 秒// chrono::duration<int, ratio<1000>> d3(3.5); // error,指明了int还用浮点,错了。应当改为doublechrono::duration<double> dd(6.6); // 6.6 秒// 使用小数表示时钟周期的次数chrono::duration<double, std::ratio<1, 30>> hz(3.5); //1/30*3.5 秒 :时钟周期为 1/30 秒,共有 3.5 个时钟周期
}
由于在 duration 类内部做了操作符重载,因此时间间隔之间可以直接进行算术运算。
注意事项:duration 的加减运算有一定的规则,当两个 duration 时钟周期不相同的时候,会先统一成一种时钟,然后再进行算术运算,具体看参考。
1.2 时间点time point
// 定义于头文件 <chrono>
template<class Clock, //此时间点在此时钟上计量class Duration = typename Clock::duration //用于计量从纪元起时间的 std::chrono::duration 类型
> class time_point;
- 构造函数原型 和 操作符重载 看参考
- 获取新纪元到现在的时间间隔 方法
time_since_epoch()
函数:用来获得 1970 年 1 月 1 日到 time_point 对象中记录的时间经过的时间间隔
使用示例:
跟下面 钟 一起说。
1.3 时钟clocks
chrono 库中提供了获取当前的系统时间的时钟类,包含的时钟一共有三种:
system_clock
:系统的时钟,系统的时钟可以修改,甚至可以网络对时,因此使用系统时间计算时间差可能不准。steady_clock
:是固定的时钟,相当于秒表。开始计时后,时间只会增长并且不能修改,适合用于记录程序耗时- high_resolution_clock:和时钟类 steady_clock 是等价的(是它的别名)。
在使用chrono提供的时钟类的时候,不需要创建类对象,直接调用类的静态方法就可以得到想要的时间了
1.3.1 system_clock
时钟类 system_clock 是一个系统范围的实时时钟。system_clock 提供了对当前时间点 time_point 的访问,将得到时间点转换为 time_t 类型的时间对象,就可以基于这个时间对象获取到当前的时间信息了。
- rep:时钟周期次数是通过整形来记录的 long long
- period:一个时钟周期是 100 纳秒 ratio<1, 10’000’000>
(源码看参考)
三个静态成员函数
now()
// 返回表示当前时间的时间点
static std::chrono::time_point<std::chrono::system_clock> now() noexcept;
to_time_t( const time_point& t )
// 将 time_point 时间点类型转换为 std::time_t 类型 :
static std::time_t to_time_t( const time_point& t ) noexcept;
from_time_t( std::time_t t )
// 将 std::time_t 类型转换为 time_point 时间点类型 :
static std::chrono::system_clock::time_point from_time_t( std::time_t t ) noexcept;
其中二三函数就是跟 Linux的time_t相联系的地方。
使用方法:
#include <chrono>
#include <iostream>
using namespace std;
using namespace std::chrono;
int main()
{// 新纪元1970.1.1时间system_clock::time_point epoch;duration<int, ratio<60*60*24>> day(1);// 新纪元1970.1.1时间 + 1天system_clock::time_point ppt(day);using dday = duration<int, ratio<60 * 60 * 24>>;// 新纪元1970.1.1时间 + 10天time_point<system_clock, dday> t(dday(10));// 系统当前时间system_clock::time_point today = system_clock::now();// 转换为time_t时间类型time_t tm = system_clock::to_time_t(today);cout << "今天的日期是: " << ctime(&tm);time_t tm1 = system_clock::to_time_t(today+day);cout << "明天的日期是: " << ctime(&tm1);time_t tm2 = system_clock::to_time_t(epoch);cout << "新纪元时间: " << ctime(&tm2);time_t tm3 = system_clock::to_time_t(ppt);cout << "新纪元时间+1天: " << ctime(&tm3);time_t tm4 = system_clock::to_time_t(t);cout << "新纪元时间+10天: " << ctime(&tm4);
}
1.3.2 steady_clock
如果我们通过时钟不是为了获取当前的系统时间,而是进行程序耗时的时长,此时使用 syetem_clock 就不合适了,因为这个时间可以跟随系统的设置发生变化。
在 C++11 中提供的时钟类 steady_clock 相当于秒表,只要启动就会进行时间的累加,并且不能被修改,非常适合于进行耗时的统计。
- rep:时钟周期次数是通过整形来记录的 long long
- period:一个时钟周期是 1 纳秒 nano
(源码看参考)
一个静态成员函数
now()
// 返回表示当前时间的时间点
static std::chrono::time_point<std::chrono::steady_clock> now() noexcept;
假设要测试某一段程序的执行效率,可以计算它执行期间消耗的总时长
#include <chrono>
#include <iostream>
using namespace std;
using namespace std::chrono;
int main()
{// 获取开始时间点steady_clock::time_point start = steady_clock::now();// 执行业务流程cout << "print 1000 stars ...." << endl;for (int i = 0; i < 1000; ++i){cout << "*";}cout << endl;// 获取结束时间点steady_clock::time_point last = steady_clock::now();// 计算差值auto dt = last - start;cout << "总共耗时: " << dt.count() << "纳秒" << endl;
}
1.4 转换函数
过程中要对时钟周期和周期次数进行修改,且不能直接用重载的操作符处理,就需要用到转换函数
1.4.1 duration_cast
作用是:通过这个函数可以对 duration 类对象内部的时钟周期 Period,和周期次数的类型 Rep 进行修改。
以下条件都可以隐式处理,若不满足,那么就需要使用 duration_cast 进行显示转换。
- 如果是对时钟周期进行转换:源时钟周期必须能够整除目的时钟周期(比如:小时到分钟)。
- 如果是对时钟周期次数的类型进行转换:低等类型默认可以向高等类型进行转换(比如:int 转 double)。
- 如果时钟周期和时钟周期次数类型都变了,根据第二点进行推导(也就是看时间周期次数类型)。
示例说明:
#include <iostream>
#include <chrono>
using namespace std;
using namespace std::chrono;
void f()
{cout << "print 1000 stars ...." << endl;for (int i = 0; i < 1000; ++i){cout << "*";}cout << endl;
}int main()
{auto t1 = steady_clock::now(); // steady_clock的周期是1 纳秒f();auto t2 = steady_clock::now();// 整数时长:时钟周期纳秒转毫秒,要求 duration_castauto int_ms = duration_cast<chrono::milliseconds>(t2 - t1);// 小数时长:不要求 duration_castduration<double, ratio<1, 1000>> fp_ms = t2 - t1;cout << "f() took " << fp_ms.count() << " ms, "<< "or " << int_ms.count() << " whole milliseconds\n";
}
1.4.2 time_point_cast
作用是:对时间点进行转换。因为不同的时间点对象内部的时钟周期 Period,和周期次数的类型 Rep 可能也是不同的,一般情况下它们之间可以进行隐式类型转换,也可以通过该函数显示的进行转换。
示例说明
#include <chrono>
#include <iostream>
using namespace std;using Clock = chrono::high_resolution_clock;
using Ms = chrono::milliseconds;
using Sec = chrono::seconds;
template<class Duration>
using TimePoint = chrono::time_point<Clock, Duration>;void print_ms(const TimePoint<Ms>& time_point)
{std::cout << time_point.time_since_epoch().count() << " ms\n";
}int main()
{TimePoint<Sec> time_point_sec(Sec(6));// 无精度损失, 可以进行隐式类型转换TimePoint<Ms> time_point_ms(time_point_sec); //将time_point_sec的周期从秒改为微秒print_ms(time_point_ms); // 6000 mstime_point_ms = TimePoint<Ms>(Ms(6789));// error,会损失精度,不允许进行隐式的类型转换TimePoint<Sec> sec(time_point_ms);// 显示类型转换,会损失精度。6789 truncated to 6000time_point_sec = std::chrono::time_point_cast<Sec>(time_point_ms);print_ms(time_point_sec); // 6000 ms
}
联系实际问题解决
uint64_t getTimeHost(void)
函数需要获取本地时间,并返回
{//创建system_clock类型的时间点 t,并通过now()获取当前时间的时间点,将其赋值给t。std::chrono::system_clock::time_point t = std::chrono::system_clock::now();//创建system_clock类型的时间间隔 t_s。并通过time_since_epoch获取从1970到时间点 t 的 时间间隔//注 system_clock类型的:rep时钟周期次数是整形来记录的 long long// :period时钟周期是 100 纳秒 ratio<1, 10'000'000>std::chrono::system_clock::duration t_s = t.time_since_epoch();//创建时间间隔t_us,并将 经过转换处理时间周期的t_s 赋值给t_us//通过转换函数duration_cast,将system_clock类型的时间间隔 t_s:// rep时钟周期次数类型:uint64_t// period时钟周期:100 纳秒 ratio<1, 10'000'000>//转换为// rep时钟周期次数类型:uint64_t// period时钟周期:1 微秒 ratio<1, 1'000'000> //将处理好的t_us赋值给t_s。(因为100纳秒转1微秒,有精度丢失,要显式转)。std::chrono::duration<uint64_t, std::ratio<1l, 1000000l>> t_us = std::chrono::duration_cast<std::chrono::duration<uint64_t, std::ratio<1l, 1000000l>>>(t_s);//通过count()返回时间间隔t_us的周期次数(单位为uint64_t)return t_us.count();
}
2 Linux时间相关
参考:Linux时间相关函数
参考:c++ 时间类型详解 time_t
开发中经常会用到时间,针对不同应用,对时间的需求有所不同:
- 时间精度(计时等,秒级、毫秒级、微秒级、纳秒级);
- 时间格式(RTC显示等,年、月、日、时、分、秒的常用不同排列组合);
- 时间计时(周期报文的发送等);
- 时间点(闹钟等);
- 时间段(进程运行时间统计等);
世界协调时(UTC:CoordinatdeUniversalTime)。UTC的表示方式为:年(y)、月(m)、日(d)、时(h)、分(min)、秒(s),均用数字表示。
linux下存储时间常见的有两种存储方式:
- 从1970年到现在经过了多少秒。
如time_t
,或者准确到微妙的structtimeval
。 - 用一个结构来分别存储年月日时分秒的。
如tm
。
其余的如到毫秒的timeb
,到纳秒的timespec
,整型表示的clockid_t
…都不做详细说明,可以看参考文章。
下面主要介绍time_t
,timeval
,tm
。
2.1 结构体
2.1.1 time_t
和timeval
time_t 就是长整型long int
。(此外还有整型等类型表示的)
timeval
精确到微妙,用结构体表示
struct timeval
{long tv_sec; /*秒*/long tv_usec; /*微秒*/
};
2.1.2 tm
struct tm
{int tm_sec; /*秒,正常范围0-59, 但允许至61*/int tm_min; /*分钟,0-59*/int tm_hour; /*小时, 0-23*/int tm_mday; /*日,即一个月中的第几天,1-31*/int tm_mon; /*月, 从一月算起,0-11*/ 1+p->tm_mon;int tm_year; /*年, 从1900至今已经多少年*/ 1900+ p->tm_year;int tm_wday; /*星期,一周中的第几天, 从星期日算起,0-6*/int tm_yday; /*从今年1月1日到目前的天数,范围0-365*/int tm_isdst; /*日光节约时间的旗标*/
};
注:
- 年份是从1900年起
- 月份从0开始的,0表示一月,星期也是从0开始的, 0表示星期日,1表示星期一。
2.2 时间函数
2.2.1 time
(获取 time_t)
一般跟time_t一起用。
作用:取得从1970年1月1日至今的秒数。
头文件:time.h
//原型
time_t time(time_t *t);//使用方法
time_t timep;
time(&timep); //或 timep = time(NULL);
2.2.2 gettimeofday
(获取 timeval)
一般跟timeval一起用。
作用:返回当前距离1970年的秒数和微妙数,后面的tz是时区,一般不用。(也常常跟settimeofday一起用)
头文件:sys/time.h
//原型
int gettimeofday(struct timeval *tv, struct timezone *tz);//使用方法
struct timeval tv;
gettimeofday(&tv,NULL);
2.2.3 difftime
(获取 两time_t间)
一般跟time_t一起用。
作用:返回两个时间相差的秒数。
//原型
double difftime(time_t time1, time_t time2);
2.2.4 ctime
(time_t 转 字符串)
一般跟time_t一起用。
作用:将time_t转换为真实世界的时间,以字符串显示。
//原型
char *ctime(const time_t *timep);
2.2.5 actime
(tm 转 字符串)
一般跟tm一起用。
作用:将tm转换为真实世界的时间,以字符串显示。
//原型
char *asctime(const struct tm* timeptr);
2.2.6 gmtime
(time_t 转 tm)
一般跟tm,time_t一起用。
作用:将time_t表示的时间转换为没有经过时区转换的UTC时间,是一个struct tm结构指针。(还有种stuct tm* localtime(const time_t *timep)
但是它是经过时区转换的时间)
//原型
struct tm* gmtime(const time_t *timep);
2.2.7 mktime
(tm 转 time_t)
一般跟tm,time_t一起用。
作用:将struct tm 结构的时间转换为从1970年至今的秒数
//原型
time_t mktime(struct tm* timeptr);
联系实际问题解决
#include <time.h>time_t timep;//获取time_t类型的当前时间time(&timep); //用gmtime将time_t类型的时间转换为struct tm类型的时间(没有经过时区转换的UTC时间)//然后再用asctime转换为字符串printf("%s", asctime(gmtime(&timep)));}