现在的位置: 首页 > 综合 > 正文

时间转换相关函数

2013年06月13日 ⁄ 综合 ⁄ 共 4729字 ⁄ 字号 评论关闭

 linux下存储时间常见的有两种存储方式,一个是从1970年到现在经过了多少秒,一个是用一个结构来分别存储年月日时分秒的。

time_t 这种类型就是用来存储从1970年到现在经过了多少秒,要想更精确一点,可以用结构struct timeval,它精确到微妙。

struct timeval

{

   long tv_sec; /*秒*/

   long tv_usec; /*微秒*/

};

直接存储年月日的是一个结构:

struct tm

{

   int tm_sec; /*秒,正常范围0-59, 但允许至61*/

   int tm_min; /*分钟,0-59*/

   int tm_hour; /*小时, 0-23*/

   int tm_mday; /*日,即一个月中的第几天,1-31*/

   int tm_mon; /*月, 从一月算起,0-11*/

   int tm_year; /*年, 从1900至今已经多少年*/

   int tm_wday; /*星期,一周中的第几天, 从星期日算起,0-6*/

   int tm_yday; /*从今年1月1日到目前的天数,范围0-365*/

   int tm_isdst; /*日光节约时间的旗标*/

};

需要特别注意的是,年份是从1900年起至今多少年,而不是直接存储如2008年,月份从0开始的,0表示一月,星期也是从0开始的, 0表示星期日,1表示星期一。

常用的时间函数:

#include <time.h>

char *asctime(const struct tm* timeptr);

将结构中的信息转换为真实世界的时间,以字符串的形式显示

char *ctime(const time_t *timep);

将timep转换为真实世界的时间,以字符串显示,它和asctime不同就在于传入的参数形式不一样

double difftime(time_t time1, time_t time2);

返回两个时间相差的秒数

int gettimeofday(struct timeval *tv, struct timezone *tz);

返回当前距离1970年的秒数和微妙数,后面的tz是时区,一般不用

函数说明

gettimeofday()会把目前的时间有tv所指的结构返回,当地时区的信息则放到tz所指的结构中。

timezone 结构定义为:

struct timezone{

int tz_minuteswest; /*Greenwich时间差了多少分钟*/

int tz_dsttime; /*日光节约时间的状态*/

};

上述两个结构都定义在/usr/include/sys/time.htz_dsttime所代表的状态如下

DST_NONE /*不使用*/

DST_USA /*美国*/

DST_AUST /*澳洲*/

DST_WET /*西欧*/

DST_MET /*中欧*/

DST_EET /*东欧*/

DST_CAN /*加拿大*/

DST_GB /*大不列颠*/

DST_RUM /*罗马尼亚*/

DST_TUR /*土耳其*/

DST_AUSTALT /*澳洲(1986年以后)*/

返回值

成功则返回0,失败返回-1,错误代码存于errno。附加说明EFAULT指针tvtz所指的内存空间超出存取权限。

范例

可以看出,使用这种方式计时,精度可达微秒,也就是10-6秒。进行计时的时候,我们需要前后调用两次gettimeofday,然后计算中间的差值:

gettimeofday( &start, NULL );

foo();

gettimeofday( &end, NULL );

timeuse = 1000000 * ( end.tv_sec -start.tv_sec ) + end.tv_usec - start.tv_usec;

timeuse /= 1000000;

 

struct tm* gmtime(const time_t *timep);

将time_t表示的时间转换为没有经过时区转换的UTC时间,是一个struct tm结构指针

stuct tm* localtime(const time_t *timep);

和gmtime类似,但是它是经过时区转换的时间。

time_t mktime(struct tm* timeptr);

将struct tm 结构的时间转换为从1970年至今的秒数

time_t time(time_t *t);

取得从1970年1月1日至今的秒数。

头文件 #include <time.h>

 定义函数 struct tm *localtime(const time_t * timep);

 函数说明 localtime()将参数timep 所指的time_t 结构中的信息转换成真实世界所使用的时间日期表示方法,

返回值返回结构tm 代表目前的当地时间.

 范例

 #include<time.h>

 main()

 {

 char *wday[] ={"Sun", "Mon", "Tue", "Wed","Thu", "Fri", "Sat"};

 time_t timep;

 struct tm *p;

 time(&timep);

 p =localtime(&timep); //取得当地时间

 printf ("%d%d%d", (1900+p->tm_year), (l+p->tm_mon), p->tm_mday);

 printf("%s%d:%d:%d\n",wday[p->tm_wday], p->tm_hour, p->tm_min, p->tm_sec);

 }

 

          我们可以使用time调用获取当前的时间,注意,这是以UTC表示的机器时间——自1970年1月1日0点以来的秒数,接着我们用localtime调用可以将time获取的时间转换为本地时间,从UTC 转换到本地时间会依靠时区信息进行调整。对于一个daemon进程而言,如果每隔一段时间用time和localtime调用就可以定期获取当前时间的数值,但是如果在这个期间发生了时区设置转换会怎样呢? 或许你会觉得,那一定会出大问题——时区变了,localtime也会出现很大的调整。如果时区的设置变化了,localtime转换的时间依然与之前没有什么不同,除非程序再次启动。

        Linux的时区设置通过几个不同的途径完成。一方面可以通过设置环境变量TZ来指定时区,例如TZ=Asia/Shanghai,可以将时区指定为上海所在的时区,时区的配置出现在/usr/share/zoneinfo/Asia/Shanghai文件当中(Redhat环境);如果没有指定TZ环境变量,那么缺省的时区配置文件可以用/etc/localtime来获得,这个文件可能是一个符号链接指向真实的文件,也有可能就是将/usr/share/zoneinfo下的文件复制过来达到所要的结果。由于环境变量由各个进程组单独继承,那么在设置时区之后很难改变其他进程组的环境变量,所以一般的系统很少直接设置TZ环境变量,而是由/etc/localtime文件来指示时区位置。
既然如此,为什么设置了时区以后,已经运行的daemon程序在使用localtime函数调用时没有使用新时区呢?这个可以通过glibc的源码来回答。

         localtime等涉及到本地所在时区的函数在调用的时候会先调用tzset这个函数,这一点可以通过tzset函数的manpage看出来。tzset完成的工作是把当前时区信息(通过TZ环境变量或者/etc/localtime)读入并缓冲。事实上tzset在实现的时候是通过内部的 tzset_internal函数来完成的,显式的调用tzset会以显式的方式告知tzset_internal,而单独调用localtime的时候是以隐式的方式告知tzset_internal,前者将强制tzset不管何种情况一律重新加载TZ信息或者/etc/localtime,而后者则是只有在TZ发生变化,或者加载文件名发生变化的时候才会再次加载时区信息。因此,如果只是/etc/localtime的内容发生了变化,而文件名"/etc/localtime"没有变化,则不会再次加载时区信息,导致localtime函数调用仍然以老时区转换UTC时间到本地时间。
结论:对localtime的反复调用,如果要考虑时区变化的因素,最好显式的调用一次tzset。或许今后的glibc库会修正这个bug?至少我在glibc-2.3.5和2.4的版本上还看到这个问题。

 

函数名称: tzset

函数原型: void tzset(void)

函数功能: UNIX兼容函数,用于得到时区,在DOS环境下无用途

所属文件: <time.h>

#include <time.h>

#include <stdlib.h>

#include <stdio.h>

int main()

{

time_t td;

putenv("TZ=PST8PDT");

tzset();

time(&td);

printf("Currenttime=%s",asctime(localtime(&td)));

return 0;

}

 

clock_gettime( ) 提供了纳秒级的精确度  

头文件 <time.h>  

编译&链接。在编译链接时需加上 -lrt ;因为在librt中实现了clock_gettime函数  

函数原型  

int clock_gettime(clockid_t clk_id, structtimespect *tp);  

参数说明:  

clockid_t clk_id 用于指定计时时钟的类型,有以下4种:  

CLOCK_REALTIME:系统实时时间,随系统实时时间改变而改变,即从UTC1970-1-10:0:0开始计时,中间时刻如果系统时间被用户该成其他,则对应的时间相应改变  

CLOCK_MONOTONIC:从系统启动这一刻起开始计时,不受系统时间被用户改变的影响  

CLOCK_PROCESS_CPUTIME_ID:本进程到当前代码系统CPU花费的时间  

CLOCK_THREAD_CPUTIME_ID:本线程到当前代码系统CPU花费的时间  

struct timespect *tp用来存储当前的时间,其结构如下:  

struct timespec  

{  

time_t tv_sec; /* seconds */ 

long tv_nsec; /* nanoseconds */ 

};  

返回值。0成功,-1失败 

#include<stdio.h> 

#include<time.h>  

int main()  

{  

struct timespec ts;  

clock_gettime(CLOCK_REALTIME, &ts);  

printf("CLOCK_REALTIME: %d, %d", ts.tv_sec, ts.tv_nsec);  

clock_gettime(CLOCK_MONOTONIC, &ts);

//打印出来的时间跟 cat /proc/uptime
第一个参数一样  

printf("CLOCK_MONOTONIC: %d, %d", ts.tv_sec,ts.tv_nsec);  

clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts);  

printf("CLOCK_PROCESS_CPUTIME_ID: %d, %d", ts.tv_sec,ts.tv_nsec);  

clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts);  

printf("CLOCK_THREAD_CPUTIME_ID: %d, %d", ts.tv_sec,ts.tv_nsec);  

printf("/n%d/n", time(NULL));  

   return 0;  

}  

  

 

抱歉!评论已关闭.