10.01 时间类型 tm time_t timeval timespec
总览

和时间相关的很多函数都是不可重入的。它们修改同一块静态分配的内存区域并返回,因此不是线程安全的。在新版本已经有 *_r 这样的可重入函数来替代它们。
timeval 精确时间,微秒级
struct timeval 是带有秒和微秒的结构体,可以用 gettimeofday 获取,gettimeofday 的第二个参数 struct timezone_t * 建议填 NULL。
#include <sys/time.h>
struct timeval {
time_t tv_sec; /* Seconds */
suseconds_t tv_usec; /* Microseconds */
};
time_t 日历时间,秒级
C 标准库 time 函数获得的秒就是 timeval 结构体的一个分量。尽管 timeval 信息更全面,在分解和格式化时间的时候都只支持了秒级别(time_t)。
tm 分解时间,秒级
分解时间(broken-down) tm 包含了各个组分,有了这个结构体我们也能写出自己的格式化函数。
struct tm {
int tm_sec; /* Seconds [0, 60] */
int tm_min; /* Minutes [0, 59] */
int tm_hour; /* Hour [0, 23] */
int tm_mday; /* Day of the month [1, 31] */
int tm_mon; /* Month [0, 11] (January = 0) */
int tm_year; /* Year minus 1900 */
int tm_wday; /* Day of the week [0, 6] (Sunday = 0) */
int tm_yday; /* Day of the year [0, 365] (Jan/01 = 0) */
int tm_isdst; /* Daylight savings flag */
#ifdef _BSD_SOURCE
long tm_gmtoff; /* Seconds East of UTC */
const char *tm_zone; /* Timezone abbreviation */
#endif
};
为什么 tm_sec 的最大值是 60?这是因为闰秒,最近一次闰秒在 北京时间 2017 年 1 月 1 日 7 时 59 分 59 秒(时钟显示 07:59:60)出现。但有消息说 2035 年将取消闰秒。
使用 time_t mktime(struct tm *tm) 函数可以将分解时间修改之后转换成日历时间。这里修改的含义是:超过存储范围的数值会被正确进位 / 退位,并将数值修改反映在其他部分。
timespec 纳秒级时间类型
struct timespec {
time_t tv_sec; /* Seconds */
/* ... */ tv_nsec; /* Nanoseconds [0, 999'999'999] */
};
在使用 futimens / utimensat 等系统调用时,时间参数类型是纳秒级别的 timespec。