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
。