时间和日期函数
程序员文章站
2022-03-09 23:34:57
...
UNIX 内核提供的基本时间服务是计算自协调世界时(Coordinated Universal Time, UTC)公元 1970 年 1 月 1 日 00:00:00 这一特定时间以来经过的秒数(以数据类型 time_t 表示),通常称之为为日历时间。日历时间包括时间和日期,可自动进行变换,如变换到夏令时。
time 函数可用于返回当前的时间和日期。
时间值作为函数值返回。如果参数非空,则时间值也存放在由 calptr 指向的单元内。
POSXI.1 的实时扩展增加了对多个系统时钟的支持。时钟通过 clockid_t 类型进行标识,标准的值如下表所示。
[img]http://dl2.iteye.com/upload/attachment/0126/5651/a9df34b3-02ab-35ee-8feb-e5c576406e34.png[/img]
下面几个函数可以用来操作时钟。
clock_gettime 函数可用于获取指定时钟的时间,返回的时间在 timespec 结构中。当 clock_id 设置为 CLOCK_REALTIME 时,clock_gettime 就提供了类似 time 的功能,只是可能拥有更高的精度。
clock_getres 函数把参数 tsp 指向的 timespec 结构初始化为与 clock_id 参数对应的时钟精度。例如,如果精度为 1 毫秒,则 tv_sec 字段就是 0,tv_nsec 字段就是 1000000。
clock_settime 函数可对特定的时钟设置时间,这需要适当的特权,而且有些时钟是不能修改的(历史上,System V 派生的系统是调用 stime 函数来设置系统时间,而 BSD 派生的系统是调用 settimeofday 函数来设置系统时间)。
gettimeofday 函数已被 SUSv4 指定为弃用,但一些程序仍然在使用,因为它提供了比 time 函数更高的精度(可到微秒级)。tzp 参数的唯一合法值是 NULL,其他值将产生不确定的结果。该函数将当前时间秒数存放在 tp 指向的 timeval 结构中,而该结构将当前时间表示为秒和微秒。
一旦取得这种从上述特定时间经过的秒数的整型时间值后,通常需要调用函数将其转换为分解的时间结构,然后调用另一个函数生成可读的时间和日期。
这里的秒可以超过 59 的理由是可以表示润秒(Single UNIX Specification 的以前版本允许双润秒,所以 tm_sec 的有效范围是 0~61)。除了月日字段,其他字段的值都以 0 开始。如果夏令时生效,则夏令时标志为正;如果为非夏令时时间,则该标志值为 0;如果此信息不可用,则其值为负。
localtime 和 gmtime 函数将日历时间转换成分解的时间,并存放在 tm 结构中。它们的区别是:localtime 转换成本地时间,而 gmtime 转换成协调统一时间。
mktime 函数将本地时间转换成 time_t 值。
strftime 函数可通过可用的多个参数来定制产生的字符串。strftime_l 允许将区域指定为参数,strftime 使用通过 TZ 环境变量指定的区域。除此之外,strftime 和 strftime_l 是相同的(两个较早的函数 asctime 和 ctime 能用于产生一个 26 字节的可打印的字符串,类似于 date 命令的默认输出,但它们已因缓冲区溢出问题而被标记为弃用了)。
tmptr 参数是要格式化的时间值。格式化结果存在一个长度为 maxsize 个字符的 buf 数组中。
format 参数控制时间值的格式,其中除转换说明以外的字符都按原样输出。以下列出了 37 种 ISO C 规定的转换说明。
[img]http://dl2.iteye.com/upload/attachment/0126/5832/9a0bc3ce-82c3-33f0-909a-b1cc348c2e3e.png[/img]
其中可能需要略作解释的是 %U、%V 和 %W。%U 是相应日期在该年中所属周数,包含该年中第一个星期日的周是第一周。%W 也是相应日期在该年中所属的周数,不同的是包含第一个星期一的周为第一周。%V 说明符则是如果包含了 1 月 1 日的那一周包含了新一年的 4 天以上,那么该周是一年中的第一周;否则就被认为是上一年的最后一周。在这两种情况下,周一都被视作每周的第一天。
strftime 同 printf 对某些转换说明支持修饰符,可以使用 E 和 O 修饰符产生本地支持的另一种格式。
strptime 函数是 strftime 的相反版本,把字符串时间转换成分解时间。format 参数给出了 buf 参数指向的缓冲区内的字符串的格式。
下面这个程序简单演示了 strftime 函数的使用。
运行结果如下。
下图说明了各种时间函数之间的关系。
[img]http://dl2.iteye.com/upload/attachment/0126/5658/96d7ec33-e621-3269-883a-c3136269d286.png[/img]
图中的 localtime、mktime 和 strftime 三个函数都受到环境变量 TZ 的影响。如果定义了 TZ,则这些函数将使用其值代替默认时区。如果定义为空串(即 TZ=),则使用 UTC。TZ 的值常常类似于 TZ=EST5EDT。
time 函数可用于返回当前的时间和日期。
#include <time.h>
time_t time(time_t *calptr); /* 返回值:若成功,返回时间值;否则,返回 -1 */
时间值作为函数值返回。如果参数非空,则时间值也存放在由 calptr 指向的单元内。
POSXI.1 的实时扩展增加了对多个系统时钟的支持。时钟通过 clockid_t 类型进行标识,标准的值如下表所示。
[img]http://dl2.iteye.com/upload/attachment/0126/5651/a9df34b3-02ab-35ee-8feb-e5c576406e34.png[/img]
下面几个函数可以用来操作时钟。
#include <time.h>
int clock_gettime(clockid_t clock_id, struct timespec *tsp);
int clock_getres(clockid_t clock_id, struct timespec *tsp);
int clock_settime(clockid_t clock_id, const struct timespec *tsp);
/* 返回值:若成功,都返回 0;否则,都返回 -1 */
int gettimeofday(struct timeval *restrict tp, void *restrict tzp);
/* 返回值:总是返回 0 */
struct timespec{
time_t tv_sec;
long tv_nsec;
};
struct timeval{
time_t tv_sec; // seconds
long tv_usec; // microseconds
};
clock_gettime 函数可用于获取指定时钟的时间,返回的时间在 timespec 结构中。当 clock_id 设置为 CLOCK_REALTIME 时,clock_gettime 就提供了类似 time 的功能,只是可能拥有更高的精度。
clock_getres 函数把参数 tsp 指向的 timespec 结构初始化为与 clock_id 参数对应的时钟精度。例如,如果精度为 1 毫秒,则 tv_sec 字段就是 0,tv_nsec 字段就是 1000000。
clock_settime 函数可对特定的时钟设置时间,这需要适当的特权,而且有些时钟是不能修改的(历史上,System V 派生的系统是调用 stime 函数来设置系统时间,而 BSD 派生的系统是调用 settimeofday 函数来设置系统时间)。
gettimeofday 函数已被 SUSv4 指定为弃用,但一些程序仍然在使用,因为它提供了比 time 函数更高的精度(可到微秒级)。tzp 参数的唯一合法值是 NULL,其他值将产生不确定的结果。该函数将当前时间秒数存放在 tp 指向的 timeval 结构中,而该结构将当前时间表示为秒和微秒。
一旦取得这种从上述特定时间经过的秒数的整型时间值后,通常需要调用函数将其转换为分解的时间结构,然后调用另一个函数生成可读的时间和日期。
#include <time.h>
struct tm *gmtime(const time_t *calptr);
struct tm *localtime(const time_t *calptr);
/* 返回值:若成功,都返回指向分解的 tm 结构的指针;否则,都返回 NULL */
time_t mktime(struct tm *tmptr);
/* 返回值:若成功,返回日历时间;否则,返回 -1 */
size_t strftime(char *restrict buf, size_t maxsize,
const char *restrict format,
const struct tm *restrict tmptr);
size_t strftime_l(char *restrict buf, size_t maxsize,
const char *restrict format,
const struct tm *restrict tmptr, locale_t locale);
/* 返回值:若有空间,都返回存入数组的字符数;否则,都返回 0 */
char *strptime(const char *restrict buf, const char *restrict format,
struct tm *restrict tmptr);
/* 返回值:指向上次解析的字符的下一个字符的指针;否则,返回 NULL */
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: [0 - 365]
int tm_isdst; // daylight saving time flag: <0, 0, >0
};
这里的秒可以超过 59 的理由是可以表示润秒(Single UNIX Specification 的以前版本允许双润秒,所以 tm_sec 的有效范围是 0~61)。除了月日字段,其他字段的值都以 0 开始。如果夏令时生效,则夏令时标志为正;如果为非夏令时时间,则该标志值为 0;如果此信息不可用,则其值为负。
localtime 和 gmtime 函数将日历时间转换成分解的时间,并存放在 tm 结构中。它们的区别是:localtime 转换成本地时间,而 gmtime 转换成协调统一时间。
mktime 函数将本地时间转换成 time_t 值。
strftime 函数可通过可用的多个参数来定制产生的字符串。strftime_l 允许将区域指定为参数,strftime 使用通过 TZ 环境变量指定的区域。除此之外,strftime 和 strftime_l 是相同的(两个较早的函数 asctime 和 ctime 能用于产生一个 26 字节的可打印的字符串,类似于 date 命令的默认输出,但它们已因缓冲区溢出问题而被标记为弃用了)。
tmptr 参数是要格式化的时间值。格式化结果存在一个长度为 maxsize 个字符的 buf 数组中。
format 参数控制时间值的格式,其中除转换说明以外的字符都按原样输出。以下列出了 37 种 ISO C 规定的转换说明。
[img]http://dl2.iteye.com/upload/attachment/0126/5832/9a0bc3ce-82c3-33f0-909a-b1cc348c2e3e.png[/img]
其中可能需要略作解释的是 %U、%V 和 %W。%U 是相应日期在该年中所属周数,包含该年中第一个星期日的周是第一周。%W 也是相应日期在该年中所属的周数,不同的是包含第一个星期一的周为第一周。%V 说明符则是如果包含了 1 月 1 日的那一周包含了新一年的 4 天以上,那么该周是一年中的第一周;否则就被认为是上一年的最后一周。在这两种情况下,周一都被视作每周的第一天。
strftime 同 printf 对某些转换说明支持修饰符,可以使用 E 和 O 修饰符产生本地支持的另一种格式。
strptime 函数是 strftime 的相反版本,把字符串时间转换成分解时间。format 参数给出了 buf 参数指向的缓冲区内的字符串的格式。
下面这个程序简单演示了 strftime 函数的使用。
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(void){
time_t t;
struct tm *tmp;
char buf1[16];
char buf2[64];
time(&t);
tmp = localtime(&t);
if(strftime(buf1, 16, "time and date: %r, %a %b %d, %Y", tmp) == 0)
printf("buffer length 16 is too small\n");
else
printf("%s\n", buf1);
if(strftime(buf2, 64, "time and date: %r, %a %b %d, %Y", tmp) == 0)
printf("buffer length 64 is too small\n");
else
printf("%s\n", buf2);
exit(0);
}
运行结果如下。
$ ./strftimeDemo.out
buffer length 16 is too small
time and date: 00:45:35 AM, Fri Aug 19, 2017
下图说明了各种时间函数之间的关系。
[img]http://dl2.iteye.com/upload/attachment/0126/5658/96d7ec33-e621-3269-883a-c3136269d286.png[/img]
图中的 localtime、mktime 和 strftime 三个函数都受到环境变量 TZ 的影响。如果定义了 TZ,则这些函数将使用其值代替默认时区。如果定义为空串(即 TZ=),则使用 UTC。TZ 的值常常类似于 TZ=EST5EDT。