time_t的局限性及时间函数设计
time_t早期是32位的,用来表示从1970.1.1开始的秒数,当初设计的时候受制于32位的容量,time_t只能表示136年的时间,而且精度只能到秒,后来time_t修改为64位,但仍然兼容了原来的设计,time_t虽然现在默认64位了但依然精度为秒,这是极大浪费的。
系统还有很多time相关的函数,如win下mktime、gmtime、GetSystemTime、GetSystemTimeAsFileTime、gettimeofday等,对应有日期时间的结构也很多,如:
typedef struct_SYSTEMTIME {
WORDwYear;
WORDwMonth;
WORDwDayOfWeek;
WORDwDay;
WORDwHour;
WORDwMinute;
WORDwSecond;
WORDwMilliseconds;
} SYSTEMTIME, *PSYSTEMTIME, *LPSYSTEMTIME;
typedef struct_FILETIME {
DWORD dwLowDateTime;
DWORD dwHighDateTime;
} FILETIME, *PFILETIME, *LPFILETIME;
struct timeval{
long tv_sec; /*seconds */
long tv_usec; /* andmicroseconds */
};
struct tm{
inttm_sec; /*seconds after the minute - [0,59] */
inttm_min; /*minutes after the hour - [0,59] */
inttm_hour; /* hourssince midnight - [0,23] */
inttm_mday; /* dayof the month - [1,31] */
inttm_mon; /*months since January - [0,11] */
inttm_year; /* yearssince 1900 */
inttm_wday; /* dayssince Sunday - [0,6] */
inttm_yday; /* dayssince January 1 - [0,365] */
inttm_isdst; /*daylight savings time flag */
};
这些时间表示都有一个特点,他们都是绝对时间或相对于某个固定基点(如1970.1.1或1600.1.1)开始的某个精度表示,系统还提供了一些相对于os启动时刻的tickcount表示,如GetTickCount、GetTickCount64等,这些函数主要用在时间间隔测量上,由于GetTickCount有47.9天回绕问题,但GetTickCount64又是vista只后才增加的函数,所以并不是太通用,虽然也有人想出了一些对付回绕的办法,但如果发生两次回绕则计算还是会出错,而且这个tickcount函数和绝对时间没有换算关系,由于参照物为os启动时间,因此这个tickcount在两台不同的机器上无法进行相对运算。
综上描述,时间类函数主要有三类,一类是绝对时间的,一类是相对某个固定时间(如1970.1.1或1600.1.1)的,还有相对于机器启动时间的tickcount系列,现有函数缺陷主要有两个,time_t系列精度不够,tickcount系列参照物不具有可比性,因此现有时间系列函数很不易用,实际上我们可以充分利用uint64_t的表示范围,定义一个绝对或相对于某个时间起始的时间类型,如:
typedef uint64_t millitime_t; 精度为毫秒(可标识584942417年)
typedef uint64_t microtime_t; 精度为微妙(可标识584942年)
typedef uint64_t bnanotime_t; 精度为100纳秒(可标识58494年)
它的差值即为其精度表示的间隔数,如果他们也是相对于1970.1.1基点,那么它和传统的秒表示的time_t很容易换算,如millitime_t/1000即为time_t,millitime_t%1000即为毫秒,传输也很方便,只占用8个字节,要测量时间间隔精度也满足要求,在可预测时间内也不会发生回绕,可用性易用性都满足要求,在win下有一个函数基本满足这个要求,GetSystemTimeAsFileTime这个函数返回的是从1600.1.1开始的100纳秒数,但这个函数取名不是太好,导致很多人根本不知道有这个函数可用,在linux下通过gettimeofday也很容易包装出这个函数,如果要取其他精度的函数也可根据这个函数进行一些简单运算获得。
通过使用这种新方式标识的时间,使得以前描述一个任务既要记录绝对时间SYSTEMTIME,又要记录tickcount就变成只需要记录一个时间即可,而且这个时间在不同机器上也可以基本度量tickcount,避免了原来tick由于相对参照不同带来的问题,简化了设计和实现。