linux编程中与时间相关的问题总结

时间:2022-08-13 02:42:12

一、与时间相关的概念

  • GMT:Greenwich Mean Time,格林尼治平均时。格林尼治标准时间是19世纪中叶大英帝国的基准时间,同时也是事实上的世界基准时间。

  • UTC:Universal Time Coordinated,环球通用协调时间。基本上UTC的本质强调的是比GMT更为精确的世界时间标准,在不需要精确到秒的情况通常也将GMT和UTC视作等同

  • DST:Daylight Saving Time,指在夏天太阳升起的比较早时,将时钟拨快一小时以提早日光的使用;

  • CST:CST可以同时表示美国UT-6:00,澳大利亚UT+9:30,中国UT+8:00,古巴UT-4:00四个国家的标准时间;

  • Epoch:时间轴上特定的一个时间点,定义为从格林威治时间1970年01月01日00时00分00秒。记为1970年1月1日00:00:00 UTC

  • UNIX时间戳:英文表示为Unix timestamp、Unix time或者POSIX time。是从Epoch开始所经过的秒数,不考虑闰秒。在大多数的UNIX系统中UNIX时间戳存储为32位,这样会引发2038年问题或Y2038

  • Calendar Time:表示的意义同UNIX时间戳。

  • Broken-down Time:使用tm结构存储的时间,tm 数据结构将时间分别保存到代表年,月,日,时,分,秒等不同的变量中,不再是一个令人费解的64位整数。tm数据结构是各种自定义格式转换函数所需要的输入形式

  • Real-Time:也称wall-clock,即我们人类自然感受的时间。

  • Virtual-Time:进程执行所占用的cpu时间(即站在进程的角度看时间),如果在过去的一秒钟指定进程没有被调用,则virtual time为0s,real time为1s。

  • Prof-Time:系统在用户态和内核态所占用cpu时间的总和;

  • clock tick:时钟滴答,当PIT通道0的计数器减到0值时,它就在IRQ0上产生一次时钟中断,即一次时钟滴答。

  • jiffies:记录着从电脑开机到现在总共的”时钟中断”的次数。启动时内核将该变量初始化为0,此后每次时钟中断处理程序都会增加该变量的值。jiffies类型为无符号长整型(unsigned long),其他任何类型存放它都不正确。

  • xtime:从cmos电路或rtc芯片中取得的时间,一般是从某一历史时刻开始到现在的时间;

二、相关函数汇总

函数名 函数用途
time(…) 获取日历时间存储在time_t结构之中,分辨率为秒。
stime(…) 设置系统时间。
gettimeofday(…) 同time(…),但是分辨率达到微妙级别,一般用于计算程序运行所耗费的时间。
settimeofday(…) 同stime(…),只是设置更精确的时间更精确罢了。
clock_gettime(…) 同time(…),但是分辨率为纳秒级,还能根据时钟的类型获取不同的时间。
gmtime(…) 将time_t类型的UTC时间转换成struct tm类型的UTC时间。
localtime(…) 将time_t类型的本地时间转换成struct tm类型的本地时间。
mktime(…) 将struct tm类型值转换为time_t类型的值。
ctime(…) 将time_t类型的时间转换成固定格式的字符串形式,返回的字符串是静态分配的
asctime(…) 将struct tm格式的时间转化为固定格式的字符串形式,返回的字符串是静态分配的
strftime(…) 将tm格式的时间转化为字符串,显示格式可以自定义
sleep(…) 使程序睡眠seconds秒
usleep(…) 使程序睡眠usec微秒
difftime(…) 计算出两个日历时间差,大致实现为 #define difftime(t1,t0) (double)(t1 - t0)
alarm() 设置单次定时器,超时发送SIGALRM信号。
setitimer() 可以设置三种循环定时器,超时分别发送不同的信号。
getitimer() 对应setitimer的查询。

注:
time()和gettimeofday()调用比较占用系统资源,所以不如对时间精度要求不高的情况下,尽量减少调用次数;

三、经典配图回顾

刚开始学习linux的时候没看明白下面的时间转换图,现在再看看豁然开朗
linux编程中与时间相关的问题总结

四、相关数据结构

  • time_t:在Linux/Unix上定义为long int类型,在32位系统上,time_t最多只能记录2,147,483,647秒,也就是说到了2038年将会产生溢出,但在64位系统上不会出现此问题。
  • struct tm:为了更好的理解time_t表示的时间,于是产生了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 since 1900 */
int tm_wday; /* Day of the week (Sunday = 0)*/
int tm_yday; /* Day in the year (0-365; 1 Jan = 0)*/
int tm_isdst; /* Daylight saving time flag
> 0: DST is in effect;
= 0: DST is not effect;
< 0: DST information not available */
};
  • struct timeval:上面两个都是表示时间点,而这个结构体表示时间段。
struct timeval {
time_t tv_sec; /* seconds */
suseconds_t tv_usec; /* microseconds */
};
  • struct itimerval:设置间隔定时器时使用的结构体。
 struct itimerval { 
struct timeval it_interval; /* 从第二次开始以后的超时时间 */
struct timeval it_value; /* 第一次超时时间 */
};

五、linux环境下的时间戳转换

在LINUX系统中,有许多场合都使用时间戳的方式表示时间,即从1970年1月1日起至当前的天数或秒数。

  • 分别以标准格式和时间戳来显示当前时间
[root@365linux ~]# date
20100810日 星期二 03:39:21 CST
[root@365linux ~]# date +%s
1281382775
  • 显示指定时间的时间戳
[root@365linux ~]# date -d "2010-07-20 10:25:30" +%s
1279592730
  • 将时间戳转换为标准时间格式

方法1:使用date命令

[root@localhost tmp]#  date -d "@1279592730"
Tue Jul 20 10:25:30 CST 2010
[root@localhost tmp]# date -d "@1279592730" +"%Y%m%d %H:%M:%S"
20100720 10:25:30
[root@localhost tmp]# date -d "@1279592730" +"%F %H:%M:%S"
2010-07-20 10:25:30
[root@localhost tmp]# date -d "1970-01-01 utc 1279592730 seconds"
Tue Jul 20 10:25:30 CST 2010
[root@localhost tmp]# date -d "1970-01-01 utc 1279592730 seconds" +"%F %H:%M:%S"
2010-07-20 10:25:30

方法2:使用awk里的时间函数

[root@365linux ~]# echo "1279592730" |awk '{print strftime ("%F %T",$0)}'
2010-07-20 10:25:30

方法3:使用perl处理

[root@365linux ~]# perl -e 'print localtime(1279592730)."\n";'
Tue Jul 20 10:25:30 2010
  • 系统时区设置:
[root@365linux ~]# vim /etc/sysconfig/clock ZONE="Asia/Shanghai"
UTC=true
ARC=false
[root@365linux ~]# cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
  • oracle 中将unix/linux时间戳进行转换
    unix/linux时间戳转换为标准时间格式(主要是注意时区问题):
select TO_DATE('19700101','yyyymmdd') + 1235728935/86400 +TO_NUMBER(SUBSTR(TZ_OFFSET(sessiontimezone),1,3))/24 from dual 

其中1235728935就是unix/linux时间戳,转换完之后就表示为 2009-2-27 18:02:15。反过来也一样,还是要考虑时区:

select (to_date('2009-2-27 18:02:15','yyyy-mm-dd hh24:mi:ss') - to_date('1970-1-1','yyyy-mm-dd'))*86400- TO_NUMBER(SUBSTR(TZ_OFFSET(sessiontimezone),1,3))*3600 from dual

六、参考文档:

http://www.cnblogs.com/yaozhongxiao/archive/2013/04/14/3020353.html
http://www.ibm.com/developerworks/cn/linux/1307_liuming_linuxtime1/
http://www.ibm.com/developerworks/cn/linux/1308_liuming_linuxtime3/
http://blog.****.net/mcgrady_tracy/article/details/15501835

相关文章