6.10 时间和日期例程
UNIX内核提供的基本时间服务是计算处国际标准时间公元1970年1月1日00:00:00以来经过的秒数,它是用数据类型time_t表示的,我们称其为日历时间:包括日期和时间。Unix在这方面与其它操作系统的区别是(a)以国际标准时而非本地时间计时,(b)可自动进行转换,例如变换到夏日制,(c)将时间和日期作为一个量值保存。
time函数可以返回当前时间和日期:
#include <time.h>
time_t time(time_t *calptr);
与time函数相比,gettimeofday提供了更高的分辨率(最高为微秒级):
#include <sys/time.h>
int gettimeofday(struct timeval *restrict tp, void *restrict tzp);
其中,结构timeval定义如下:
struct timeval{
time_t tv_sec;
long tv_usec; /*microseconds*/
};
一旦获得这种以秒计的整型时间值后,通常要调用另一个时间函数将其转换为人们可读的时间和日期,下图说明了各个函数之间的关系:(下述函数中localtime、mktime、ctime和strftime都收到环境变量TZ的影响)
两个函数localtime和gmtime将日历时间转换成以年、月、日、时、分、秒、周日表示的时间,并将这些存放在一个tm结构,tm定义如下(注意每个成员的范围):
struct tm{ /*a broken-down time*/
int tm_sec; //seconds after the minute:[0-60]
int tm_min; //minutes after the hour:[0-59]
int tm_hour; /*hours after midnight:[0-23]*/
int tm_mday; /*day of the month[1-31]*/
int tm_mon; /*months since January[0-11]*/
int tm_year; /*years since 1900*/
int tm_wday; /*days since Sunday:[0-6]*/
int tm_yday; /*days since January 1:[0-365]*/
int tm_isdst; /*datlight saving time flag:<0,0,>0*/
};
秒可以超过59的理由是可以表示润秒。注意,除了月日字段,其它字段的值都以0开始。如果夏日制生效,则夏日制标志值为正,如果已非夏日制时间则为零,如果此信息不可用,则为负。
#include <time.h>
struct tm *gmtime(const time*_t calptr) ;
struct tm *localtime(const time_t calptr*) ;
两个函数返回:指向t m结构的指针
localtime和gmtime之间的区别是:localtime将日历时间变换成本地时间(考虑到本地时区和夏日制标志),而gmtime则将日历时间变换成国际标准时的年、月、日、时、分、秒、周日。
函数mktime以本地时间的年、月、日等作为参数,将其变换成time_t值。
#include <time.h>
time_t mktime(struct tm *tmptr);//返回:若成功为日历时间,出错为-1
asctime和ctime函数产生下列形式的26字节字符串,这与date(1)命令的系统默认输出形式类似:
Tue Jan 14 17:49:03 1992\n\0
#include <time.h>
char *asctime(const struct *tm tmptr) ;
char *ctime(const time_t *calptr) ;
两个函数返回:指向n u l l结尾的字符串
asctime的参数是指向年、月、日等字符串的指针,而ctime的参数则是指向日历时间的指针。
最后一个时间函数是strftime,它是非常复杂的printf类的时间值函数。
#include <time.h>
size_t strftime(char *buf,size_t maxsize,const char *format,const struct tm *tmptr);
// 返回:若有空间为存入数组的字符数,否则为0
最后一个参数是要格式化的时间值,说明为指向一个年、月、日、时、分、秒、周日时间值的指针。格式化结果存放在一个长度为maxsize个字符的buf数组中,如果buf长度是以存放格式化结果及一个null络止符,则该函数返回在buf中存放的字符数(不包括null终止符)。否则该函数返回0。
format参数控制时间值的格式。如同printf函数一样,变换说明的形式是百分号之后跟一个特定字符。在format中的其它字符则按原择输出。两个连续的百分号在输出中产生一个百分号。与printf函数的不同之处是,每个变换说明产生一个定长输出字符串,在format字符串中没有宽字段修饰符,表中列出了37种ISO C规定的变换说明。
格式 |
说明 |
实例 |
%a |
缩写的星期名 |
Thu |
%A |
全星期名 |
Thursday |
%b |
缩写的月名 |
Aug |
%B |
全月名 |
August |
%c |
日期和时间 |
Thu Aug 23 14:55:02 2001 |
%C |
年/100 [00,99] |
20 |
%d |
十进制表示的每月的第几天 [01,31] |
16 |
%D |
月/天/年 [MM/DD/YY] |
06/16/12 |
%e |
十进制表示的每月的第几天 ,一位数前加空格[1,31] |
10 |
%F |
年-月-日 [YYYY-MM-DD] |
2012-06-16 |
%g |
ISO 8601使用基于周的年的后两位数字 |
12 |
%G |
ISO 8601使用基于周的年 |
2012 |
%h |
简写的月份名 ,与%b相同 |
Aug |
%H |
24小时制的小时 [00,23] |
14 |
%I |
12小时制的小时 [01,12] |
02 |
%j |
每年的第几天 [001,366] |
235 |
%m |
十进制的月 [01,12] |
08 |
%M |
分钟 [00,59] |
55 |
%n |
换行符 |
|
%p |
AM/PM |
PM |
%r |
本地时间:(12时制) |
11:01:23 AM |
%R |
与“%H:%M”相同 |
11:01 |
%S |
秒 [00,60] |
02 |
%t |
水平制表符 |
|
%T |
与“%H:%M:%S”相同 |
11:01:23 |
%u |
ISO 8601的星期,星期一为1,[1,7] |
2 |
%U |
周数 ,以周日为一周开始 [00,53] |
33 |
%V |
ISO 8601周数 [01,53] |
07 |
%w |
星期,星期天为0. [0,6] |
4 |
%W |
周数,以星期一为一周开始 [00,53] |
34 |
%x |
标准日期 |
06/16/12 |
%X |
标准时间 |
14:55:02 |
%y |
年份的后两位数字 [00,99] |
12 |
%Y |
年 |
2012 |
%z |
ISO 8601格式的UTC偏移量 |
-0500 |
%Z |
时区名 |
EST |
%% |
百分号 |
% |
图中的大多数格式说明的意义是很明显的。需要略作解释的是%U和%W。%U是相应日期在该年中所属周数,包含该年中第一个星期日的周是第一周。%W也是相应日期在该年中所属的周数,不同的是包含第一个星期一的周为第一周。而%V说明符则与上述两者有较大区别。若某周包含了1月1日,而且至少包含了其后的另外3天,那么改周是一年中的第一周,否则改周被认为是上一年的最后一周。在这两种情况下,周一都被视为每周的第一天。