C++时间函数小结
time
time_t time (time_t* timer);
返回的值表示自1970年1月1日0时0分0秒(这个时间名叫 The Unix Epoch)起,到现在过去的时间,这里C/C++标准中并没有规定精度单位(linux和windows中单位是秒),也没有规定time_t的类型长度。
当time_t是32位有符号整型的时候,并且时间单位是秒,那么最大只能表示2038年1月19日3时14分8秒,也就是Y2038问题。
但在64位linux和windows上,time_t都是64位的,所以不用担心溢出问题,但是我在raspbian32位系统上测试,time_t是32位的,所以可能业界以后还是会引入新的类型来解决这一问题吧,或者升级64位操作系统就是解决方案?
gettimeofday
int gettimeofday(struct timeval *tv, struct timezone *tz);
同样也是获取自1970年1月1日0时0分0秒,到现在过去的时间。并且将结果写入timeval
结构中:
struct timeval {
time_t tv_sec; /* seconds */
suseconds_t tv_usec; /* microseconds */
};
而timezone
参数已经过时了,所以直接传入nullptr
即可。下面是使用gettimeofday
的代码示例:
/**
* 返回自unix时间戳(unix epoch)到现在经过的时间(ms)
* @return 自unix时间戳到现在经过的时间(ms)
* @note 若time_t为32位,会有Y2038问题,如果只是用于计算时间差影响不大
*/
uint64_t utcTime() noexcept {
// struct timeval {
// time_t tv_sec; /* seconds */
// suseconds_t tv_usec; /* microseconds */
// }
// 64位linux和windows中,time_t都是64位的,但一些32位系统time_t为32位,最多只能计数到2038年
struct timeval tv;
gettimeofday(&tv, nullptr);
return tv.tv_sec * 1000 + tv.tv_usec / 1000;
}
日期转字符串
时间戳转为字符串分为两步:
struct tm *localtime(const time_t *timep)
将time_t转换为tm结构体;size_t strftime(char *s, size_t max, const char *format,const struct tm *tm)
将tm结构体转换为指定格式字符串输出;
tm结构体:
成员 | 类型 | 含义 | 取值范围 |
---|---|---|---|
tm_sec | int | 秒数 | 0-60* |
tm_min | int | 分钟 | 0-59 |
tm_hour | int | 小时 | 0-23 |
tm_mday | int | 日期 | 1-31 |
tm_mon | int | 月份 | 0-11 |
tm_year | int | 年份 | |
tm_wday | int | 星期几 | 0-6 |
tm_yday | int | 今年的第几天 | 0-365 |
tm_isdst | int | 夏令时标志 | |
常用日期输出格式控制符: | |||
控制符 | 说明 | 示例 | |
- | - | - | |
%Y | 年份 | 2020 | |
%y | 年份后两位 | 20 | |
%m | 月份(01-12) | 04 | |
%d | 日期(01-31) | 05 | |
%H | 24小时(00-23) | 23 | |
%I | 12小时(01-12) | 11 | |
%M | 分钟(00-59) | 23 | |
%S | 秒数(00-59) | 45 | |
这里使用strftime 时需要注意,该函数不是线程安全的,因为使用了全局共享的空间去返回结果。这时可以用linux和windows的可重入替代版本: |
- linux:
struct tm *localtime_r(const time_t *timep, struct tm *result)
- windows:
struct tm *localtime_s(struct tm *result, const time_t *timep)
可以看到linux和windows的功能都是一样的,只是参数顺序不同。
字符串转日期
在linux系统上提供了char *strptime(const char *s, const char *format, struct tm *tm)
函数,可以将字符串转换为tm结构体。
再用mktime
就可以将tm结构体转换为time_t了,这里重点讲一下这个mktime
,首先它会忽略掉tm_wday
和tm_yday
成员,然后会自动纠正里面的错误,比如tm_mday
天数设置为32超了一天,那么mktime
会自动将其理解为下一个月的第一天。最后会将修正后的信息改写如传入的tm结构体中。