http://www.reader8.cn/jiaocheng/20120910/1995886.html

2012

Linux下系统时间函数、DST等相关问题总结1. 内核中时间的基本类型:在Linux内核中,常见的时间类型有以下两种

Linux下系统时间函数、DST等相关问题总结

1. 内核中时间的基本类型:

在Linux内核中,常见的时间类型有以下两种:系统时间(system time)和实时时间(real time),其实,方便理解,可以将二者分别认为是相对时间和绝对时间,同时它们分别对应于内核中的两个全局变量值:jiffies和xtime。

xtime: xtime值是从cmos电路中取得的时间,一般是从某个历史时刻(1970年1月1日0时0分)开始到现在的时间,其实也就是我们操作系统上面所显示的时间,它的精度是微秒。

jiffies:jiffies是记录从电脑开机到现在总共的时钟中断次数(拍数),它的值取决于系统的频率,单位是HZ,其倒数即表示一秒钟中断所产生的次数,在Linux 2.5内核版本之后将HZ从100提高到1000MHZ,它的精度也就是10毫秒。

根据对上面两个全局变量值的介绍,大提升应该了解到Linux系统中系统时间与实时时间之间的区别,前者表示的是从电脑开机到现在的时间,可以通过全局变量jiffies值换算而来;而实时时间则是指我们日常生活中的日期时间,它跟UTC有着密切关系,这些将在后面章节做介绍。

2. Linux time API中常见的时间结构:

(1)time_t:它是一个长整型数据,用来表示从1970年之后到现在的秒数。一般通过time函数获取。

(2)timeval结构:通过gettimeofday函数获取。

struct timeval

{

long tv_sec; /* seconds */

long tv_usec; /* microseconds */

};

(3)timezone结构:通过gettimeofday函数获取。

struct timezone

{

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

int tz_dsttime; /*DST types*/

};

【引申】常见的DST类型如下:

#define   DST_NONE      0    /* not on dst */

#define   DST_USA        1    /* USA style dst */

#define   DST_AUST       2   /* Australian style dst */

#define   DST_WET        3    /* Western European dst */

#define   DST_MET        4    /* Middle European dst */

#define   DST_EET         5    /* Eastern European dst */

#define   DST_CAN        6    /* Canada */

(4)timespec结构:通过clock_gettime函数获取。

struct timespec {

time_t tv_sec;         /* seconds */

long   tv_nsec;        /* nanoseconds */

};

(5)tm结构:通常由gmtime, localtime, mktime等函数返回。

struct tm {

/*

* the number of seconds after the minute,normally in the range

* 0 to 59, but can be up to 60 to allow forleap seconds

*/

int tm_sec;

/* the number of minutes after the hour, in the range 0 to 59*/

int tm_min;

/* the number of hours past midnight, in the range 0 to 23 */

int tm_hour;

/* the day of the month, in the range 1 to 31*/

int tm_mday;

/* the number of months since January, in the range 0 to 11 */

int tm_mon;

/*thenumber of years since 1900 */

long tm_year;

/* the number of days since Sunday, in the range 0 to 6 */

int tm_wday;

/* the number of days since January 1, in the range 0 to 365 */

int tm_yday;

};

3. 常见的时间系统函数:

(1) time:   #include

time_ttime(time_t *t)

若函数的参数为NULL,则返回从1970年1月1日0时0分0秒到现在(系统时间)所经过的秒;若参数非空,则将返回的值存在由指针t所指代的内存中。

(2) gettimeofday: #include

int gettimeofday(structtimeval *tv ,struct timezone *tz )

此函数可以获取两方面的时间信息,一个是可以获取到从1970年1月1日0时0分0秒到现在(系统时间)所经过的微秒,精度相比time函数精度有所提升;另外还可以获取到系统的时区信息。

【说明】

◆     gettimeofday函数成功返回0;否则返回-1,错误存储在errno中。

◆     tz_minuteswest值的确定问题:它表示的是与GTM之间相差的分钟数,其值应该为GMT(GMT +0)减去本地

时区对应的时间所得到的值,以EDT(GMT -4)为例,其值为240分钟。

◆     在实际开发中,gettimeofday中的tz参数实际很少使用,因为各种原因,一直未能实现(所获取出来的值恒为

0),因此,通常将此处直接写成NULL。

◆     对于gettimeofday函数的效率以及内部实现(系统调用实现),可参考

http://blog.csdn.net/russell_tao/article/details/7185588中的阐述。

◆     与gettimeofday函数相对应的是settimeofday,它可以设置实时时间RTC。但之前必须要具有root权限。

(3) gmtime,localtime and mktime:

struct tm*gmtime(const time_t *timep)

struct tm *localtime(const time_t *timep)

time_tmktime(struct tm*tm)

以上三个函数实现了time_t与tm结构的互换。前两者将time_t结构转换成tm结构,mktime则正好相反。

【说明】gmtime与localtime之间的区别:

二者均可以将time_t结构的时间值转化成真实世界所使用的日期时间表示方法(tm结构),但是,前者返回的时间值未作时区的转换,即返回的是UTC时间;而localtime函数则返回的经过了时区转换的时间值,所获取到的值才是本地的真实时间。例如,在Linux系统中运行date命令,它显示的是经过时区转换之后的时间值(通过localtime获取),而若运行“date-u”则能显示未经过时区转换的UTC时间(通过gmtime获取)。

(3) strftime:  #include

size_tstrftime (char *s,sizetsize, const char *format,const struct tm *brokentime)

此函数的功能是将由brokentime指针所指的时间按照format指针所指的格式输出到由s指针所指向的存储空间中,其中size是指存储空间的最大值。若返回0,则表明出现错误,所写进存储空间的结果是未定义的,若为真,则返回的是写进存储空间的字符数。

(4) clock_gettime: #include

intclock_gettime(clockid_tclk_id,struct timespec *tp);

此函数的功能是用来获取不同类型计时时钟的时间,其类型由clockid_t指定,常见的有:

CLOCK_REALTIME(与实时时间对应)

CLOCK_MONOTONIC(与系统时间对应)

【说明】

◆     clock_gettime函数能将所获得的时间值精确到纳秒级别;

◆     函数运行成功则返回0,否则返回-1,并将错误存在errno中;

◆     除上面的两个时钟类型之外,还有以下两种类型:

CLOCK_PROCESS_CPUTIME_ID和CLOCK_THREAD_CPUTIME_ID

但是这两种时钟类型一般出现在多处理机系统(SMP)中,值得注意的是,在老版本的Linux系统中可能会出现CPU时间之间不一致的现象,这是因为不同的CPU之间没有保证时间一致性措施,导致CPU时间之间出现偏移量,在2.6.18版本之后解决了这方面的问题,使得系统启动后不同的CPU之间具有相同的时间基准点。

◆CLOCK_REALTIME时间可以通过settime或者settimeofday函数进行修改,或者通过NTP周期性 地纠正,此时需要用到adjtimex函数;CLOCK_MONOTONIC时间则不能通过settime或者settimeofday函数进行修改,但是同样可以通过NTP进行调整,此时同样需要用到adjtimex函数。

◆对比两种时钟类型,若要在实际开发中要统计某个事件的时间,则最好是使用CLOCK_MONOTONIC,因为CLOCK_REALTIME被影响的因素太多,如手动修改,时区变化等等。

4. DST以及相关的系统函数:

(1)UTC、GMT与DST

目前世界上常见的计时方式主要有:太阳时(MT)和原子时。GMT(格林尼治时间)的正午是指当太阳横穿格林尼治子午线时的时间,由于地球的自转呈现不规则性,并且正在缓慢减速,因此格林威治时间目前已经不再作为标准时间使用,取而代之的是协调时间时(UTC),它是由原子钟提供,它是基于标准的GMT提供的准确时间,若在不需要精确到秒的前提下,通常也将GMT与UTC视作等同。

DST(daylight saving time)也称为夏令时,它是以节约能源为目的而人为规定的一种制度,它规定某段时间作为夏令时间,并在标准时间的基础上提前多长时间(通常是一个小时),同时DST还规定了规定生效的起始时间和末尾时间,详细规则会在tzset函数中介绍,值得注意的是目前只是部分国家实施了夏令时制度。

标准时间是相对于UTC/GMT时间而言的,它在UTC/GMT之上增加了时区信息,比如中国标准时间是GMT+8,即在UTC时间上增加8个小时。

(2) 系统时间、标准时间以及UTC时间之间的关系:

这节主要探讨在具体项目实现过程中,如何处理系统时间、标准时间以及UTC时间之间的关系,其中系统时间可以通过前面的系统函数获取到,它可能正处于夏令时间区域,下面这个图可以清晰地阐述三者之间的关系:

我们以localtime函数获取到本地系统时间为例,演示如何将其转换成UTC时间,前面已经说过,localtime所获取到的时间已经包含了时区信息,但是之前我们必须要确认目前的这个时间是否处于夏令时区域之内,若是,则还需要经过A阶段(去掉DST偏移量,通常是一个小时),若不是,只需要经历第二个阶段B,即去时区,最后转化成UTC,当然这两个阶段并没有严格的先后顺序。反过来,在具体实现中,还经常出现将UTC时间转化成本地时间的情况,比如NTP就是基于这样的原理,它从NTP server端获取统一的UTC时间,然后需要经过C(加时区)和D(加DST,如果存在或正好处于夏令时区域范围之内的话)两个阶段将其转化成本地系统时间。

下面主要阐述第一种情况(本地系统时间——>UTC)是如何具体实现的。当然前提是我们要知道目前所在的时区,这是一切的根本。在此之前,值得说明的是,一般来讲,时区是一个固定的信息,难以想象一个国家或地区去改变时区所带来的后果,但是DST因为是人为规定的,因此可能存在着修改的情况,基于这个事实,在具体实现中,时区信息可以存储在本地,而DST信息既可以静态存储在本地,也可以通过相关的server动态获取到。我们以静态存储的方式为例来讲解具体是如何实现去时区,去DST。

下面这个结构体存储了跟时区相关的位移量(offset)以及是否存在DST等信息,根据所在的时区信息,很容易找到系统时间与UTC时间之间的时区偏移,另外根据rule是否为-1来确定此时区是否实施了夏令时,若为-1,表明这个时区地已经实现了夏令时,则还需要经过去DST阶段,否则只需要经过去时区就可以得到UTC时间。

struct zone zones[N_ZONES] = {

/* offset rules */

{ -43200, -1 }, /* (GMT-12:00)International Date Line West */

{ -39600, -1 }, /* (GMT-11:00) Midway Island,Samoa */

{ -36000, -1 }, /* (GMT-10:00) Hawaii */

{ -32400,  0 }, /* (GMT-09:00) Alaska */

{ -28800,  0 }, /* (GMT-08:00) Pacific Time, Tijuana */

{ -25200, -1 }, /* (GMT-07:00) Arizona, Mazatlan*/

{ -25200, 13 }, /* (GMT-07:00) Chihuahua, La Paz*/

{ -25200,  0 }, /* (GMT-07:00) Mountain Time */

{ -21600,  0 }, /* (GMT-06:00) Central America */

{ -21600,  0 }, /* (GMT-06:00) Central Time */

{ -21600, 13 }, /* (GMT-06:00) Guadalajara, MexicoCity, Monterrey*/

{ -21600, -1 }, /* (GMT-06:00) Saskatchewan */

{ -18000, -1 }, /* (GMT-05:00) Bogota, Lima, Quito */

{ -18000,  0 }, /* (GMT-05:00) Eastern Time */

{ -18000, -1 }, /* (GMT-05:00) Indiana */

{ -14400,  0 }, /* (GMT-04:00) Atlantic Time */

{-14400, -1 }, /* (GMT-04:00) Caracas, La Paz */

{ -14400,  2 }, /* (GMT-04:00) Santiago */

{ -12600,  0 }, /* (GMT-03:30) Newfoundland */

{ -10800, 14 }, /* (GMT-03:00) Brasilia */

{ -10800, -1 }, /* (GMT-03:00) Buenos Aires, Georgetown*/

{ -10800, -1 }, /* (GMT-03:00) Greenland */

{ -7200, -1 }, /* (GMT-02:00) Mid-Atlantic */

{ -3600,  1 }, /* (GMT-01:00) Azores */

{ -3600, -1 }, /* (GMT-01:00) Cape Verde Is. */

{     0, -1 }, /* (GMT) Casablanca, Monrovia */

{     0,  1 }, /* (GMT) Greenwich MeanTime: Dublin, Edinburgh,Lisbon, London*/

{  3600,  1 }, /* (GMT+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna

{  3600,  1 }, /* (GMT+01:00) Belgrade, Bratislava, Budapest, Ljubljana, Prague */

{  3600,  1 }, /* (GMT+01:00) Brussels, Copenhagen, Madrid, Paris*/

{  3600,  1 }, /* (GMT+01:00) Sarajevo, Skopje, Warsaw, Zagreb*/

{  3600, -1 }, /* (GMT+01:00) West Central Africa*/

{  7200,  1 }, /* (GMT+02:00) Athens, Istanbul, Minsk */

{  7200,  1 }, /* (GMT+02:00) Bucharest */

{  7200,  4 }, /* (GMT+02:00) Cairo */

{  7200, -1 }, /* (GMT+02:00) Harare, Pretoria */

{  7200,  1 }, /* (GMT+02:00) Helsinki, Kyiv, Riga, Sofia, Tallinn, Vilnius */

{  7200,  5 }, /* (GMT+02:00) Jerusalem */

{ 10800,  6 }, /* (GMT+03:00) Baghdad */

{ 10800, -1 }, /* (GMT+03:00) Kuwait,Riyadh */

{ 10800,  7 }, /* (GMT+03:00) Moscow, St. Petersburg, Volgograd */

{ 10800, -1 }, /* (GMT+03:00) Nairobi*/

{ 12600,  8 }, /* (GMT+03:30) Tehran */

{ 14400, -1 }, /* (GMT+04:00) Abu Dhabi, Muscat */

{ 14400,  9 }, /* (GMT+04:00) Baku, Tbilisi, Yerevan */

{ 16200, -1 }, /* (GMT+04:30) Kabul*/

{ 18000,  7 }, /* (GMT+05:00)Ekaterinburg */

{ 18000, -1 }, /* (GMT+05:00) Islamabad, Karachi, Tashkent*/

{ 19800, -1 }, /* (GMT+05:30) Chennai, Kolkata, Mumbai, New Delhi */

{ 20700, -1 }, /* (GMT+05:45) Kathmandu*/

{ 21600, 12 }, /* (GMT+06:00) Almaty, Novosibirsk */

{ 21600, -1 }, /* (GMT+06:00) Astana, Dhaka*/

{ 21600, -1 }, /* (GMT+06:00) Sri Jayawardenepura */

{  23400, -1 }, /* (GMT+06:30) Rangoon */

{ 25200, -1 }, /* (GMT+07:00) Bangkok, Hanoi, Jakarta*/

{ 25200,  7 }, /* (GMT+07:00) Krasnoyarsk */

{ 28800, -1 }, /* (GMT+08:00) Beijing,Chongquing, Hong Kong, Urumqi*/

{ 28800, -1 }, /* (GMT+08:00) Irkutsk,Ulaan Bataar */

{ 28800, -1 }, /* (GMT+08:00) Kuala Lumpur, Singapore*/

{ 28800, -1 }, /* (GMT+08:00) Perth*/

{ 28800, -1 }, /* (GMT+08:00) Taipei*/

{ 32400, -1 }, /* (GMT+09:00) Osaka, Sapporo, Tokyo*/

{ 32400, -1 }, /* (GMT+09:00) Seoul*/

{ 32400,  7 }, /* (GMT+09:00) Yakutsk */

{ 34200,  3 }, /* (GMT+09:30) Adelaide */

{ 34200, -1 }, /* (GMT+09:30) Darwin*/

{ 36000, -1 }, /* (GMT+10:00) Brisbane*/

{ 36000,  3 }, /* (GMT+10:00) Canberra, Melbourne, Sydney*/

{ 36000, -1 }, /* (GMT+10:00) Guam, Port Moresby */

{ 36000, 10 }, /* (GMT+10:00) Hobart*/

{ 36000,  7 }, /* (GMT+10:00) Vladivostok */

{ 39600, -1 }, /* (GMT+11:00) Magadan */

{ 39600,  7 }, /* (GMT+11:00)Solomon Is., New Caledonia*/

{ 43200, 11 }, /* (GMT+12:00) Auckland, Wellington */

{ 43200, -1 }, /* (GMT+12:00) Fiji,Kamchatka, Marshall Is. */

{ 43200, -1 }, /* (GMT+12:00) NZ */

};

那么又如何去掉DST,即找到系统时间与标准时间之间的DST偏移量呢?在此之前需要了解到DST的规则问题,如规则格式、规则数据等等。

DST规则规定了实施夏令时的起始时间以及结束时间,如澳大利亚的是:从4月的第一个星期天的凌晨3点到10月的第一个星期天的凌晨2点,全世界DST可参考www.worldtimezone.com/daylight.html。下面主要阐述如何判断目前的时间是否包含有夏令时。

rpytime(rule1,year) < (gm_time + zone->z_gmtoff))< rpytime(rule2,year)

上面的式子中gm_time是本地系统时间(注意是通过localtime获取,没有加入时区,单位为秒),z_gmtoff是指制定时区的偏移量,这样式子中间代表就是标准时间;式子中rule1,rule2分别对应于DST规则中的两个界点,并利用rpytime函数计算出从1970年以来的时间总长(以秒为单位),若上面的式子成立,表明存在DST,那是因为DST使得在标准时间之上提前了1小时。

linux内核时间函数us,Linux上系统时间函数、DST等相关有关问题总结相关推荐

  1. 解析Linux内核的基本的模块管理与时间管理操作---超时处理【转】

    转自:http://www.jb51.net/article/79960.htm 这篇文章主要介绍了Linux内核的基本的模块管理与时间管理操作,包括模块加载卸载函数的使用和定时器的用法等知识,需要的 ...

  2. linux 内核 死锁 检查,一种linux内核自旋锁死锁检测报告系统和方法与流程

    本发明涉及内核死锁检测领域,具体的说是一种linux内核自旋锁死锁检测报告系统和方法. 背景技术: linux内核死锁是长期困扰内核开发人员的问题之一,但自内核引入lockdep调试模块之后,内核死锁 ...

  3. linux ntp时间立即同步命令_Linux系统时间同步方法小结

    在Windwos中,系统时间的设置很简单,界面操作,通俗易懂,而且设置后,重启,关机都没关系.系统时间会自动保存在BIOS时钟里面,启动计算机的时候,系统会自动在BIOS里面取硬件时间,以保证时间的不 ...

  4. linux 如何在命令行下改系统时间

    我们一般使用"date -s"命令来修改系统时间.比如将系统时间设定成2009年6月1日的命令如下.       #date -s 06/01/2009       或 #date ...

  5. linux内核启动分析 三,Linux内核分析 实验三:跟踪分析Linux内核的启动过程

    贺邦 + 原创作品转载请注明出处 + <Linux内核分析>MOOC课程 http://mooc.study.163.com/course/USTC-1000029000 一. 实验过程 ...

  6. Linux内核开发_1_编译LInux内核

    目录 1. 准备工作 1.1 学习环境 1.2 下载Linux内核源码 1.3 解压Linux内核 1.4 目录结构介绍 2. Linux内核配置 2.1 配置选项 1. make config 2. ...

  7. linux内核功能有,好消息!LINUX内核2.6.18终于支持实时功能了

    LINUX内核2.6.18终于支持实时功能了,这是个好消息.当LINUX实时功能加强后,它在嵌入式系统的应用就会更广泛了.在这一版发布前,为了使嵌入式系统的LINUX具有实时特性,需要给标准和LINU ...

  8. linux内核学习之三:linux中的32位与64位

    linux内核学习之三:linux中的"32位"与"64位" 在通用PC领域,不论是windows还是linux界,我们都会经常听到"32位" ...

  9. linux内核开发基础(linux内核源码、树莓派源码编译、SD卡挂载)

    首先下载树莓派linux内核源码: 下载网址:https://github.com/raspberrypi/linux 在树莓派使用指令:uname -r查看当前树莓派的版本号,然后选择对应的linu ...

最新文章

  1. vue中router使用keep-alive缓存页面的注意事项
  2. makefile常用讲解(2)
  3. python text insert()背景色_50行python代码写个计算器教程
  4. 道哥:我人生的两大选择,为的都是同一件事
  5. 并查集(许多东西的基本哦)
  6. SecureCRT 查询ORCLE NUMBER字段显示问题
  7. logistic模型 matlab,logistic模型MATLAB代码
  8. 日常问题:上传接口报错
  9. 此文对你人生会有莫大好处的,建议永久保存
  10. iOS 依赖注入:Objection 和 Typhoon
  11. Awesome Crowd Counting
  12. 程序员晒出从毕业到工作5年照片,抱怨头发掉光了,网友:很真实
  13. vba excel 开发游戏_自动化神器—VBA
  14. TP6基础知识【新框架】
  15. Xshell vim使用右侧数字键盘时数字变成英文字母的解决办法
  16. TI-RTOS学习笔记(三)—— 驱动程序框架
  17. linux 查看网卡连接网线,查看网卡是否连接网线
  18. Linux课堂笔记--第九天
  19. [原创]-[UiPath] UiPath中关于日期的操作
  20. CocoaChina12月源码精选

热门文章

  1. python学习笔记(十七) Tkinter鼠标事件、树状层级目录和一些补充
  2. grafana添加被监控主机
  3. 如何处理投递的邮件被趋势RBL拦截的问题
  4. 哪个网站云服务器最便宜,哪家云服务器比较便宜
  5. 在线画图工具https://www.draw.io/
  6. 浅谈 IOC 什么是 IOC?
  7. dma总线全称_DMA原理介绍
  8. Android AOSP 6.0.1 registerReceiver广播注册流程分析
  9. mysql:ERROR 1366 (HY000): Incorrect string value: ‘\x80\xE6\x96\xB0‘ for column ‘name‘ at row 1
  10. 律师状告百度竞价排名注水 百度首度回应