Linux_C环境编程:时间日期函数总结

 一、时间日期类型

Linux下常用的时间类型有6个:time_t, clock_t, struct timeb, struct timeval, struct timespec, struct tm

1.1  time_t 类型

time_t 是一个长整型,一般用来表示从1970年1月1日0时0分0秒以来的秒数。

该类型定义在 #include <sys/time.h> 头文件中。

一般通过 time_t time = time(NULL); 获取。

1.2  clock_t 类型

clock_t 也是一个长整型。

#include <time.h>
#ifndef _CLOCK_T_DEFINED
typedef long clock_t;    //clock_t是一个长整形数
#define _CLOCK_T_DEFINED
#endif

//在time.h文件中,还定义了一个常量 CLOCKS_PER_SEC,它用来表示一秒钟会有多少个时钟计时单元
#define CLOCKS_PER_SEC ((clock_t)1000000)

通常使用 clock() 函数返回获取。

#include <time.h>

clock_t clock(void);

//表示进程占用的cpu时间,精确到微秒。
//这个函数返回值为程序开始启动到程序调用clock()函数时之间的CPU时钟计时单元(clock tick)数。

//如果想返回以秒为单位的时间数,可以使用下面的方式:
clock_t start, end, duration;
start = clock();
...
end = clock();
duration = (end - start) / CLOCKS_PER_SEC;

1.3  struct timeb 结构体

#include <time.h>

struct timeb
{
    time_t time;             //秒数
    unsigned short millitm;  //毫秒数
    short timezone;          //时区,当前时区和Greenwich相差的时间,单位为分钟
    short dstflag;           //夏令时标志,如果为非0表示启用夏令时
};

 使用 ftime() 函数获取当前的时间和日期:ftime(&tb);

1.4  struct timeval 结构体

#include <sys/time.h>

struct timeval
{
    long tv_sec;  //seconds:秒
    long tv_usec; //microseconds:微秒
};

由 int gettimeofday(struct timeval *tv, struct timezone *tz); 函数获取。

  • struct timezone 时区结构体
#include <sys/time.h>

struct timezone
{
   int tz_minuteswest; //和Greewich(格林威治)时间差了多少分钟
   int tz_dsttime;     //夏令时Type
};

//常见的DST类型如下:
#define   DST_NONE   0   //not on dst
#define   DST_USA    1   //USA style dst
#define   DST_AUST   2   //Australian style dst
#define   DST_WET    3   //Western European dst
#define   DST_MET    4   //Middle European dst
#define   DST_EET    5   //Eastern European dst
#define   DST_CAN    6   //Canada

1.5  struct timespec 结构体

#include <time.h>

struct timespec
{
    time_t tv_sec; //seconds:秒
    long tv_nsec;  //nanoseconds:纳秒
};

一般由 long clock_gettime (clockid_t which_clock, struct timespec *tp); 函数获取。

1.6  struct tm 结构体

#include <time.h>

struct tm {
    int tm_sec;     //秒 – 取值区间为[0,59]
    int tm_min;     //分 - 取值区间为[0,59]
    int tm_hour;    //时 - 取值区间为[0,23]
    int tm_mday;    //一个月中的日期 - 取值区间为[1,31]
    int tm_mon;     //月份(从一月开始,0代表一月) - 取值区间为[0,11]
    int tm_year;    //年份,其值等于实际年份减去1900
    int tm_wday;    //星期 – 取值区间为[0,6],其中0代表星期天,1代表星期一,以此类推
    int tm_yday;    //从每年的1月1日开始的天数 – 取值区间为[0,365],其中0代表1月1日,1代表1月2日,以此类推
    int tm_isdst;   //夏令时标识符,实行夏令时的时候,tm_isdst为正。不实行夏令时的进候,tm_isdst为0;不了解情况时,tm_isdst()为负
};

struct tm 结构体通常由 gmtime, localtime, mktime 等时间函数返回。

二、常用时间日期函数

2.1  time() 函数 — 提供秒级时间精度

#include <time.h>

time_t time(time_t *t);

使用说明
(1)若函数实参为 NULL, 则返回从1970年1月1日0时0分0秒到现在(系统时间)所经过的秒;
(2)若函数实参非空,则将返回的值存方在由指针 t 所指向的内存单元中。

//使用示例1
time_t now = time(NULL);

//使用示例2
time_t now;
time(&now);
printf("%s", ctime(&now));  //ctime()将时间和日期以字符串格式返回

2.2  gettimeofday() 函数 — 提供微秒级时间精度

#include <sys/time.h>
#include <unistd.h>

int gettimeofday(struct timeval *tv ,struct timezone *tz);

函数说明

该函数可以获取两方面的时间信息,一个是可以获取到从1970年1月1日0时0分0秒到现在(系统时间)所经过的微秒,精度相比 time() 函数精度有所提升;另外还可以获取到系统的时区信息。

返回值】gettimeofday()函数成功返回0,否则返回-1,并将错误码存放在 errno 全局变量中。errno 在 <errno.h> 头文件中定义。

使用说明

  • 在实际开发中,gettimeofday 中的 tz 参数实际很少使用,因为各种原因,一直未能实现(所获取出来的值恒为0),因此,通常将此处直接写成 NULL。

  • 与gettimeofday()函数相对应的是 settimeofday()函数,它可以设置实时时间RTC。但之前必须要具有root权限。

  • settimeofday()

#include <sys/time.h>
#include <unistd.h>

int settimeofday(const struct timeval *tv, const struct timezone *tz);

函数说明】settimeofday()会把目前时间设成由 tv 所指的结构信息,当地时区信息则设成 tz 所指的结构。

返回值】成功则返回0,失败返回-1,错误代码存于errno。

错误代码:

  • EPERM  并非由root 权限调用settimeofday(),权限不够。
  • EINVAL  时区或某个数据是不正确的,无法正确设置时间。

<注意> 在Linux下,只有root 权限才能使用此函数修改时间。

//使用示例
struct timeval tv;
gettimeofday(&tv,NULL);  //获取以struct timeval结构体保存的时间信息

time_t sec, usec;
sec = tv.tv_sec;
usec = tv.tv_usec;

2.3  clock_gettime() 函数 — 提供纳秒级时间精度

#include <time.h>

int clock_getres(clockid_t clk_id, struct timespec *res);

int clock_gettime(clockid_t clk_id, struct timespec *tp);

int clock_settime(clockid_t clk_id, const struct timespec *tp);

函数说明

  • clock_getres() 函数返回由 clk_id 指定的时钟的分辨率,并将其放置在res指向的位置。但是,如果res为 NULL,则不返回任何分辨率。
  • clock_gettime() 函数返回由 clk_id 指定的时钟的当前值,并将其放置在tp指向的位置。
  • clock_settime() 函数将 clk_id 指定的时钟设置为 tp指向时间。当tp不是指定时钟分辨率的倍数时,将使用小于tp的 tp 的最大倍数 。

参数说明

  • clk_id:用于指定计时时钟的类型,有以下4种:

CLOCK_REALTIME:系统实时时间,随系统实时时间改变而改变,即从UTC 1970-1-1 0:0:0 开始计时,中间时刻如果系统时间被用户该成其他,则对应的时间相应改变。

CLOCK_MONOTONIC:从系统启动这一刻起开始计时,不受系统时间被用户改变的影响。

CLOCK_PROCESS_CPUTIME_ID:本进程到运行到当前代码系统CPU所花费的时间。

CLOCK_THREAD_CPUTIME_ID:本线程到运行到当前代码系统CPU花费的时间。

  • res:指向clock_getres()存储检索到的时钟分辨率的位置。
  • tp:指向 timespec 结构,该结构用于存储使用 clock_gettime() 检索的时间值或包含要使用 clock_settime() 设置的新时间值。

返回值】成功时,这些函数返回 0;否则,这些函数返回 -1 ,并将 errno 设置为以下之一:
EFAULT
clock_id 参数是一个未知时钟类型。
EINVAL
clock_id 参数未识别已知时钟或为 clock_settime() 的 tp 指定了无效值。
EPERM
调用clock_settime()的进程缺少设置指定时钟的适当权限。需要 root 权限。

范例

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

int main()
{
    struct timespec ts;
    memset(&ts, 0, sizeof(struct timespec));

    clock_gettime(CLOCK_REALTIME, &ts);
    printf("CLOCK_REALTIME: %d, %d\n", ts.tv_sec, ts.tv_nsec);

    clock_gettime(CLOCK_MONOTONIC, &ts);  //打印出来的时间跟 cat /proc/uptime 第一个参数一样
    printf("CLOCK_MONOTONIC: %d, %d\n", ts.tv_sec, ts.tv_nsec);

    clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts);
    printf("CLOCK_PROCESS_CPUTIME_ID: %d, %d\n", ts.tv_sec, ts.tv_nsec);

    clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts);
    printf("CLOCK_THREAD_CPUTIME_ID: %d, %d\n", ts.tv_sec, ts.tv_nsec);

    printf("time(): %d seconds\n", time(NULL));
    return 0;
}

运行结果

CLOCK_REALTIME: 1645960150, 566539139
CLOCK_MONOTONIC: 13078, 97392275
CLOCK_PROCESS_CPUTIME_ID: 0, 2632933
CLOCK_THREAD_CPUTIME_ID: 0, 2643581
time(): 1645960150 seconds

2.4  asctime()、gmtime()、ctime()、localtime()、mktime()

#include <time.h>

char *asctime(const struct tm *tm);
char *asctime_r(const struct tm *tm, char *buf);

char *ctime(const time_t *timep);
char *ctime_r(const time_t *timep, char *buf);

struct tm *gmtime(const time_t *timep);
struct tm *gmtime_r(const time_t *timep, struct tm *result);

struct tm *localtime(const time_t *timep);
struct tm *localtime_r(const time_t *timep, struct tm *result);

time_t mktime(struct tm *tm);

gmtime、localtime 和 mktime 函数实现了 time_t 时间类型和 struct tm 时间结构体类型的互换功能,而 ctime 函数实现了 time_t 类型转换为时间字符串格式化功能。

以上四个有后缀为 _r 的函数表示的是其对应的线程安全函数版本,用于多线程环境下。

  • asctime()

函数说明】asctime() 将参数 timep 所指的 tm 结构中的信息转换成真实世界所使用的时间日期表示方法,然后将结果以字符串形式返回。此函数已经由时区转换成当地时间,字符串格式为:"Wed Jun 30 21:49:08 1993"。

返回值】返回一个字符串,表示目前当地的时间日期。该函数与 ctime() 函数的不同之处在于传入的参数类型不同:ctime 传入的参数类型是 time_t,而asctime 传入的是 struct tm。

使用说明】asctime() 函数通常与 time()、gmtime() 或 localtime() 函数一起配合使用。范例如下:

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

int main()
{
    time_t now;
    time(&now);
    printf("now=%u\n",now);
    printf("time=%s\n", asctime(gmtime(&now)));
    return 0;
}

运行结果

now=1645885210
time=Sat Feb 26 14:20:10 2022
  • ctime()

函数说明】将参数 timep 所指的 time_t 类型的时间信息转换成真实世界所使用的时间日期表示方法,然后将结果以字符串形式返回。

返回值】返回一个字符串,表示目前当地的时间日期。该函数的功能与 asctime 函数类型,只是传入的参数类型不同。

范例

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

int main()
{
    time_t now;
    time(&now);
    printf("now=%u\n",now);
    printf("time=%s\n", ctime(&now));
    return 0;
}

运行结果

now=1645885675
time=Sat Feb 26 22:27:55 2022
  • gmtime()

函数说明】将参数 timep 所指的 time_t 类型中的时间信息转换成真实世界所使用的时间日期表示方法,然后将结果由结构体 tm 返回。注意该函数获取的是格林威治时间,而不是你所在的本地时间。

返回值】返回由结构体 tm 代表的目前 UTC 时间。也就是说时间日期信息存放在 tm 结构体中。

使用说明】gmtime 函数返回的是格林威治时间,而不是你所在地的本地时间。格林威治时间+8小时,才是我们中国的北京时间。如果要获取本地时间,并使用 tm 返回,应当使用 localtime 函数。

范例

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

int main()
{
    time_t now;
    struct tm *p_tm;
    char buf[256]={0};
    time(&now);
    p_tm = gmtime(&now);  //将time_t时间类型转换为 struct tm 时间结构体类型
    sprintf(buf, "%4d-%02d-%02d %02d:%02d:%02d", p_tm->tm_year+1900, p_tm->tm_mon+1, p_tm->tm_mday,
            p_tm->tm_hour, p_tm->tm_min, p_tm->tm_sec);
    printf("Greenwich time=%s\n", buf);
    return 0;
}

运行结果

Greenwich time=2022-02-26 14:49:36
  • localtime()

函数说明】将参数 timep 所指的 time_t 类型中的信息转换成真实世界所使用的时间日期表示方法,然后将结果由结构 tm 返回。函数返回的时间日期已经转换成当地时区。

返回值】返回结构 tm 代表目前的当地时间。在我们中国就是北京时间。

范例:修改 gmtime 函数中的范例,输出当地时间的字符串格式。

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

int main()
{
    time_t now;
    struct tm *p_tm;
    char buf[256]={0};
    time(&now);
    p_tm = localtime(&now);  //将time_t时间类型转换为 struct tm 时间结构体类型
    sprintf(buf, "%4d-%02d-%02d %02d:%02d:%02d", p_tm->tm_year+1900, p_tm->tm_mon+1, p_tm->tm_mday,
            p_tm->tm_hour, p_tm->tm_min, p_tm->tm_sec);
    printf("Beijing time=%s\n", buf);
    return 0;
}

运行结果

Beijing time=2022-02-26 23:01:12
  • mktime()

函数说明】用来将参数 timep 所指的 tm 结构时间数据转换成从公元1970年1月1日0时0分0 秒算起至今的UTC时间所经过的秒数,相当于调用 time()函数的返回值。

返回值】返回经过的秒数。

函数使用】一般先是使用 localtime 函数返回 tm 结构的本地时间,然后使用 mktime 函数获得从 Epoch 开始到当前时间所经过的秒数。Epoch 指的是公元1970年1月1日0时0分0秒时刻

范例

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

int main()
{
    time_t now;
    struct tm *p_tm;
    time(&now);
    printf("time():%d\n", now);
    p_tm = localtime(&now);  //将time_t时间类型转换为 struct tm 时间结构体类型
    now = mktime(p_tm);      //将struct tm 时间结构体类型转换为 time_t 时间类型
    printf("time()->localtime()->mktime():%d\n", now);
    return 0;
}

运行结果

time():1645888684
time()->localtime()->mktime():1645888684

2.5  timegm()、timelocal() 函数

#include <time.h>

time_t timegm(struct tm *tm);

time_t timelocal(struct tm *tm);

函数说明】timegm() 函数是 gmtime() 的逆置函数;timelocal() 函数是 localtime() 的逆置函数。将 tm 结构体所表示的时间转换为从 Epoch 时刻开始所经过的时间秒数。Epoch 指的是公元1970年1月1日0时0分0秒时刻。这两个函数都是线程安全的。

返回值】返回经过的秒数。

范例

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

int main()
{
    time_t now, seconds;
    struct tm *p_tm;
    time(&now);
    printf("time():%d\n", now);
    p_tm = gmtime(&now);     //将time_t时间类型转换为 struct tm 时间结构体类型
    seconds = timegm(p_tm);  //将struct tm 时间结构体类型转换为 time_t 时间类型
    printf("timegm():%d\n", seconds);
    p_tm = localtime(&now);
    seconds = timelocal(p_tm);
    printf("timelocal():%d\n", seconds);
    return 0;
}

运行结果

time():1645889946
timegm():1645889946
timelocal():1645889946

2.6  strftime()、strptime() — 自定义时间格式函数

#include <time.h>

size_t strftime(char *s, size_t max, const char *format,
               const struct tm *tm);

char *strptime(const char *s, const char *format, struct tm *tm);
  •  strftime()

函数说明】strftime 函数的功能是将由 tm 结构体指针所指的时间按照 format 指针所指的格式输出到由 s 指针所指向的存储空间中,其中 max 是指存储空间允许存放的最大字符个数(即字符数组长度-1)。

返回值】成功,返回写入存储空间的字符个数;失败,返回0。

函数使用】strftime() 函数的操作有些类似于sprintf():识别以百分号(%)开始的格式命令集合,格式化输出结果放在一个字符串中。

格式命令如下,注意它们是区分大小写的:

%a 星期几的简写
%A 星期几的全称
%b 月分的简写
%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 时区名称,如果不能得到时区名称则返回空字符。
%% 百分号

范例

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

int main()
{
    time_t now;
    struct tm *p_tm;
    char buf[256]={0};
    now = time(NULL); 
    p_tm = localtime(&now);
    strftime(buf, sizeof(buf)-1, "%F %T %a", p_tm);
    printf("local time=%s\n", buf);
    return 0;
}

运行结果

local time=2022-02-27 00:23:46 Sun
  • strptime()

函数说明】strptime 函数是 strftime 函数的逆过程,它是将字符指针 s 指向的时间字符串,按照 format 格式转换为 tm 结构体时间格式。format 格式的书写与 strftime 的相同。

返回值】成功,则返回第一个未处理的字符的指针;失败,返回 NULL。

函数使用】该函数类似于 scanf 函数,解析时间字符串为 tm 时间格式。

范例

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

int main()
{
    time_t now;
    struct tm tm;
    char buf[256]={0};
    memset(&tm, 0, sizeof(struct tm));
    strptime("2022-02-27 00:57:30", "%Y-%m-%d %H:%M:%S", &tm);
    strftime(buf, sizeof(buf)-1, "%D %H:%M:%S %a", &tm);
    printf("local time=%s\n", buf);
    return 0;
}

运行结果

local time=02/27/22 00:57:30 Sun

2.7  difftime() — 计算时间持续的长度函数

#include <time.h>

double difftime(time_t time1, time_t time0);

函数说明】计算time1 和 time0 之间相差的秒数(time1 - time0)。这两个时间是在日历时间中指定的,表示了自纪元 Epoch(协调世界时 UTC:1970-01-01 00:00:00)起经过的时间

返回值】返回 (time1 - time0) 的时间秒数。

范例

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

int main()
{
    time_t start, end;
    start = time(NULL);
    getchar();
    end = time(NULL);
    printf("The pause time: %.2f seconds\n", difftime(end, start));
    return 0;
}

运行结果

The pause time: 4.00 seconds

2.8  睡眠函数:sleep()、usleep()、nanosleep()

#include <unistd.h>

unsigned int sleep(unsigned int seconds);  //秒数
int usleep(useconds_t usec);               //微秒数

#include <time.h>
int nanosleep(const struct timespec *rqtp, struct timespec *rmtp);  //纳秒数
  • sleep() 函数

函数说明】sleep 函数会让进程/线程进入睡眠状态 seconds 秒。

返回值】如果睡眠时间达到了参数 seconds 指定的秒数,则返回 0;如果 sleep 函数被信号中断执行,则返回剩余睡眠的秒数。

  • usleep() 函数

函数说明】usleep 函数的功能和 sleep 一样,只是它提供的是更精确的时间粒度,单位为微秒(1 秒 = 一百万微秒)。

返回值】成功,返回 0;失败,返回 -1,并将错误码存放在 errno 全局变量中。errno 在 <errno.h> 头文件中定义

(1) 如果 usleep 函数被信号中断执行,也是返回 -1,并将 errno 设置为 EINTR 错误码。

(2) 如果传给形参 usec 的实参值大于一百万,系统也会认为这是一个错误,返回 -1,并将 errno 设置为 EINVAL 错误码。

  • nanosleep() 函数

函数说明】nanosleep 函数可以利用 struct timespec 时间结构体提供纳秒粒度的时间精度。nanosleep 会让程序睡眠 rqtp 指针指向的时间,若 rmtp 参数为 non-NULL,而且睡眠时间未到期就返回了,将会把剩余的时间存放在 rmtp 指针指向的 timespec 结构变量中。如果不需要的话,可以将 rmtp 参数置为 NULL。

返回值】如果达到了要求的睡眠时间,则返回 0;否则,返回 -1,并将错误码存放在 errno 全局变量中。

(1) 如果 nanosleep 函数被信号中断,返回 -1,并将 errno 设置为 EINTR 错误码。

(2) rqtp 指针指向的 timespec 结构体变量的成员 tv_nsec 的值设置为小于 0 或者大于等于 10亿,返回 -1,并将 errno 设置为 EINVAL 错误码。

2.9  alarm() 函数 — 设置告警信号(SIGALRM)传送闹钟

#include <unistd.h>

unsigned int alarm(unsigned seconds);

函数说明】alarm 函数用来设置告警信号(SIGALRM)的定时器,调用该函数,在经过参数seconds秒数后,系统将会产生一个 SIGALRM 告警信号发送给当前的进程。如果未设置信号 SIGALARM 的处理函数,那么 alarm() 函数默认处理方式是终止进程。

返回值】如果在之前被调用的 alarm 函数的 seconds 秒时间到期之前,再次调用了alarm 函数设置了新的闹钟,则后面定时器的设置将覆盖前面的设置,即之前设置的秒数被新的闹钟时间取代,之前的 alarm 函数将返回剩余秒数的值;如果是在 seconds 秒数到期时返回的,则返回 0。

函数使用】alarm 函数设置的定时时间到期后,系统将会产生一个 SIGALARM 信号发送给进程,因此其一般与信号处理函数一起配合使用,Linux下的信号处理函数有 signalsigaction。下面的范例我们将使用 signal 函数来处理 SIGALARM 信号。

  • signal() 函数

#include <signal.h>

//signal函数原型声明方式1
void (*signal(int sig, void (*func)(int)))(int);

//signal函数原型声明方式2 (推荐使用方式2的函数原型声明)
typedef void (*sighandler_t)(int);  //声明一个函数类型 sighandler_t
 
sighandler_t signal(int signo, sighandler_t handler);

参数说明

  • sig:表示信号,它是一个整数值(1~64)。在Linux中用符号常量来表示,使用 kill -l 命令可以查看所有的信号,一共有64个。如 alarm 函数产生的告警信号为 SIGALARM
  • handler:它是一个函数指针,指向信号处理函数。当产生参数 sig 表示的信号时,会回调该信号对应的信号处理函数。

范例

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

void sig_handler(int sig)
{
    if(sig == SIGALRM)
        printf("receive alarm signal: %d\n", sig);
    alarm(5);  //每隔5秒重复产生一个SIGALRM信号
}

int main()
{
    int i=0;
    signal(SIGALRM, sig_handler);  //注册SIGALRM信号的信号处理函数sig_handler
    alarm(2);                      //设置2秒后产生一个SIGALRM信号
    for(; ; i++)
    {
        printf("sleep %d ...\n", i+1);
        sleep(1);  //进程睡眠1秒
    }
    return 0;
}

运行结果

sleep 1 ...
sleep 2 ...
receive alarm signal: 14
sleep 3 ...
sleep 4 ...
sleep 5 ...
sleep 6 ...
sleep 7 ...
receive alarm signal: 14
sleep 8 ...
sleep 9 ...
sleep 10 ...
sleep 11 ...
sleep 12 ...
receive alarm signal: 14
^C

结果分析:从运行结果可以看到,当进程运行2秒后,产生了一个SIGALRM信号,并触发了该注册信号的信号处理器,即信号处理函数 sig_handler(),输出打印语句。在sig_handler函数中又调用了alarm 函数,以后每隔5秒就会产生一个SIGALRM信号,然后回调信号处理函数。在 main() 函数中,使用了无限循环。

2.10  ftime() 函数

#include <sys/timeb.h>

int ftime(struct timeb *tp);

函数描述】取得当前的时间,并将返回的结果保存在指针 tp 所指向的 timeb 结构的存储空间中。该函数的功能类似于 time、localtime、gettimeofday、clock_gettime 函数的功能,只是保存的时间类型不同。

  • time():返回的 time_t 类型
  • localtime:返回的是 struct tm 结构体类型
  • gettimeofday:返回的是 struct timeval 结构体类型
  • clock_gettime:返回的是 struct timespec 结构体类型
  • ftime:返回的是 struct timeb 结构体类型

ftime 函数取得的时间是从 Epoch(即 1970-01-01 00:00:00 +0000 (UTC)) 时刻开始到当前时刻所经过的时间,并保存在 tp 指针指向的 timeb 结构的存储空间中。

返回值】无论成功或失败都是返回 0。

范例

#include <stdio.h>
#include <string.h>
#include <sys/timeb.h>
#include <time.h>

int main()
{
    struct timeb tb;
    memset(&tb, 0, sizeof(struct timeb));
    time_t now = time(NULL);
    printf("time()=%d\n", now);
    ftime(&tb);
    printf("tb.time=%d\n", tb.time);
    printf("tb.millitm=%d\n", tb.millitm);
    printf("tb.timezone=%d\n", tb.timezone);
    printf("tb.dstflag=%d\n", tb.dstflag);
    
    return 0;
}

运行结果

time()=1645962384
tb.time=1645962384
tb.millitm=170
tb.timezone=0
tb.dstflag=0

2.11  tzset() 函数 — 使用系统环境变量初始化时间转换信息

#include <time.h>

void tzset (void);

extern char *tzname[2];  //字符指针数组
extern long timezone;
extern int daylight;

函数描述】tzset() 函数使用系统环境变量 TZ 的当前设置把值赋给三个全局变量: daylight, timezone 和 tzname。如果环境变量 TZ 没有设置,全局变量 tzname 会按照 /etc/localtime 找出最接近当地的时区。如果环境变量TZ的值为NULL,或是无法判断,则使用UTC时区。

基于TZ环境变量的值,当调用tzset()函数时把如下值赋给全局变量 daylight、timezone 和 tzname:
全局变量              说明                                                         缺省值
daylight      如果在TZ设置中指定夏令时时区           有夏令时则为非0值;否则为0
timezone    UTC和本地时间之间的时差,单位为秒    28800(28800秒等于8小时)
tzname[0]   TZ环境变量的时区名称的字符串值        如果TZ未设置则为空 PST
tzname[1]   夏令时时区的字符串值;                          如果TZ环境变量中忽略夏令时时区则为空PDT。在上表中daylight 和 tzname数组的缺省值对应于"PST8PDT",即太平洋标准时间(PST)和太平洋夏令时(PDT)。

tzname[0] = "PST"  表示太平洋标准时间

tzname[1] = "PDT"  表示太平洋夏令时

timezone = 28800   表示UTC和本地时间的时区差,用秒来表示,8小时即为 28800 秒。

如果从TZ环境变量忽略DST(夏令时)时区,daylight的值为0,ftime, gmtime 和 localtime 函数对于它们的DST标志返回0。

参考链接

linux 的时区设置函数 tzset()

全球时区大全

UTC和GMT时间

范例

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <errno.h>

int main()
{
    time_t now;
    //输出tzname,timezone,daylight的默认值
    tzset();
    printf("daylight = %d\n", daylight);
    printf("timezone = %ld\n", timezone);
    printf("tzname[0]=%s, tzname[1]=%s\n", tzname[0], tzname[1]);
	time(&now);
    printf("default time = %s\n", asctime(localtime(&now)));

    
    if(putenv("TZ=PST8PDT") != 0)  //设置太平洋标准时间和太平洋夏令时
    {
        printf("putenv() error: %d:%s\n", errno, strerror(errno));
        return -1;
    }
    tzset();
    printf("daylight = %d\n", daylight);
    printf("timezone = %ld\n", timezone);
    printf("tzname[0]=%s, tzname[1]=%s\n", tzname[0], tzname[1]);
    time(&now);
    printf("PST time = %s\n", asctime(localtime(&now)));
    
    if(setenv("TZ","UTC-8", 1) != 0)  //设置中国时区时间 UTC=北京时间-8(中国没有夏令时)
    {
        printf("putenv() error: %d:%s\n", errno, strerror(errno));
        return -1;
    }
    tzset();
    printf("daylight = %d\n", daylight);
    printf("timezone = %ld\n", timezone);
    printf("tzname[0]=%s, tzname[1]=%s\n", tzname[0], tzname[1]);
    time(&now);
    printf("China time = %s\n", asctime(localtime(&now)));

    return 0;
}

运行结果

daylight = 1
timezone = -28800
tzname[0]=CST, tzname[1]=CDT
default time = Sun Feb 27 21:45:35 2022

daylight = 1
timezone = 28800
tzname[0]=PST, tzname[1]=PDT
PST time = Sun Feb 27 05:45:35 2022

daylight = 0
timezone = -28800
tzname[0]=UTC, tzname[1]=UTC
China time = Sun Feb 27 21:45:35 2022

结果分析

<说明> 本人 Linux 系统中并未设置 TZ 环境变量。

第一组输出中,CST 表示的是美国中部标准时间缩写,-28800秒(-8小时)表示该时区比UTC早8个小时,夏令时缩写为 CDT(美国中部夏令时),这个默认值的输出结果显然是有问题的。

第二组输出中,PST 表示的是太平洋标准时间缩写,28880秒(8小时)表示该时区比UTC晚8个小时,夏令时缩写为 PDT(太平洋夏令时)。

第三组删除中,UTC-8 表示的是中国标准时间缩写,-28800秒(-8小时)表示该时区比UTC早8个小时,中国无夏令时。

CST 时区缩写同时可以代表如下 3 个不同的时区:
Central Standard Time (USA) UTC-6:00(美国中部时间)
China Standard Time UTC+8:00(中国时间)
Cuba Standard Time UTC-4:00(古巴时间)

备注】设置 Linux 系统的环境变量可以使用 setenv 或 putenv 函数,取消环境变量的设置可以使用 unsetenv 函数。这3个函数的函数原型如下:

#include <stdlib.h>

int setenv(const char *name, const char *value, int overwrite);

int unsetenv(const char *name);

int putenv(char *string);

三、时间日期函数的应用

3.1  获取当前日期时间字符串格式(时间粒度精确到秒)

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

void get_format_now_string(char *format, char *buf);
void get_format_time_string(time_t time, char *format, char *buf);

void get_date_string(char *buf) {
    if (buf == NULL) {
        return;
    }

    time_t now = time(NULL);
    struct tm mytm={0};
    struct tm* p_tm = localtime_r(&now, &mytm);
    sprintf(buf, "%4d-%02d-%02d", p_tm->tm_year + 1900, p_tm->tm_mon + 1, p_tm->tm_mday);
}

void get_now_string(char *buf)
{
    get_format_now_string("%4d-%02d-%02d %02d:%02d:%02d", buf);
}

void get_compact_now_string(char* buf)
{
    get_format_now_string("%4d%02d%02d%02d%02d%02d", buf);
}

void get_time_string(time_t time,char* buf)
{
    get_format_time_string(time,"%4d-%02d-%02d %02d:%02d:%02d", buf);
}

void get_compact_time_string(time_t time,char* buf)
{
    get_format_time_string(time,"%4d%02d%02d%02d%02d%02d", buf);
}

void get_format_now_string(char* format, char* buf)
{
    time_t now = time(NULL);
    get_format_time_string(now,format,buf);
}

void get_format_time_string(time_t time, char* format, char *buf)
{
    if (buf == NULL) {
        return;
    }
    struct tm mytm={0};
    struct tm* p_tm = localtime_r(&time,&mytm);  //localtime_r是线程安全版本函数
    if (p_tm == NULL) {
        return;
    }
    sprintf(buf, format, p_tm->tm_year + 1900, p_tm->tm_mon + 1, p_tm->tm_mday,
            p_tm->tm_hour, p_tm->tm_min, p_tm->tm_sec);
}
  • 测试用例
int main()
{
    char buf[255]={0};
    
    get_date_string(buf);
    printf("date_string=%s\n", buf);
    
    get_now_string(buf);
    printf("now_string=%s\n", buf);
    
    get_compact_now_string(buf);
    printf("compact_now_string=%s\n", buf);
    
    int now = time(NULL);
    get_time_string(now, buf);
    printf("time_string=%s\n", buf);
    
    get_compact_time_string(now, buf);
    printf("compact_time_string=%s\n", buf);

    return 0;
}
  • 运行结果
date_string=2022-02-27
now_string=2022-02-27 17:59:33
compact_now_string=20220227175933
time_string=2022-02-27 17:59:33
compact_time_string=20220227175933

3.2  获取当前日期时间字符串格式(时间粒度精确到毫秒)

#include <stdio.h>
#include <string.h>
#include <time.h>
#include <sys/types.h>

void get_format_milli_now_string(char* format, char* buf);
void get_format_milli_time_string(time_t time, suseconds_t usec, char* format, char* buf);


void get_milli_now_string(char* buf)
{
    get_format_milli_now_string("%4d-%02d-%02d %02d:%02d:%02d.%03d", buf);
}

void get_compact_milli_now_string(char* buf)
{
    get_format_milli_now_string("%4d%02d%02d%02d%02d%02d.%03d", buf);
}

void get_format_milli_now_string(char* format, char* buf)
{
    struct timeval tv;
    gettimeofday(&tv, NULL);
    get_format_milli_time_string(tv.tv_sec, tv.tv_usec, format, buf);
}

void get_milli_time_string(time_t time, suseconds_t usec, char* buf)
{
    get_format_milli_time_string(time, usec, "%4d-%02d-%02d %02d:%02d:%02d.%03d", buf);
}

void get_compact_milli_time_string(time_t time, suseconds_t usec, char* buf)
{
    get_format_milli_time_string(time, usec, "%4d%02d%02d%02d%02d%02d.%03d", buf);
}

void get_format_milli_time_string(time_t time, suseconds_t usec, char* format, char* buf)
{
    if(buf == NULL) {
        return;
    }

    struct tm mytm={0};
    struct tm* p_tm = localtime_r(&time, &mytm);
    if (p_tm == NULL) {
        return;
    }
    sprintf(buf, format, p_tm->tm_year + 1900, p_tm->tm_mon + 1, p_tm->tm_mday,
            p_tm->tm_hour, p_tm->tm_min, p_tm->tm_sec,usec/1000);
}
  • 测试用例
int main()
{
    char buf[255]={0};

    get_milli_now_string(buf);
    printf("milli_now_string=%s\n", buf);

    get_compact_milli_now_string(buf);
    printf("compact_milli_now_string=%s\n", buf);

    struct timeval tv;
	gettimeofday(&tv, NULL);
    get_milli_time_string(tv.tv_sec, tv.tv_usec, buf);
    printf("milli_time_string=%s\n", buf);

    get_compact_milli_time_string(tv.tv_sec, tv.tv_usec, buf);
    printf("compact_milli_time_string=%s\n", buf);

    return 0;
}
  • 运行结果
milli_now_string=2022-02-27 18:20:47.220
compact_milli_now_string=20220227182047.221
milli_time_string=2022-02-27 18:20:47.221
compact_milli_time_string=20220227182047.221

参考

linux下时间有关的函数和结构体

时间函数:localtime、localtime_r

Linux 时间日期函数总结

  • 4
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值