1. 序言
程序中常需要记录时间戳或者计算模块耗时,在此对时间函数及应用场景做一个总结
2. 有哪些函数
-
获取时间
clock, time, gettimeofday, chrono库时间函数
-
时间格式转换
ctime, localtime, gmtime, asctime, mktime, strftime
-
其他
计算时间差:difftime
时间转换线程安全函数:ctime_r, localtime_r, asctime_r, gmtime_r
3. 选用场景
函数 |
功能描述 |
选用场景 |
clock |
从程序启动到此函数调用消耗的处理器时间,精确到微秒 |
统计程序内模块处理器耗时 |
time |
当前的UTC时间,精确到秒 |
统计过去了多少秒 |
gettimeofday |
当前的UTC时间,精确到微秒 |
获取当前较精确时间戳 |
chrono::system_clock |
当前的UTC时间,精确到微秒 |
获取当前较精确时间戳,与NTP时间有关 |
chrono::steady_clock |
当前的UTC时间,精确到纳秒 |
获取当前稳定的高精确时间戳 |
chrono::high_resoluction_clock |
当前的UTC时间,精确到纳秒 |
获取当前最高精确时间戳 |
函数 |
功能描述 |
选用场景 |
localtime |
将UTC秒数转换为本地时间(tm格式) |
可按年月日时分秒显示 |
gmtime |
将UTC秒数转换为本地时间(tm格式) |
可按年月日时分秒显示 |
ctime |
将UTC秒数转换为本地时间(字符串格式) |
星期 月 日 时分秒 年 |
asctime |
将tm时间转换为UTC秒数(字符串形式) |
星期 月 日 时分秒 年 |
mktime |
将tm格式的时间转换为UTC秒数 |
统计过去了多少秒 |
strftime |
将tm格式的时间转换为指定格式 |
时间转换为特定格式 |
函数 |
功能描述 |
选用场景 |
difftime |
统计两个时间相差的秒数 |
计算两个UTC时间相差多少秒 |
ctime_r, localtime_r, asctime_r, gmtime_r |
当ctime, localtime, asctime, gmtime对应的线程安全函数 |
线程安全的时间转换函数 |
ctime/asctime两者传入的参数结构不同,见4. 详细解析
4. 详细解析
4.1 时间获取函数
1. clock函数 |
|
头文件 |
#include |
函数原型 |
clock_t clock(void) |
函数说明 |
typedef long clock_t;获取从程序启动到此函数调用消耗的处理器时间,精确到毫秒 |
返回值 |
时间可用返回时间,否则返回-1 |
#include
#include
#include
#include
#include
void function()
{
double d = 0;
for (int n = 0; n < 10000; ++n)
for (int m = 0; m < 10000; ++m)
d += d * n * m;
}
int main()
{
std::clock_t clock_start = std::clock();
auto utc_start = std::chrono::high_resolution_clock::now();
std::thread t1(function);
std::thread t2(function);
t1.join();
t2.join();
std::clock_t clock_end = std::clock();
auto utc_end = std::chrono::high_resolution_clock::now();
std::cout << std::fixed << std::setprecision(2) << "CPU耗时: "
<< (clock_end - clock_start) / 1000.0 << " ms\n"
<< "UTC耗时: "
<< std::chrono::duration<double, std::milli>(utc_end - utc_start).count()
<< " ms\n";
}
g++ -o main main.cpp -lpthread
./main
2. time函数 |
|
头文件 |
#include |
函数原型 |
time_t time(time_t* t) |
函数说明 |
typedef long time_t; 返回UTC时间,精确到秒 |
返回值 |
成功返回秒数,失败返回 (time_t)-1 |
#include
#include
using namespace std;
int main()
{
time_t seconds = time((time_t*)NULL);
std::cout << seconds << std::endl;
return 0;
}
g++ -o main main.cpp
3. gettimeofday函数 |
|
头文件 |
#include #include |
函数原型 |
int gettimeofday (struct timeval * tv , struct timezone * tz) |
函数说明 |
时间放到tv结构,时区放到tz所指结构。tz一般使用nullptr |
返回值 |
成功返回0, 失败返回-1 |
#include
#include
#include
using namespace std;
int main()
{
struct timeval tv;
struct timezone tz;
gettimeofday (&tv , &tz);
std::cout << "\n tv.sec = " << tv.tv_sec << ", tv.usec = " << tv.tv_usec << std::endl;
std::cout << "\n tz.minuteswest = " << tz.tz_minuteswest << ", tz.tz_dsttime = " << tz.tz_dsttime << std::endl;
return 0;
}
4. chrono库时间函数 |
|
头文件 |
#include |
函数原型 |
std::chrono::system_clock()::成员函数 |
函数说明 |
常用::now()获取当前UTC时间,用::is_steady判断是否为稳定时钟 |
chrono三个时间函数的区别 |
|
system_clock() |
系统时钟,精确到微秒。不稳定,NTP时间变化会跟着变。 |
steady_clock() |
稳定时钟,精确到纳秒。适合于记录程序耗时 |
high_resolution_clock() |
高精度时钟,精确到纳秒。相当于steady_clock的高精度版本 |
- 三个函数均是c11才引入的
- system_clock还有两个成员函数 to_time_t和from_time_t
- system_clock和gettimeofday精度有微秒级差异,不能混用!会造成时间错乱
- 使用实例
#include
#include
#include
using namespace std;
using namespace chrono;
int main()
{
std::cout << "system_clock::is_steady: " << std::boolalpha << system_clock::is_steady << std::endl;
std::cout << "steady_clock::is_steady: " << std::boolalpha << steady_clock::is_steady << std::endl;
std::cout << "high_resolution_clock::is_steady: " << std::boolalpha << high_resolution_clock::is_steady << std::endl;
auto start = system_clock::now();
int i = 0;
while (i < 10000)
i++;
duration<double> timeGap = system_clock::now() - start;
std::cout << "timeGap: " << duration_cast<microseconds>(timeGap).count() << endl;
std::time_t timeT = system_clock::to_time_t(system_clock::now());
std::cout << asctime(gmtime(&timeT)) << std::endl;
std::cout << asctime(localtime(&timeT)) << std::endl;
duration<double> timeGap1 = system_clock::now() - system_clock::from_time_t(timeT);
std::cout << "timeGap: " << duration_cast<microseconds>(timeGap1).count() << std::endl;
return 0;
}
4.2 时间转换函数
1. ctime函数 |
|
头文件 |
#include |
函数原型 |
char* ctime(const time_t *time); |
函数说明 |
将time_t格式时间以字符串形式返回 |
返回值 |
成功返回0, 失败返回-1 |
#include
#include
using namespace std;
int main()
{
time_t timep;
time(&timep);
std::cout << ctime(&timep) << std::endl;
return 0;
}
2. localtime函数 |
|
头文件 |
#include |
函数原型 |
struct tm* localtime(const time_t * timep); |
函数说明 |
将time_t格式时间以tm格式返回,转换为为当地时区 |
返回值 |
返回tm结构代表当地时间 |
#include
#include
#include
using namespace std;
int main()
{
string wday[] = {"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
time_t timep;
time(&timep);
struct tm *localTime = localtime(&timep);
std::cout << 1900 + localTime->tm_year << 1 + localTime->tm_mon << localTime->tm_mday;
std::cout << " " << wday[localTime->tm_wday] << " " << localTime->tm_hour << " " << localTime->tm_min << " " << localTime->tm_sec << std::endl;
return 0;
}
3. gmtime函数 |
|
头文件 |
#include |
函数原型 |
struct tm* gmtime(const time_t*timep); |
函数说明 |
将tm格式时间转换为真实世界时间,中间转换使用 |
返回值 |
返回tm格式时间为UTC时间 |
#include
#include
#include
using namespace std;
int main()
{
string wday[] = {"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
time_t timep;
time(&timep);
struct tm *gmTime = gmtime(&timep);
std::cout << 1900 + gmTime->tm_year << 1 + gmTime->tm_mon << gmTime->tm_mday;
std::cout << " " << wday[gmTime->tm_wday] << " " << gmTime->tm_hour << " " << gmTime->tm_min << " " << gmTime->tm_sec << std::endl;
return 0;
}
- localtime和gmtime区别:时区。比如gmtime是10:00, 中国时间localtime就是18:00 (GMT+8)
4. asctime函数 |
|
头文件 |
#include |
函数原型 |
char* asctime(const struct tm * timeptr); |
函数说明 |
将tm格式时间转换为当地时间,以字符串形式返回 |
返回值 |
返回字符串表示当地时间 |
#include
#include
using namespace std;
int main()
{
time_t timep;
time(&timep);
std::cout << asctime(gmtime(&timep)) << std::endl;
return 0;
}
5. mktime函数 |
|
头文件 |
#include |
函数原型 |
time_t mktime(strcut tm* timeptr);/ |
函数说明 |
将tm格式时间转换为time_t时间(UTC秒数) |
返回值 |
UTC时间秒数 |
#include
#include
using namespace std;
int main()
{
time_t timep;
time(&timep);
std::cout << "time(): " << timep << std::endl;
struct tm *localTime = localtime(&timep);
timep = mktime(localTime);
std::cout << "time() -> localTime() -> mktime(): " << timep << std::endl;
return 0;
}
time(): 1651132717
time() -> localTime() -> mktime(): 1651132717
6. strftime函数 |
|
头文件 |
#include |
函数原型 |
size_t strftime(char *strDest, size_t maxSize, const char *format, const struct tm *timeptr); |
函数说明 |
将tm格式时间转换为自定义时间格式。 |
参数 |
strDest: 存放格式化后的字符串; maxSize: 最多可以输出的字符数; format: 格式化; timeptr: 要转换的tm格式时间 |
返回值 |
UTC时间秒数 |
#include
#include
#include
int main(void)
{
char buff[70];
struct tm tmTime;
tmTime.tm_year = 122;
tmTime.tm_mon = 3;
tmTime.tm_mday = 28;
tmTime.tm_hour = 16;
tmTime.tm_min = 12;
tmTime.tm_sec = 21;
if (strftime(buff, sizeof buff, "%A %c", &tmTime)) {
std::cout << buff << std::endl;
} else {
std::cout << "strftime failed" << std::endl;
}
setlocale(LC_TIME, "ja_JP");
if (strftime(buff, sizeof buff, "%A %c", &tmTime)) {
std::cout << buff << std::endl;
} else {
std::cout << "strftime failed" << std::endl;
}
return 0;
}
4.3 时间差计算函数
difftime函数 |
|
头文件 |
#include |
函数原型 |
double difftime(time_t, time_t) |
函数说明 |
计算两个UTC时间的差值 |
返回值 |
时间差,精确到秒 |
#include
#include
#include
using namespace std;
int main(void)
{
time_t start, ends;
clock_t cstart, cends;
start = time(NULL);
cstart = clock();
sleep(3);
ends = time(NULL);
cends = clock();
cout << "时间差:" << difftime(ends, start) << endl;
cout << "Clock时间差:" << cends - cstart << endl;
return 0;
}
4.4 线程安全的时间转换函数
- 以下时间转换函数是线程安全的,多线程中应用对应的xxx_r函数代替xxx函数
char *ctime_r(const time_t *timep, char *buf);
struct tm *localtime_r(const time_t *timep, struct tm *result);
char *asctime_r(const struct tm *tm, char *buf);
struct tm *gmtime_r(const time_t *timep, struct tm *result);
参考文章:
C++时间获取函数
C++时间函数总结
线程安全的时间函数
C++时间函数实例
C++时间函数详细说明
chrono三个时间函数的区别
created by shuaixio, 2022.04.28