概述
在一个程序之内,我们可能对两类时间会很感兴趣:
- 真实时间Real time:这是一个要么从某个标准点开始测量的时间(日历时间)或者从某一个固定点(进程起始)开始测量的process已经过的时间。获得日历时间对于程序来说非常有用,比如说,对于时间戳数据记录或者文件。对于程序来说测量已经过的时间对于那些采取周期性动作或者在外部输入设备上做一定的时间测量非常有用。
- 进程时间Process time:被进程所用的CPU时间。测量进程时间对于检查或者优化程序或者算法的表现非常有用。
大多数计算机架构都有一个自己的内建硬件时钟允许内核测量真实和进程时间。这一章,我们会看几个处理这两种类型时间的系统调用还有库函数来在人类可理解的和内部表示的时间之间做转换。因为人类可读的时间形式是依赖于地理位置还有语言文化传统,当讨论这些形式的时候就会引导我们进入时区和位置信息。
10.1 日历时间
不考虑地理位置,UNIX系统内部时间是从Epoch开始以秒计时。Epoch时间也就是1970年1月1日午夜,UTC时间。这个时间是UNIX系统开始工作的时候。日历时间被存储在time_t变量当中,SUSv3中规定是一个整型。
小提示:如果是在使用Linux32位系统的话,那么它的time_t是一个带符号的整型数字,它只能用来表示1901年12月31日20:45:52到2038年1月19日 03:14:07这个时间区间的时间。因此,有很多32位的UNIX系统都会面临到一个2038年问题,但如果他们在2038年之前也许计算一些日期晚于2038年的话,那么它们将会提前遇到这样的问题。但是到2038年的时候也许大多数Linux系统就已经是64位的了。
使用gettimeofday()系统调用就可以得到被bv指针指向的日历时间。
#include <sys/time.h>
int gettimeofday(struct timeval *tv, struct timezone *tz);
//Returns 0 on success, or –1 on error
而这个timeval是一个结构体类型,它的样子如下:
struct timeval {
time_t tv_sec; /* Seconds since 00:00:00, 1 Jan 1970 UTC */
suseconds_t tv_usec; /* Additional microseconds (long int) */
};
虽然tv_usec是一个单位是微秒us的数据,但是它的精确度是由架构所决定的。在现代x86-32系统上,gettimeofday()确实可以提供微秒级准确度信息。
tz参数之于ggettimeofday()只是一个历史遗迹。在早期UNIX实现中,它被用于获取系统上的时区信息。现在这个参数已经不再有用而且一般来讲需要设置成NULL。
time()系统调用返回从Epoch开始所经过的秒数,其实也就是gettimeofday()中返回的tv数组中的tv_sec。
#include <time.h>
time_t time(time_t *timep);
//Returns number of seconds since the Epoch,or (time_t) –1 on error
如果timep参数不是NULL的话,那么从Epoch开始的秒数也就同样会被放在timep所指向的指针变量中。
尽管我们有两种获得该时间的可能性,但是考虑到如果给定的指针是个无效指针的话,这时候就会返回一个错误。为了能够简单安全使用,最好的办法还是设置timep为NULL。
t = time(NULL);
10.2 时间转换函数
下午列出了在time_t时间和别的时间形式之间的转换。这些函数帮助我们解决时区,地理等等复杂问题。
10.2.1 转换time_t到可读形式
ctime()函数提供了一个简单的方式来转换time_t数据到可读形式上:
#include <time.h>
char *ctime(const time_t *timep);
//Returns pointer to statically allocated string terminated
//by newline and on success, or NULL on error
给定一个指向time_t值的指针timep,ctime()就会返回一个26字节长的字符串包含了标准化形式的日期和时间,就像这样--Wed Jun 8 14:22:34 2011。
该字符串包含了"