(一)Linux系统中的时间
rtc
由rtc芯片提供的时间,可以转换为格林尼治时间,linux中把这一类时间称为wall time,墙上时间。rtc时间由rtc芯片来维护更新,它通常由一个专门的计时硬件来实现,软件可以读取该硬件来获得年月日、时分秒等时间信息。rtc时间是可持续计时的,通常硬件上会加上一个后备电池供电,这样即使系统关闭,rtc时间依然是正常更新的,这样就可以保证下次系统起来的时候可以从rtc芯片中,重新读取到正确的墙上时间。
xtime
linux系统时间是用从Epoch(1970年1月1日00:00:00 UTC)开始所经过的时间来表示,比如unix时间戳就是从Epoch开始所经过的秒数。注意这里使用的是UTC世界统一时间标准来计算的,它也是一种墙上时间。
monotonic time
单调增长的系统运行时间(ntp影响其单调性), 记录的是从系统启动以来到当前的时间间隔,它不会像xtime一样可以被用户修改而发生跳变。不过该时间不计算休眠时间。
raw monotonic time
raw monotonic time: 该时间与monotonic时间类似,也是单调递增的时间,唯一的不同是,raw monotonic time不会受到NTP时间调整的影响,它代表着系统独立时钟硬件对时间的统计。
boot time
它代表着系统上电后的总时间,包括了休眠时间。
ntp服务会全部影响到上面提到的几种时间类型。ntp就是为了校正时间的服务,为了每次启动都能正确修改,所以rtc要更新,为了使当前时间也修改生效,所以xtime也要更新。
(二)时间操作函数
RTC时间操作:
1.rtc时间是由rtc硬件控制的,所以在linux中想要修改和获取rtc时间就只能通过驱动的接口来获取和修改。
int rtc_test(void)
{
struct rtc_time rtc;
int fd = -1;
int ret = -1;
fd = open("/dev/rtc0", O_RDWR);
if (fd < 0)
{
return -1;
}
ret = ioctl(fd, RTC_RD_TIME, &rtc);
if (ret < 0) {
return -1;
}
printf("\nCurrentRTC data/time is %d-%d-%d, %02d:%02d:%02d.\n",
rtc.tm_mday, rtc.tm_mon + 1, rtc.tm_year + 1900, rtc.tm_hour, rtc.tm_min, rtc.tm_sec);
ret = ioctl(fd, RTC_SET_TIME, &rtc);
if (ret < 0) {
return -1;
}
return 0;
}
2.除了上面这种方式操作rtc时间以外,linux中也有一个命令可以简化rtc时间操作,hwclock,比如,可以通过system("hwclock -w");系统调用来把xtime设置到rtc硬件。
墙上时间(realtime、xtime):
linux系统中主要使用的就是xtime,它是系统运行的基础,很多程序都是依赖于xtime来运行的,接下来将介绍将如何操作xtime。
1.获取、设置微秒级别的时间:
#include <sys/time.h>
#include <unistd.h>
struct timeval
{
inttv_sec;
inttv_usec;
};
int gettimeofday(struct timeval *tv, struct timezone *tz);
int settimeofday(const struct timeval *tv, const struct timezone *gz);
功能描述:
gettimeofday()获取当前时间,有tv指向的结构体返回。
settimeofday()把当前时间设成由tv指向的结构体数据。当前地区信息则设成tz指向的结构体数据。
2.获取秒级别的时间
typedef long time_t;
time_ttime(time_t *t);
如果t是non-null,它将会把时间值填入t中
3.内核2.6版本后新增的clock api接口
获取纳秒级别的时间
struct timespec{
time_t tv_sec; /*秒s*/
long tv_nsec; /*纳秒ns*/
};
int clock_getres(clockid_t clk_id , struct timespec *res);
int clock_gettime(clockid_t clk_id , struct timespec *tp);
int clock_settime(clockid_t clk_id 、 const struct timespec *tp);
编译连接时采用-lrt才能编译通过。
clk_id可选参数:
CLOCK_REALTIME
系统全局的实时时钟.设置此时钟需要合适的权限.
CLOCK_MONOTONIC
只能被读取,无法被设置,表示 monotonic 时间起点.
CLOCK_PROCESS_CPUTIME_ID
从 cpu 每进程的高分辨率计时器.
CLOCK_THREAD_CPUTIME_ID
线程的特定 cpu 时间时钟.
系统启动时,会首先从rtc中读取rtc时间,并设置给xtime,而当ntp对系统时间进行更新时,首先设置xtime,然后调用hwclock设置到rtc硬件中。xtime根据需要的精度,可以通过上面几个接口来选择使用。