时间和日期函数

    UNIX 内核提供的基本时间服务是计算自协调世界时(Coordinated Universal Time, UTC)公元 1970 年 1 月 1 日 00:00:00 这一特定时间以来经过的秒数(以数据类型 time_t 表示),通常称之为为日历时间。日历时间包括时间和日期,可自动进行变换,如变换到夏令时。
    time 函数可用于返回当前的时间和日期。
#include <time.h>
time_t time(time_t *calptr);    /* 返回值:若成功,返回时间值;否则,返回 -1 */

    时间值作为函数值返回。如果参数非空,则时间值也存放在由 calptr 指向的单元内。
    POSXI.1 的实时扩展增加了对多个系统时钟的支持。时钟通过 clockid_t 类型进行标识,标准的值如下表所示。

    下面几个函数可以用来操作时钟。
#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 规定的转换说明。

    其中可能需要略作解释的是 %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

    下图说明了各种时间函数之间的关系。

    图中的 localtime、mktime 和 strftime 三个函数都受到环境变量 TZ 的影响。如果定义了 TZ,则这些函数将使用其值代替默认时区。如果定义为空串(即 TZ=),则使用 UTC。TZ 的值常常类似于 TZ=EST5EDT。

猜你喜欢

转载自aisxyz.iteye.com/blog/2390062