C/C++时间库使用
C++时间和日期库学习
C语言中,time.h定义了用于日期和时间操作的结构和函数,而C++标准库中没有提供所谓的日期类型,而是继承自C语言。表示时间中有一个重要的概念:时间戳,时间戳指的是格林威治时间1970年01月01日00时00分00秒(北京时间1970年01月01日08时00分00秒)起至现在的总秒数。
下面对C/C++中两个重要的时间库ctime和chrono进行分析学习,并说明它们之间的联系。
ctime
在C语言中,ctime头文件包含用于获取和操作日期和时间的函数定义。接下来,将从如何表示时间、不同时间之间的转换、以及时间操作函数三个方面介绍。
时间的数据结构
在ctime中提供了四种不同时间表示的数据结构:clock_t、size_t、time_t、struct tm。
- time_t
表示UTC时区下,自1970年1月1日0点以来经过的秒数,实际上是一个long类型,单位为秒。
- struct tm
struct tm是一个结构体,其中包含日期和时间信息。具体的定义如下:
struct tm
{
int tm_sec; /* Seconds. [0-60] (1 leap second) */ 秒
int tm_min; /* Minutes. [0-59] */ 分
int tm_hour; /* Hours. [0-23] */ 时
int tm_mday; /* Day. [1-31] */ 天
int tm_mon; /* Month. [0-11] */ 月
int tm_year; /* Year - 1900. */ 距1900年的年数
int tm_wday; /* Day of week. [0-6] */ 星期几
int tm_yday; /* Days in year.[0-365] */ 一年中的第几天
int tm_isdst; /* DST. [-1/0/1]*/
}
在使用struct tm构建时间时,需要注意每个变量的含义以及起始数。
- clock_t
用于时钟滴答计数,实际是long类型。
- size_t
unsigned int类型的别名。
时间转换函数
ctime头文件中提供了6种时间转换函数:asctime、ctime、gmtime、localtime、strftime、mktime。
- asctime
将struct tm的时间数据结构转换为字符串string。
- ctime
将time_t时间数据结构转换为字符串string。
- gmtime
将time_t转换为struct tm数据结构(UTC Time)。
- localtime
将time_t转换为struct tm数据结构(local Time)。
- srftime
将struct tm数据结构生成格式化的字符串内容(常用函数)。
- mktime
将struct tm数据结构转换为time_t数据结构。
时间操作函数
ctime中提供了3种时间操作函数:time、clock、difftime。
- time
返回当前时间,返回值为time_t类型,表示距离UTC格林尼治时间1970年1月1日00:00:00的时长,单位为秒
time_t now;
time(&now); /* get current time; same as: now = time(NULL) */
- clock
获取始终的ticks,返回clock_t类型。
- difftime
获取两个time_t数据类型之间的时间差,单位为秒。
double difftime (time_t end, time_t beginning);
举例说明
- 获取当前时间,并转换为struct tm类型,然后分别转换为字符串并打印
#include <ctime>
#include <iostream>
int main()
{
time_t now = time(NULL); // 获取当前时间
std::cout << "The current local time is: " << ctime(&now) << std::endl;
struct tm* timeinfo = localtime(&now);
std::cout << "current Beijing (China) time and date: " << asctime(timeinfo) << std::endl;
struct tm* timeinfo2 = gmtime(&now);
std::cout << "current Reykjavik (Iceland) time and date: " << asctime(timeinfo2) << std::endl;
return 0;
}
- 构建struct tm时间,并转换为time_t类型
int main()
{
struct tm timeinfo = {0};
timeinfo.tm_year = 100; // 距离1900的100年, 即2000
timeinfo.tm_mon = 0; // 一月
timeinfo.tm_mday = 1; // 第一天
std::cout << "1/1/2000 represented by struct tm is: " << asctime(&timeinfo) << std::endl;
time_t tt = mktime(&timeinfo);
std::cout << "1/1/2000 represented by time_t is: " << asctime(&timeinfo) << std::endl;
return 0;
}
- 格式化表示时间
int main()
{
struct tm timeinfo = {0};
timeinfo.tm_year = 100; // 距离1900的100年, 即2000
timeinfo.tm_mon = 0; // 一月
timeinfo.tm_mday = 1; // 第一天
// format time as string
char buf[80];
// format
// %Y : Year (2023)
// %m : Month (0-12)
// %d : Day of the month (0-31)
// %H : Hour in 24th format (00-23)
// %M : Minute (00-59)
// %S : Second (00-61)
strftime(buf, 80, "Now it's %Y-%m-%d-%H-%M-%S.", &timeinfo);
std::cout << "Format time and data: " << buf << std::endl;
return 0;
}
chrono
chrono是C++ 11中的时间库,提供计时、时钟等功能。关键是要理解时间段(durations)、时间点(time points)等概念。
时间节拍
时间节拍指的是时间计数的基本单位,其定义如下:
template <intmax_t N, intmax_t D = 1> class ratio;
其中N表示分子,D表示分母,默认的时间节拍单位为秒。
常见时间节拍的定义如下:
ratio <60, 1> minute; // 60/1 seconds
ratio <1, 1> second;
ratio <1, 1000> microsecond;
时间段
duration表示一段时间,其定义如下:
template < class Rep, class Period = ratio<1>> class duration;
其中Rep表示Period的数量,可以是int, float,double等类型。Period是ratio类型,用来表示时间节拍(精度)。
Rep的值乘以Period精度等于一段时间的大小。
chrono中宏定义了许多特例化的duration:hours,miniutes,seconds,milliseconds等等。
/// nanoseconds
typedef duration<int64_t, nano> nanoseconds;
/// microseconds
typedef duration<int64_t, micro> microseconds;
/// milliseconds
typedef duration<int64_t, milli> milliseconds;
/// seconds
typedef duration<int64_t> seconds;
/// minutes
typedef duration<int64_t, ratio< 60>> minutes;
/// hours
typedef duration<int64_t, ratio<3600>> hours;
常见时间单位转换知识:
秒(second),时间单位 : s,
毫秒(millisecond),时间单位:ms
微秒(microsecond),时间单位:μs
时间换算:
1s【秒】 = 1000ms【毫秒】
1ms【毫秒】 = 1000μs【微秒】
1μs【微秒】 = 1000ns【纳秒】
1ns 【纳秒】= 1000ps【皮秒】
其中成员函数count返回单位精度下的数量,即Rep值。duration_cast函数用来转换duration中Period的精度,从而得到不同的Rep值。
#include <iostream>
#include <chrono>
int main()
{
// 使用chrono库中自定义的duration
typedef std::chrono::seconds seconds_type;
typedef std::chrono::minutes minutes_type;
typedef std::chrono::hours hours_type;
// template<class Rep2>
// constexpr explicit duration (const Rep2& n);
hours_type h_oneday(24); // 24h
std::cout << h_oneday.count() << "hours." << std::endl;
// 赋值构造函数
minutes_type ms_oneday = std::chrono::duration_cast<minutes_type>(h_oneday) ;
std::cout << ms_oneday.count() << "minutes." << std::endl;
// 赋值构造函数
seconds_type s_oneday = std::chrono::duration_cast<minutes_type>(h_oneday);
std::cout << s_oneday.count() << "seconds." << std::endl;
return 0;
}
时间点
time_point表示一个具体时间,其中Clock用来指定需要使用的时钟(system_clock, steady_clock和high_resolution_clock),第二个参数duration type表示以何种精度表示时间点。
template< class Clock, class Duration = typename Clock::duration > class time_point;
Clock时钟
chrono中提供了三种时钟:system_clock、steady_clock和high_resolution_clock。每一个clock类中都有确定的time_point, duration,Rep, Period类型。
这三个时钟类都提供了一个静态成员函数 **now() **用于获取当前时间,该函数的返回值是一个 time_point 类型。
- system_clock:系统时间,可以人为的调整。system_clock除了now()函数外,还提供了to_time_t()静态成员函数,用于将系统时间转换成熟悉的std::time_t类型,from_time_t()静态成员函数,用来将time_t时间类型转换为time_point;
- steady_clock:是单调的时钟,类似教练手中的秒表,适合用于记录程序耗时;
- high_resolution_clock:是当前系统能够提供的最高精度的时钟,同样不可以修改,相当于steady_clock的高精度版本;
举例说明
- 记录程序的耗时
int main()
{
using std::chrono::steady_clock;
typedef std::chrono::seconds seconds_type;
typedef std::chrono::milliseconds milliseconds_type;
typedef std::chrono::microseconds microseconds_type;
steady_clock::time_point start = steady_clock::now();
std::cout << "printing out 1000 stars...\n";
for (int i=0; i<1000; ++i) std::cout << "*";
std::cout << std::endl;
steady_clock::time_point end = steady_clock::now();
seconds_type s_span = std::chrono::duration_cast<seconds_type>(end - start);
std::cout << "It took me " << s_span.count() << " seconds." << std::endl;
milliseconds_type mill_span = std::chrono::duration_cast<milliseconds_type>(end - start);
std::cout << "It took me " << mill_span.count() << " milliseconds." << std::endl;
microseconds_type micro_span = std::chrono::duration_cast<microseconds_type>(end - start);
std::cout << "It took me " << micro_span.count() << " microseconds." << std::endl;
return 0;
}
- system_clock与time_t时间类型互换
int main()
{
using std::chrono::system_clock;
system_clock::time_point now_t = system_clock::now();
time_t tt;
tt = system_clock::to_time_t(now_t);
std::cout << "now is: " << ctime(&tt) << std::endl;
// 构建 struct tm转换为 time_t,然后将time_t转换为time_point
struct tm timeinfo = {0};
timeinfo.tm_year = 100; // 距离1900的100年, 即2000
timeinfo.tm_mon = 0; // 一月
timeinfo.tm_mday = 1; // 第一天
time_t tt_2000 = mktime(&timeinfo);
std::cout << "1/1/2000 is: " << ctime(&tt) << std::endl;
system_clock::time_point tp = system_clock::from_time_t(tt_2000);
system_clock::duration d = system_clock::now() - tp;
// convert to number of days
typedef std::chrono::duration<int64_t, std::ratio<60*60*24>> days_type;
days_type ndays = std::chrono::duration_cast<days_type> (d);
// display result
std::cout << ndays.count() << "days have passed since 1/1/2000" << std::endl;
return 0;
}
参考链接
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)