Linux C 系统编程(05) 时间与日历编程

linux/Unix下的时间分为两种:

  1. 系统时间:一般是一个长整型数据,单位是秒。
  2. 日历时间:更贴近于人们熟悉的时间表示法,通过一个结构体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中均没有定义,所以不具有可移植性,使用较少。
发布了289 篇原创文章 · 获赞 47 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/vviccc/article/details/105149178
今日推荐