Unix时间日期例程之间是怎样的复杂关系?

摘要:GMT 和 UTC 时间有何区别?Unix 时间例程为何不处理闰秒?系统时区是如何设置的?哪些时间例程受夏时制影响?localtime 和 gmtime 是否共享内部存储区?strftime 获取第几周使用的 %U%V%W 有何区别?l
概览 开门见山先上图 界定一些术语,方便后面说明: GMT:格林威治平均时,太阳每天经过位于英国伦敦郊区的皇家格林威治天文台的时间为中午 12 点,1972 年之前使用的国际标准时间,因地球在它的椭圆轨道里的运动速度不均匀,这个时刻可能和实际的太阳时相差16分钟。 UTC:国际标准时间,相当于本初子午线 (即经度0度) 上的平均太阳时。UTC 时间是经过平均太阳时 (以格林威治时间 GMT 为准)、地轴运动修正后的新时标以及以秒为单位的国际原子时所综合精算而成。 Epoch:日历时间,自国际标准时间公元 1970 年 1 月 1 日 00:00:00 以来经过的秒数。 Unix 日期时间 获取 unix 通过接口 time 将 Epoch 作为整数返回,自然的包含了日期和时间两部分: time_t time(time_t *tloc); 其中 time_t 在 64 位系统上是 8 字节整数 (long long): sizeof (time_t) = 8 在 32 位系统上可能是 4 字节整数,没有试。 time 例程的 tloc 参数如果不为空,则时间值也存放在由 tloc 指向的单元内。 如果想获取更精准的时间,需要借助另外的接口: int gettimeofday(struct timeval *tv, struct timezone *tz); 时间通过参数 tv 返回: struct timeval { time_t tv_sec; /* seconds */ suseconds_t tv_usec; /* microseconds */ }; 除了代表 UTC 的 tv_sec 外还有代表微秒的 tv_usec,注意如果只需要精确到毫秒,需要将这个值除以 1000。 在 64 位 CentOS 上它是 8 字节整数: sizeof (suseconds_t) = 8, sizeof (struct timeval) = 16 不过不是所有 64 位系统这个字段都是 long long,在 64 位 Darwin 上它是 4 字节整数: sizeof (suseconds_t) = 4, sizeof (struct timeval) = 16 但最终 timeval 结构体的长度还是 16,可能是内存对齐的缘故。 tz 参数用来指定时区信息: struct timezone { int tz_minuteswest; /* minutes west of Greenwich */ int tz_dsttime; /* type of DST correction */ }; 因为一些原因,tz 在 SUS 标准中唯一合法值是 NULL,某些平台支持使用 tz 说明时区,但完全没有可移植性,例如在 Linux 上,建议这个参数设置为 NULL: The use of the timezone structure is obsolete; the tz argument should normally be specified as NULL. (See NOTES below.) 不为 NULL 也不会报错,但是不会修改指定参数的内容。Darwin 支持这个参数,下面是它的日常返回: minuteswest = -480, dsttime = 0 具体可参考时区和夏时制一节。 转换 time_t 类型利于接口返回,但可读性比较差,需要将它转换为人能理解的日期和时间。
阅读全文