C++常用的时间接口
与时间相关的操作在开发中是十分常见的,本文总结了常用时间接口,并给出了示例代码。
1 获取当前系统的时间
在C++中用于表示时间的数据结构有: time_t
, struct tm
, struct timeval
, struct timespec
等。
1.1 获取 time_t
格式的时间
std::time_t time(std::time_t* arg);
其中 arg
参数可以是现有变量的地址,结果就会存储在该变量中;当然, arg
参数也可以是 nullptr
。
1.2 获取 struct tm
格式的时间
struct tm
提供了详细的,便于阅读的时间格式。可以通过这个时间格式直接获得常用的时间信息,如月份、星期等。
struct tm {
int tm_sec;
int tm_min;
int tm_hour;
int tm_mday;
int tm_mon;
int tm_year;
int tm_wday;
int tm_yday;
int tm_isdst;
};
一般通过将 time_t
转换为 struct tm
的方式获取该格式的时间。
std::tm* localtime(const std::time_t* time);
std::tm* localtime_s(const std::time_t* time, struct tm* result);
在多线程情况下,推荐使用线程安全的版本 localtime_s
,这个版本使用了用户指定的变量地址用来存储结果。
1.3 获取 struct timeval
格式的时间
timeval
格式能够表示精确到微秒(us)的时间。
typedef struct timeval {
long tv_sec;
long tv_usec;
} timeval;
在linux系统中,使用 gettimeofday
获取 struct timeval
格式的当前时间。
int gettimeofday(struct tm* tp, void* tzp);
在windows系统中,没有 gettimeofday
的官方实现,可以使用以下代码。
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <stdint.h> // portable: uint64_t MSVC: __int64
int gettimeofday(struct timeval * tp, struct timezone * tzp) {
// Note: some broken versions only have 8 trailing zero's, the correct epoch has 9 trailing zero's
// This magic number is the number of 100 nanosecond intervals since January 1, 1601 (UTC)
// until 00:00:00 January 1, 1970
static const uint64_t EPOCH = ((uint64_t) 116444736000000000ULL);
SYSTEMTIME system_time;
FILETIME file_time;
uint64_t time;
GetSystemTime( &system_time );
SystemTimeToFileTime( &system_time, &file_time );
time = ((uint64_t)file_time.dwLowDateTime ) ;
time += ((uint64_t)file_time.dwHighDateTime) << 32;
tp->tv_sec = (long) ((time - EPOCH) / 10000000L);
tp->tv_usec = (long) (system_time.wMilliseconds * 1000);
return 0;
}
(以上代码摘自stackoverflow)
1.4 获取 struct timespec
格式的时间
timespec
数据结构从C++17 / C11开始支持, timespec
提供精确到纳秒(ns)的时间表示方法。
struct timespec {
time_t tv_sec; /* seconds */
long tv_nsec; /* nanoseconds */
};
使用 timespec_get
函数获取 timespec
,该函数也是 C++17 / C11 中的函数接口。
int timespec_get(struct timespec* ts, int base);
2 时间形式的转换
2.1 std::time_t
与 std::tm
( struct tm
)转换
将 std::time_t
转换为 std::tm
的函数:
std::tm* localtime(const std::time_t* time);
// (C11接口,线程安全)
struct tm* localtime_s(const time_t* restrict time,
struct tm* restrict result);
std::tm* gmtime(const std::time_t* time);
// (C11接口,线程安全)
struct tm* gmtime_s(const time_t* restrict time,
struct tm* restrict result);
将 std::tm
转换为 std::time_t
的函数:
time_t mktime(struct tm *time);
2.2 std::time_t
与字符串转换
将 std::time_t
转换为字符串的函数:
char* ctime(const time_t* time);
// (C11接口,线程安全)
errno_t ctime_s(const time_t* time, char* buf);
2.3 std::tm
与字符串转换
将 std::tm
转换为字符串的函数:
char* asctime(const struct tm* time_ptr);
errno_t asctime_s(char *buf, rsize_t bufsz,
const struct tm *time_ptr);
std::size_t strftime(char* str, std::size_t count,
const char* format, const std::tm* time);
// C++11
template< class CharT >
/*unspecified*/ put_time(const std::tm* tmb, const CharT* fmt);
3 计算时间间隔
推荐使用 std::chrono::steady_clock
进行时间间隔的计算,因为 steady_clock
是单调的,不会受到校时的影响。不推荐使用 std::chrono::system_clock
进行时间间隔的计算,由于它会受到系统时间更改的影响,如果在计时间隔中修改了系统时间,则本次的计算结果会收到影响。
如果编译器不支持C++11,可以考虑以系统启动时间作为基准进行时间间隔的计算。
4 C++11风格的时钟接口
C++11中提供了 std::chrono
库,丰富了与时间相关的函数,其中定义了三种主要的类型:
- clock 时钟相关
- time point 某个时间点
- duration 一段时间
更详细的资料可以参考 cppreference 。