10.01 时间类型 tm time_t timeval timespec

总览

700

和时间相关的很多函数都是不可重入的。它们修改同一块静态分配的内存区域并返回,因此不是线程安全的。在新版本已经有 *_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