该系列文章总纲链接:专题分纲目录 LinuxC 系统编程
本章节思维导图如下所示(思维导图会持续迭代):
第一层:
第二层:
linux/Unix下的时间分为两种:
- 系统时间:一般是一个长整型数据,单位是秒。
- 日历时间:更贴近于人们熟悉的时间表示法,通过一个结构体tm来更贴切地标明时间的年、月、日、时、分、秒、星期。实际上就是一种结构的转换而已。
1 系统时间
在linux/Unix系统中,采用的是全球时间协调计时法,描述的是自1970年1约1日以来所经过的秒数,这个值的数据类型是time_t,一个长整型数据。
1.1 time函数
在linux下,使用time函数为进程提供当前的时间。time函数的定义如下:
#include <time.h>
time_t time(time_t *t);
参数t:一个指向time_t类型的指针,当此值为NULL的时候函数将从纪元至今的时间写入t中。
函数执行成功,返回值是从纪元至今的时间(秒数);失败返回-1。
若time函数在精度上不能满足用户的需求,在linux/Unix系统上还可以使用gettimeofday()函数来获取更高精度的数据。
1.2 gettimeofday函数及其相关知识
1.2.1 gettiemofday函数
在linux下,使用gettimeofday函数来获取更高精度的时间。gettimeofday函数的定义如下:
#include <sys/time.h>
int gettimeofday(struct timeval *tv, struct timezone *tz);
int settimeofday(const struct timeval *tv, const struct timezone *tz);
参数tv:一个指向timeval结构体的指针,函数执行成功后存放当前的系统时间值,这是一个值结果参数。
参数tz:一个指向timezone结构体的指针,此参数与时区有关,函数执行成功后存放当地时区的信息,但是一般不用的时候置为NULL。这是一个值结果参数。
注意:tz参数的作用需要系统支持,在某些系统中会产生错误的值,所以在调用的时候需要仔细查看手册。
函数执行成功或失败均返回0。
1.2.2 结构体timeval和timezone的说明
结构体timeval与结构体timezone的定义如下:
struct timeval{
time_t tv_sec; //秒数
timez_t tv_usec; //微秒数
};
struct timezone{
int tz_minutewest; //格林威治向西的分钟数,即与greenwich 时间差了多少分钟
int tz_dsttime; //夏令时修正的类型
};
1.2.3 settimeofday函数的说明
对于settimeofday:把目前时间设成由tv所指的结构信息,当地时区信息则设成tz所指的结构。(注意,只有root权限才能使用此函数修改时间)。成功则返回0,失败返回-1,错误代码存于errno。errno的解释如下:
- EPERM 并非由root权限调用settimeofday(),权限不够。
- EINVAL 时区或某个数据是不正确的,无法正确设置时间。
如果tv或tz某一项为NULL,表示对相关的信息不感兴趣。
1.2.4 timeval结构体类型值的运算
5个宏定义如下:
timerisset(tvp):设置tvp的sec属性和usec属性。
timerclear(tvp):tvp的sec属性和usec属性置为0。
timercmp(a,b,CMP):比较a,b的值。CMP的取值有>、<、=;比较正确则返回0,错误返回非0值。
timeradd(a,b,result):分别取a,b的sec属性和usec属性,对其进行+操作,结果放在result中。
timersub(a,b,result):分别取a,b的sec属性和usec属性,对其进行-操作,结果放在result中。
函数difftime用于计算两个time_t类型的时间值之间的秒数差。difftime函数的定义如下:
#include <time.h>
double difftime(time_t time1, time_t time2);
函数中参数表示time_t类型的时间值,返回值为一个浮点数,表示2个时间值之间的秒数差。
2 日历时间
2.1 tm结构体简介
linux/Unix下定义了系统日历时间结构体struct tm,详细信息如下:
struct tm
{
int tm_sec; /* Seconds. [0-60] (1 leap second) */
int tm_min; /* Minutes. [0-59] */
int tm_hour; /* Hours. [0-23] */
int tm_mday; /* Day. [1-31] */
int tm_mon; /* Month. [0-11] */
int tm_year; /* Year - 1900. */
int tm_wday; /* Day of week. [0-6] */
int tm_yday; /* Days in year.[0-365] */
int tm_isdst; /* DST. [-1/0/1]*/
#ifdef __USE_BSD
long int tm_gmtoff; /* Seconds east of UTC. */
__const char *tm_zone; /* Timezone abbreviation. */
#else
long int __tm_gmtoff; /* Seconds east of UTC. */
__const char *__tm_zone; /* Timezone abbreviation. */
#endif
};
注意:tm结构体中前面9个成员是必需的,对于后面2个成员,根据系统的不同会有区别。
- 成员tm_gmtoff/__tm_gmtoff表示的是日期变更线东面时区中的UTC东部时区的正秒数/UTC西部时区的负秒数。
- 成员tm_zone/__tm_zone表示的是当前时区的名字(与环境变量TZ有关)。
2.2 其他系统时间函数与结构
2.2.1 timespec结构
与timeval结构体相比,精度要提高很多,该结构可以精确到十亿分之一秒。该结构体定义如下:
struct timespec{
long int tv_sec;
long int tv_usec;
};
但同时该结构也需要更大的空间来存储。
2.2.2 time.h文件中常见的时间类型转换函数:
#include <time.h>
@1 linux下用函数asctime来将tm结构体类型的时间转换成asc码:
char *asctime(const struct tm *tm);
char *asctime_r(const struct tm *tm, char *buf);
参数tm:指向要转换的tm结构的指针。
参数buf:用户缓冲区,一个副本的存储。
得到机器时间(日期时间转换为ASCII码);对于asctime_r函数,只是多了一个存储数据的buf,和返回值是一样的。
@2 linux下用函数ctime来将time_t结构体类型的时间转换成asc码:
char *ctime(const time_t *timep);
char *ctime_r(const time_t *timep, char *buf);
参数timep:指向要转换的time_t结构的指针
参数buf:用户缓冲区,一个副本的存储。
得到日历时间(日期时间转换为ASCII码) ;对于ctime_r函数,只是多了一个存储数据的buf,和返回值是一样的。
@3 linux下用函数gmtime来将time_t结构体类型的时间转换成tm类型的结构体,但是同localtime函数相比是有区别的:
struct tm *gmtime(const time_t *timep);
struct tm *gmtime_r(const time_t *timep, struct tm *result);
参数timep:指向要转换的time_t结构的指针。
参数result:用户缓冲区,一个返回值副本的存储。
函数的返回值是指向tm结构体指针,表示的是国际标准时间。对于gmtime_r函数,只是多了一个存储数据的buf,和返回值是一样的。
@4 linux下用函数localtime来将time_t结构体类型的时间转换成tm类型的结构体,但是同gmtime函数相比是有区别的:
struct tm *localtime(const time_t *timep);
struct tm *localtime_r(const time_t *timep, struct tm *result);
参数timep:指向要转换的time_t结构的指针。
参数result:用户缓冲区,一个返回值副本的存储。
函数的返回值是指向tm结构体指针,表示的是本地时间。对于localtime_r函数,只是多了一个存储数据的buf,和返回值是一样的。
@5 linux下使用mktime函数实现将tm结构体类型的变量转换成time_t的类型:
time_t mktime(struct tm *tm);
参数tm指向日历时间结构的指针。
函数执行成功返回相应的系统时间(受系统环境TZ(timezone)变量影响),失败返回-1。
2.2.3 strftime函数
strftime函数提供了对时间函数更加灵活的输出:strftime函数的原型如下:
#include <time.h>
size_t strftime(char *s, size_t max, const char *format,const struct tm *tm);
参数 buf:字符数组指针,存放函数的格式化输出结果。
参数 max:设定了该数组的长度。
参数format:时间值的格式字符。
%a 星期几的简写
%A 星期几的全称
%b 月份的简写,3字符形式缩写
%B 月份的全称
%c 标准的日期的时间串
%C 年份的后两位数字
%d 十进制表示的每月的第几天
%D 月/天/年
%e 在两字符域中,十进制表示的每月的第几天
%F 年-月-日
%g 年份的后两位数字,使用基于周的年
%G 年份,使用基于周的年
%h 简写的月份名
%H 24小时制的小时
%I 12小时制的小时
%j 十进制表示的每年的第几天
%m 十进制表示的月份
%M 十时制表示的分钟数
%n 新行符
%p 本地的AM或PM的等价显示
%r 12小时的时间
%R 显示小时和分钟:hh:mm
%S 十进制的秒数
%t 水平制表符
%T 显示时分秒:hh:mm:ss
%u 每周的第几天,星期一为第一天 (值从0到6,星期一为0)
%U 第年的第几周,把星期日作为第一天(值从0到53)
%V 每年的第几周,使用基于周的年
%w 十进制表示的星期几(值从0到6,星期天为0)
%W 每年的第几周,把星期一做为第一天(值从0到53)
%x 标准的日期串
%X 标准的时间串
%y 不带世纪的十进制年份(值从0到99)
%Y 带世纪部分的十制年份
%z,%Z 时区名称,如果不能得到时区名称则返回空字符。
%% 百分号
参数tm:要转换的时间结构体。
注意:对于strptime函数,在ANSI和POSIX中均没有定义,所以不具有可移植性,使用较少。