timeval及相关函数
1.结构体定义
timeval结构体在头文件为sys/time.h中,定义如下:
struct timeval { time_t tv_sec; /* seconds */ suseconds_t tv_usec; /* microseconds */ };
该结构体以1970-01-01 00:00:00 +0000 (UTC),也就是Unix中的Epoch作为0,之后的时间都是相对于Epoch流逝的秒和毫秒数。其中tv_sec是秒,tv_usec是微秒(microsecond ),即10-6秒,而不是毫秒(millisecond),10-3秒。
2. 关联函数
gettimeofday
位于头文件sys/time.h中,函数声明如下:
int gettimeofday(struct timeval *tv, struct timezone *tz);
用于获取调用该代码时,距离Epoch的时间。
第一个参数不用多说,第二个参数也是结构体,定义如下:
struct timezone { int tz_minuteswest; /* minutes west of Greenwich */ int tz_dsttime; /* type of DST correction */ };
根据Linux的手册中关于函数gettimeofday的描述(man gettimeofday):
The use of the timezone structure is obsolete; the tz argument should normally be specified as NULL
这种使用方式是过时的,该处通常提供NULL作为参数。
测试代码:
#include <stdio.h> #include <stdlib.h> #include <time.h> #include <sys/time.h> #include <errno.h> #include <unistd.h> int main() { struct timeval tv;int i; for(i=0;i<5;i++) { gettimeofday(&tv, NULL); printf("%ld.%06ld\n", tv.tv_sec, tv.tv_usec); sleep(1); } return 0; }
运行效果如下(和运行时间有关):
1610953256.769513
1610953257.769901
1610953258.770804
1610953259.771444
1610953260.771719
可以看到,并不是非常精确的1秒延时,多次测试发现延时都会滞后一点不过在一般的应用场合是足够了,例如,我们可以两次调用这个函数,测试一段代码执行所消耗的时间等。
另外一个与之相关的函数是settimeofday,看名字就知道是和gettimeofday对应的,这里就不去展开讨论了。
3. 同日期之间的转换
在获取了相对于Epoch的时间以后,相应的日期也就可以确定了,这个时候就要用到time.h中的结构体struct tm了。结构体定义如下:
struct tm
{ int tm_sec; /* Seconds (0-60) */ int tm_min; /* Minutes (0-59) */ int tm_hour; /* Hours (0-23) */ int tm_mday; /* Day of the month (1-31) */ int tm_mon; /* Month (0-11) */ int tm_year; /* Year - 1900 */ int tm_wday; /* Day of the week (0-6, Sunday = 0) */ int tm_yday; /* Day in the year (0-365, 1 Jan = 0) */ int tm_isdst; /* Daylight saving time */ };
与之相关的几个函数分别是gmtime\localtime、mktime。
先说说将时间戳转换为日期的函数gmtime和localtime,前者是GMT时间,而后者是本地时间,例如现在北京时间是下午16点,则GMT时间实际上是当日的上午8点(我们在东八区,记作GMT+8)。
gmtime定义如下:
struct tm *gmtime(const time_t *timep);
接收一个time_t*的指针,然后将其转换为了代表gmt时间的结构体t指针,需要年月日时分秒等,都可以从这个返回的tm结构体中获取,测试代码如下。
#include <stdio.h> #include <stdlib.h> #include <time.h> #include <sys/time.h> #include <errno.h> #include <unistd.h> int main() { struct timeval tv; struct tm* st; gettimeofday(&tv, NULL); printf("%ld.%06ld\n", tv.tv_sec, tv.tv_usec); st=gmtime(&tv.tv_sec); printf("%02d:%02d:%02d\n",st->tm_hour,st->tm_min,st->tm_sec); return 0; }
这将显示当前的时间,由于使用的是GMT时间,因此,比北京时间慢了8小时,如果使用localtime而不是gmtime的话,则和北京时间相同。
反过来,如果我们向知道某个日期所对应的相对Epoch时间是多少,则可以使用mktime函数,这个函数原型如下:
time_t mktime(struct tm *tm);
就是将tm结构体指针转换为time_t,测试代码如下:
#include <stdio.h> #include <stdlib.h> #include <time.h> #include <sys/time.h> #include <errno.h> #include <unistd.h> int main() { time_t tt; struct tm st; st.tm_year=121;//year=1900+121=2021 st.tm_mon=0;//for Jaunary st.tm_mday=18; st.tm_hour=7; st.tm_min=39; st.tm_sec=34; tt=mktime(&st); printf("%ld\n",tt); return 0; }