日期:2014-05-16  浏览次数:20883 次

unix系统里的各种时间和时间的转换

我估计很多人对于unix里面的时间各种头疼,我在unix高级环境编程上看到第一张图,发现原来时间转换也可以这么简单,好东西自然就要分享了,于是我就补充了一些内容,删减了一些内容,出现了这篇博文。

1.日历时间
日历时间是我们最经常使用的时间,它包含时间和日期两部分,它是从公元 1970年1月1日00:00:00以来经过的秒数。这种秒数以数据类型 time_t 表示。UNIX在这方面与其他操作系统的区别是:

(a)以国际标准时间而不是本地时间计时

(b)可自动进行转化,例如转化到夏时制
(c)将时间和日期作为一个值保存


#include <time.h>

// 成功则返回时间值,出错则返回 -1
// 如果calptr 不为空,则时间值也保存在 calptr指向的地址
time_t time(time_t *calptr);

// 计算一个事件持续的时间长度,比如计算打字速度。
// 虽然该函数返回的以秒计算的时间间隔是double类型的,但这并不说明该时间具有同double一样的精确度,这是由它的参数觉得的(time_t是以秒为单位计算的)
double difftime(time_t time1, time_t time0);

time提供的是秒级的时间,如果你需要更精确的时间,那么可以试试 gettimeofday ,它提供微秒级的时间表示。

#include <sys/time.h>       //这跟上面的头文件不同

struct timeval {
       time_t tv_sec;       // 妙级的时间
       long   tv_usec;      // 微秒时间
};

/**
 * tzp 的唯一合法值是 NULL,其他值将产生不确定的结果
 * 总是返回 0
 */
 int gettimeofday (struct timeval *restrict tp,void* restrict tzp);

在得到这些整形时间后,通常需要转化为人可读的时间和日期。下图说明了各种时间之间的关系。(如果我没记错的话,python里面的时间也是这种转换关系)


上图中以虚线表示的四个函数受到环境变量TZ的影响。 这四个函数是:

localtime, mktime , ctime 和  strftime。如果定义了TZ,则这些函数将使用其值以代替系统默认时区。如果TZ定义为空串(亦即TZ=),则使用国际标准时间。TZ的值常常类似于:TZ=EST5EDT,但是POSIX.1允许更详细的说明。

由上图可知,有两个函数 localtime 和 gmtime 将日历时间变换成以年、月、日、时、分、秒、周日表示的时间,并将这些存放在一个 tm 结构中。

struct tm {
        int tm_sec;     /* 秒 – 取值区间为[0,60] 因为超过59时可表示闰秒 现在不支持双闰秒了 */
        int tm_min;     /* 分 - 取值区间为[0,59] */
        int tm_hour;    /* 时 - 取值区间为[0,23] */
        int tm_mday;    /* 一个月中的日期 - 取值区间为[1,31] */
        int tm_mon;     /* 月份(从一月开始,0代表一月) - 取值区间为[0,11] */
        int tm_year;    /* 年份,其值等于实际年份减去1900 ,即年份是从1900年开始计算的 */
        int tm_wday;    /* 星期 – 取值区间为[0,6],其中0代表星期天,1代表星期一,以此类推 */
        int tm_yday;    /* 从每年的1月1日开始的天数 – 取值区间为[0,365],其中0代表1月1日,1代表1月2日,以此类推 */
        int tm_isdst;   /* 夏令时标识符,实行夏令时的时候,tm_isdst为正。不实行夏令时的进候,tm_isdst为 0;不了解情况时,tm_isdst()为负。*/
        };

#include <time.h>

/**
 * 以下两个函数的返回值都指向tm的指针
 * 区别是: gmtime将日历时间转化为标准时间,而localtime将日历时间转化为本地时间(考虑时区和夏时制)
 */
struct tm* gmtime( cosnt time_t *calptr);
struct tm* localtime( cosnt time_t *calptr);

/**
* 将本地时间转化为 time_t 的值
* 成功时返回日历时间 出错时返回 -1
*/<br>
time_t mktime(struct tm *tmptr);

/**
* 以下两个函数分别可以把tm 和 time_t 表示的时间转化为字符串
* 以下两个函数都返回字符串指针,当然包括NULL了
*/
char *asctime(const struct tm *tmptr);
char *ctime(const time_t *calptr);

/**
* 将时间格式化为我们想要的格式
* 根据format指向字符串中格式命令把timeptr中保存的时间信息放在strDest指向的字符串中,最多向strDest中存放maxsize个字符
* 返回向strDest指向的字符串中放置的字符数
*/
size_t strftime(char *restrict buf,size_t maxsize,const char *restrict format,const struct tm *restrict tmptr);

函数strftime()的操作有些类似于sprintf():识别以百分号(%)开始的格式命令集合,格式化输出结果放在一个字符串中。格式化命令说明串strDest中各种日期和时间信息的确切表示方法。格式串中的其他字符原样放进串中。格式命令列在下图,它们是区分大小写的。



2.计时时间

说完了日历时间,再来看看计时时间,当你想统计一下你的代码运行了多少个时钟周期就用上计时时间了。计时的函数是clock(),而与其相关的数据类型是clock_t

>#include <time.h>  
  
typedef long clock_t;     // 使用一个长整数计算cpu的滴答次数,可以精确到毫秒级  
  
#define CLOCKS_PER_SEC ((clock_t)1000)         
//也就是说每过千分之一秒(1毫秒),调用clock()函数返回的值就加1  
  
// 返回从“开启这个程序进程”到“程序中调用clock()函数”时之间的CPU时钟计时单元(clock tick)数  
clock_t clock( void );

3.小结