UNIX及LinuxQ的时间系统是由「新纪元时间」Epoch开始计算起。Epoch是指定为1970
年1月1日凌晨零点零分零秒,格林威治时间。目前大部份的UNX系统都是用32位来记录时间,正值
表示为1970以后,负值则表示1970年以前。
对于当前时间到Epoch 我们用两种类型来描述 time_t
和 timeval
time_t // 实际上就是uint32_t
struct timeval
{__time_t tv_sec; /* Seconds. */__suseconds_t tv_usec; /* Microseconds. */
};
这两个数据结构唯一的区别 就是timeval
的精度更高,精度达到了微妙
接下来我们要了解如何得到这两个类型:
time()
#include<time.h>
time_t time(time_t *tloc);
参数:
- tloc: 当这个参数不为空的时候 ,距离Epoch 的秒数 会存在tloc所指向的内存中
返回值:
返回的是 距离Epoch 的秒数
从上面的我们发现:
time_t t1;time(&t1);time_t t2;t2 = time(nullptr);
t1 和 t2 得到的结果是一样的
gettimeofday
#include<sys/time.h>
int gettimeofday(struct timeval *tv, struct timezone *tz);
参数:
- *tv: 输入输出型参数,返回现在到Epoch 有多少秒+多少微妙
- tz:已经被废弃,直接NULL完事
返回值:
0 代表成功,-1 代表错误,errno 会被设置
现在我们已经知道了如何获取时间,但是现在又有一个问题,存储的秒数 虽然精确但是不是很易读,如何让这些时间变得易读就要用到接下来的系统调用。
在linux 中我们使用下面的数据结构来表示 一个易读的时间
struct tm
{int tm_sec; /* Seconds. [0-60] (1 leap second) */int tm_min; /* Minutes. [0-59] */int tm_hour; /* Hours. [0-23] */int tm_mday; /* Day. [1-31] */int tm_mon; /* Month. [0-11] */int tm_year; /* Year - 1900. */int tm_wday; /* Day of week. [0-6] */int tm_yday; /* Days in year.[0-365] */int tm_isdst; /* DST. [-1/0/1]*/# ifdef __USE_MISClong int tm_gmtoff; /* Seconds east of UTC. */const char *tm_zone; /* Timezone abbreviation. */
# elselong int __tm_gmtoff; /* Seconds east of UTC. */const char *__tm_zone; /* Timezone abbreviation. */
# endif
};
gmtime
struct tm *gmtime(const time_t *timep); // 线程不安全
struct tm *gmtime_r(const time_t *timep, struct tm *result); // 线程安全的版本
参数:
- timep:距离Epoch 的秒数
- result:输入输出型参数
gmtime_r
输出的结构从输入参数中得到,而不是函数的返回值中得到!gmtime 不是线程安全的原因是把结果存在了静态变量中,导致多线程的时候不可重入!
注意这里的 gmt 和 UTC (世界协调时) 是一样的
localtime
struct tm *localtime(const time_t *timep);
struct tm *localtime_r(const time_t *timep, struct tm *result);
参数:
- timep:距离Epoch 的秒数
- result:输入输出型参数
localtime_r
输出的结构从输入参数中得到,而不是函数的返回值中得到!localtime
不是线程安全的原因是把结果存在了静态变量中,导致多线程的时候不可重入!
下面来介绍一下 gmt 时间 和 本地时间 的区别:
众所周知不同国家都是有时差的,那么比方说北京时间是如何计算出来的呢? 首先UTC(世界协调时) 是一个基准,在这个基准上我们根据经纬度 划分出不同的时区,如果我们想得到本地时间 只要用标准时间加上该地区所在时区的偏移量。
举一个简单的例子: 北京时间在东八区时区,意味着北京时间比基准时间快8个小时(偏移量),而这个标准时间就是gmtime
函数得到的时间 而 本地时间(北京时间) 就是localtime
得到的时间
我们可以做一个小实验
struct timeval t3;gettimeofday(&t3, NULL);struct tm tm1;struct tm tm2;gmtime_r(&t1, &tm1);localtime_r(&t1, &tm2);cout << tm1.tm_year << " " << tm1.tm_mon << " " << tm1.tm_mday << " "<< tm1.tm_hour << endl;cout << tm2.tm_year << " " << tm2.tm_mon << " " << tm2.tm_mday << " "<< tm2.tm_hour << endl;
我们在执行之前先看一下时间
执行结果如下:
我们发现 正如所验证的一样,localtime
比 gmtime
快了八个小时
strftime
按照输入的格式,输出时间
size_t strftime (char *__restrict __s, size_t __maxsize,const char *__restrict __format,const struct tm *__restrict __tp)
参数:
- __s:输出字符串的指针
- __maxsize:输出字符串的大小
- __format:输出到输出字符串的时间的格式 详情见:
man 2 strftime
- __tp:上面获取的时间结构体
输出:
输出到__s
字符串中 的字符的数量