LINUX 时间和日期

时间和日期

通常能确定时间和日期对一个程序来说是非常有用的。程序可能希望记录它运行的时间,或者可能需要在某些时候改变它的运行方式。例如,一个游戏可能拒绝在工作时间运行,或者一个定时备份程序可能想等到每天的凌晨才开始一个自动备份。
所有的UNIX系统都使用同一个时间和日期的起点:格林尼治时间(GMT)1970年1月1日午夜(0点)。这是“UNIX纪元的起点”,Linux也不例外。Linux系统中所有的时间都以从那时起经过的秒数来衡量。这和MS-DOS处理时间的方法类似,只是MS-DOS纪元始于1980年。其他系统使用其他的纪元起始时间。
时间通过一个预定义的类型time_t来处理。这是一个大到能够容纳以秒计算的日期和时间的整数类型。在Linux系统中,它是一个长整型,与处理时间值的函数一起定义在头文件time.h中。
绝不要想当然地以为,时间就是32位的。在使用32位time_t类型的UNIX和Linux系统中,时间将在2038年回绕。那时,我们希望系统都开始使用大于32位的time_t类型。
你可以通过调用time函数得到底层的时间值,它返回的是从纪元开始至今的秒数。如果tloc不是一个空指针,time函数还会把返回值写入tloc指针指向的位置。
实验:time函数
下面这个简单的程序envtime.c演示了time函数的用法:
运行这个程序,它会在20秒时间内每两秒钟打印一次底层的时间值。
实验解析
这个程序用一个空指针参数调用time函数,返回以秒数计算的时间和日期。程序休眠两秒后再重复调用time函数,总共调用10次。
以从1970年开始计算的秒数来表示时间和日期,对测算某些事情持续的时间是很有用的。我们可以把它考虑为只是简单地把两次调用time得到的值相减就行了。然而ISO/ANSI C标准委员会经过深思熟虑,并没有规定用time_t类型来测量任意时间之间的秒数,他们发明了一个函数difftime,该函数用来计算两个time_t值之间的秒数并以double类型返回它。
difftime函数计算两个时间值之间的差,并将time1-time2的值作为浮点数返回。对Linux来说,time函数的返回值是秒数,可以对它进行处理,但考虑到最大限度的增加可移植性,则最好使用difftime。
为了提供(对人类)更有意义的时间和日期,我们需要把时间值转换为可读的时间和日期。有一些标准函数可以帮我们做到这一点。
gmtime函数把底层时间值分解为一个结构,该结构包含一些常用的字段。
tm结构定义为至少包含表4-2所示的成员。
表  4-2
tm成员
说    明
int tm_sec
秒,0~61
(续)
tm成员
说    明
int tm_min
分,0~59
int tm_hour
小时,0~23
int tm_mday
月份中的日期,1~31
int tm_mon
月份,0~11(一月份为0)
int tm_year
从1900年开始计算的年份
int tm_wday
星期几,0~6(周日为0)
int tm_yday
年份中的日期,0~365
int tm_isdst
是否夏令时
tm_sec的范围允许临时闰秒或双闰秒。
实验:gmtime函数
下面这个程序gmtime.c利用tm结构和gmtime函数打印出当前时间和日期:
运行这个程序,我们得到含义明显的时间和日期:
实验解析
程序调用time函数得到底层的时间值,然后调用gmtime将该值转换为一个包含更有用的时间和日期值的结构。程序用printf将这些信息打印出来。严格来说,不应该用这种方法打印原始时间值,因为我们并不能保证它在所有系统上都是long类型的值。我们在gmtime程序后立即运行date命令,以比较它们的输出。
不过,这儿有个小问题。如果你在格林尼治标准时间(GMT)之外的时区运行这个程序,或者如果你所在的地方采用了夏令时,你会发现时间(可能还有日期)是不对的。因为gmtime按GMT返回时间(现在GMT被称为世界标准时间,或UTC)。Linux和UNIX这样做是为了同步全球各地的所有程序和系统。不同时区同一时刻创建的文件就会有相同的创建时间。要看当地时间,我们需要使用localtime函数。
localtime函数和gmtime一样,除了它返回的结构中包含的值已根据当地时区和是否采用夏令时做了调整。如果你把上面程序中gmtime换成localtime再编译运行一次,你就会看到正确的时间和日期了。
要把已分解出来的tm结构再转换为原始的time_t时间值,可以使用mktime函数:
如果tm结构不能表示为time_t值,mktime将返回-1。
为了得到更“友好”的时间和日期表示,像date命令输出的那样,我们可以使用asctime函数和ctime函数:
asctime函数返回一个字符串,表示由tm结构timeptr所给出的时间和日期。这个返回的字符串有类似下面的格式:
它总是这种长度为26个字符的固定格式。ctime函数等效于调用
它以原始时间值为参数,并将它转换为可读的本地时间。
实验:ctime函数
我们用下面的代码来看看ctime函数的用法。
编译并运行这个ctime.c程序,输出如下:
实验解析
ctime.c程序调用time函数得到底层时间值,让ctime做所有的艰巨工作,把时间值转换成可读的字符串,然后打印它。
为了对时间和日期字符串的格式有更多控制,Linux和现代的类UNIX系统提供了strftime函数。它很像是一个针对时间和日期的sprintf函数,工作方式也很类似:
strftime函数格式化timeptr指针指向的tm结构所表示的时间和日期,并将结果放在字符串s中。字符串被指定(至少)maxsize个字符。format字符串用于控制写入字符串s的字符。与printf一样,它包含将被传给字符串的普通字符和用于格式化时间和日期元素的转换控制符。转换控制符见表4-3。
表  4-3
转换控制符
说    明
转换控制符
说    明
%a
星期几的缩写
%S
秒,00~61
%A
星期几的全称
%u
星期几,1~7(周一为1)
%b
月份的缩写
%U
一年中的第几周,01~53(周日是一周的第一天)
%B
月份的全称
%V
一年中的第几周,01~53(周一是一周的第一天)
%c
日期和时间
%w
星期几,0~6(周日为0)
%d
月份中的日期,01~31
%x
本地格式的日期
%H
小时,00~23
%X
本地格式的时间
%I
12进制的小时,01~12
%y
年份减去1900
%j
年份中的日期,001~366
%Y
年份
%m
年份中的月份,01~12
%Z
时区名
%M
分钟,00~59
%%
字符%
%p
a.m.(上午)或p.m(下午)
因此,date命令输出的普通日期就相当于strftime格式字符串中的:
为了帮助读取日期,我们可以使用strptime函数,该函数以一个代表日期和时间的字符串为参数,并创建表示同一日期和时间的tm结构:
format字符串的构建方式和strftime的format字符串完全一样。strptime在字符串扫描方面类似于sscanf函数,也是查找匹配数据字段,并把它们写入对应的变量中。只是这里是根据format字符串填充tm结构的成员。不过,strptime的转换控制符与strftime的相比,限制要稍微松一些,因为strptime中的星期几和月份用缩写和全称都行,两者都匹配strptime中的%a控制符,此外,strftime使用小于10的数字总以0开头,而strptime则把它看作是可选的。
strptime返回一个指针,指向转换过程处理的最后一个字符后面的那个字符。如果碰到不能转换的字符,转换过程就在该点停下来。调用程序需要检查是否已从传递的字符串中读入了足够多的内容,以确保tm结构中写入了有意义的值。
实验:strftime函数和strptime函数
请留意下面这个程序中选用的转换控制符:
编译并运行这个程序strftime.c,我们得到:
实验解析
strftime程序通过调用time和localtime得到当前的本地时间。然后,它通过调用带有合适的格式参数的strftime将时间转换成可读的格式。为演示strptime的用法,程序构建了一个包含日期和时间的字符串,然后调用strptime将原始时间和日期值分解并打印出来。转换控制符%R是strptime中对%H:%M的缩写形式。
注意:要成功地扫描日期,strptime需要一个精确的格式字符串。这一点非常重要。一般来说,该函数不会精确扫描读自用户的日期,除非用户输入的格式非常严格。
编译strftime.c时,你可能会看到编译器有一个警告信息。因为GNU库在默认情况下并未声明strptime函数。要解决这个问题,在包含time.h头文件的语句之前加上如下一行即可,它的作用是明确请求使用X/Open标准的功能:

========================================================================================

#include <stdio.h>
#include <time.h>

int main(int argc, char* arv[])
{
        time_t curTime;
        char buf[100];
        struct tm *tm_ptr;

        time(&curTime);
        tm_ptr = localtime(&curTime);
        strftime(buf, 100, "%Y-%m-%d %I:%M:%S", tm_ptr);

        printf("%s\n", buf);


        return 0;
}

================================================




阅读更多
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭