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

摘自:https://blog.csdn.net/u010429831/article/details/122722187

一、时间日期类型
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下的信号处理函数有 signal 和 sigaction。下面的范例我们将使用 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 时间日期函数总结
————————————————
版权声明:本文为CSDN博主「yunfan188」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u010429831/article/details/122722187

posted @ 2023-11-15 15:52  LiuYanYGZ  阅读(1327)  评论(0编辑  收藏  举报