Linux下提供了丰富的api以供开发者们处理和时间相关的问题。然而这些接口看似各自为政实则有有着千丝万缕的联系,在学习和时间中引发了各种各样的混乱。因此时间处理成为了许多Linux开发者的梦魇,遇到时间处理往往避之不及。不过只要你稍微花费一点点精力,学会在Linux上优雅的处理时间和日期也并不是什么难事。
所以本文将会详细介绍Linux api和c标准库对时间的处理,对于更现代化的c++的chrono,会在另一篇文章里再讲。
本文并不会涉及定时器(timer),timer和时间有着关联,而且timer对于程序员来说是极为重要的,但介绍timer接口将会花费相当可观的篇幅,那样多少会使本文离题,所以请允许我在另外的文章中单独讨论timer,这里我们主要集中精力在time pointer和date time上。
本文索引time的分类
在讨论具体的时间问题前,我们先要明确时间的概念。也许你觉得时间的概念是那么浅显易懂没有什么额外强调的必要,但对于程序来说却不然。在程序看来时间的定义是灵活多变的,不同的定义下时间的计算是不同的,因此有必要仔细区分。
一般而言Linux上提供了三种时间,每种时间都包含了自己的含义,起点和特征:
real time
日历时间,又叫wall-clock或者system clock,如同字面意思,是指和真实世界中同样的时间。因此这是最直观最容易理解的时间。
对于Linux世界来说这个时间的起点是1970年1月1日0时(UTC),又被叫做Epoch,Linux上以此为起点的均为UTC时间。
real time的最大特点是会受到修改系统时间的命令/api或者ntp服务的影响,因而导致时间出现跳跃。
monotonic time
单调时间,意思是不能被设置和影响的时间,因此相比系统时钟它可以提供更精确是时间信息,也不会出现时间跳跃。
单调时间的起点POSIX标准并没有明确指定,但在Linux上是以系统启动的时间为起点的。
虽然说单调时钟的时间是稳定的,但它会被adjtime函数和ntp服务影响,同时当系统挂起或休眠时计时会被暂停。
cpu time
程序占用的cpu运行时间。
起点是程序开始运行的时间。
起点说的不是很严谨,因为严格来说cpu time计算的是程序占用的cpu的ticks数,所以程序上的用户等待时间是不包含在内的。
总结一下,前两种是我们接触最多的,系统时间最常见于date time的处理,单调时间则是计时功能和定时器的基石;而cpu time虽然用的少但是在衡量程序性能时是一个重要的参考指标。
时间的表示存储时间的方法多如牛毛,而对于计算机来说最简单也最有效率的方式便是记录从起点到现在所经过的时间长度。这也是Linux上不同时间表示法的共通之处。
Linux上最常见的时间存储方案有四种:time_t,struct tm,struct timeval和struct timespec。我们分别介绍它们。
time_ttime_t是c和c++标准库的一部分,有标准库背书,因此用的也是最广泛的。
time_t主要表示日历时间,也就是1970/1/1 0:00 UTC开始到现在的秒数。因此一部分的资料会告诉你他是长整数类型比如long的别名,为了方便你可能会将它们转换为整数类型,这时要小心,虽然大多数情况下time_t确实和整数类型有关系,但不同的实现可能使用了不同的整数类型,比如unsigned long和long long,有时候time_t甚至可能是编译器内置类型的别名,所以为了可移植性不要轻易断定它的原始类型是什么。
获得系统时间的方法有如下几种:
// 参数为空指针直接返回当前UTC时间 std::time_t now = std::time(nullptr); // 参数不为空的时候也会把结果存入参数 std::time_t now_now{}; now = std::time(&now_now); // 通过tm结构体还原成time_t std::tm date = {.tm_year = 70}; // 1970/1/1 std::time_t t = std::mktime(&date); std::cout << std::ctime(&t) << std::endl; // output: Thu Jan 1 00:00:00 1970一切看起来都很自然,时间的获取就应该是一件简单的事情————真的是这样吗?给出一点提示,最后ctime的输出真的正确吗?
答案很遗憾是否定的。首先我们的系统处于UTC+8时区,我们设置tm为1970年1月1日,因此mktime应该返回0,但当我们用ctime输出本地时间时却发现时间仍然在1970/1/1 0:00:00,而没有如我们预期的那样+8小时,这是为什么呢?
我们的time_t所代表的系统时间又叫做日历时间,是真实世界的时间一致的。而我们知道地球上根据经度不同对于各地区的人来说时间也是不同,因此为了正常生活需要划分出时区;各时区的时间不同,但某些事物会在不同的时区同时发生,因此又需要一个统一的标准时来确定时间,这句是协调世界时(UTC)。