c时间函数strftime、struct timespec 和 struct timeval

时间和日期

由UNIX内核提供的基本时间服务是计算自协调世界时(Coordinated Universal Time,UTC)公元1970年1月1日00:00:00这一特定 时间以来经过的秒数。1.10节中曾提及这种秒数是以数据类型time_t表示 的,我们称它们为日历时间。日历时间包括时间和日期。UNIX在这方 面与其他操作系统的区别是:(a)以协调统一时间而非本地时间计 时;(b)可自动进行转换,如变换到夏令时;(c)将时间和日期作为 一个量值保存。

一般由函数int clock_gettime(clockid_t, struct timespec *)获取特定时钟的时间,常用如下4种时钟:
CLOCK_REALTIME 统当前时间,从1970年1.1日算起
CLOCK_MONOTONIC 系统的启动时间,不能被设置
CLOCK_PROCESS_CPUTIME_ID 本进程运行时间
CLOCK_THREAD_CPUTIME_ID 本线程运行时间

struct tm *localtime(const time_t *clock);  //线程不安全
struct tm* localtime_r( const time_t* timer, struct tm* result );//线程安全
size_t strftime (char* ptr, size_t maxsize, const char* format,const struct tm* timeptr );

time函数返回当前时间和日期。

#include <time.h>
time_t time(time_t *calptr);

返回值:若成功,返回时间值;若出错,返回-1 时间值作为函数值返回。如果参数非空,则时间值也存放在由calptr
指向的单元内。

POSXI.1的实时扩展增加了对多个系统时钟的支持。在Single UNIX
Specification V4中,控制这些时钟的接口从可选组被移至基本组。时钟 通过clockid_t类型进行标识。图6-8给出了标准值。


image.png

clock_gettime函数可用于获取指定时钟的时间,返回的时间在4.2节 介绍的timespec结构中,它把时间表示为秒和纳秒。

#include <sys/time.h>
int clock_gettime(clockid_t clock_id, struct timespec *tsp);

写一段简单的代码

#include <iostream>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/utsname.h>
#include <string.h>
#include <time.h>
#include <sys/time.h>


int main() {
    time_t time_unix = time(NULL);
    printf("this  code is intended for time\n");
    printf("unix CST: %ld\n", time_unix);

    /* test clock_gettime. */
    struct timespec time_sys;
    int ret = clock_gettime(CLOCK_THREAD_CPUTIME_ID, &time_sys);
    printf("tv_nsec: %ld ns, tv_sec: %ld s\n", time_sys.tv_nsec, time_sys.tv_sec);
    return 0;
}
image.png

当时钟ID设置为CLOCK_REALTIME时,clock_gettime函数提供了
与time函数类似的功能,不过在系统支持高精度时间值的情况下, clock_gettime可能比time函数得到更高精度的时间值。

#include <sys/time.h>
int clock_getres(clockid_t clock_id, struct timespec *tsp);

返回值:若成功,返回0;若出错,返回-1 clock_getres函数把参数tsp指向的timespec结构初始化为与clock_id参
数对应的时钟精度。例如,如果精度为1毫秒,则tv_sec字段就是0, tv_nsec字段就是1 000 000。

例如:

/*
 * @Author: machineplay
 * @Date: 2020-02-04 20:25:49
 * @Description: only for fun
 */
#include <iostream>
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/utsname.h>
#include <time.h>
#include <sys/time.h>
#include <string.h>


/**
 * main function.
 * @param 
 * @return: 0
 */
int main(int argc, char *argv[]) {

    /*  test time. */
    time_t now_time = time(NULL);
    printf("time_t :%ld\n", now_time);

    /* test sys_time. */
    int ret = 0;
    struct timespec time_sys;
    clock_getres(CLOCK_PROCESS_CPUTIME_ID, &time_sys);
    printf("process_time: %ld ns, %ld s\n", time_sys.tv_nsec, time_sys.tv_sec);
    clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &time_sys);
    printf("process_time: %ld ns, %ld s\n", time_sys.tv_nsec, time_sys.tv_sec);

    

    return 0;
}

精度为1000ns


image.png

要对特定的时钟设置时间,可以调用clock_settime函数。

要对特定的时钟设置时间,可以调用clock_settime函数。

#include <sys/time.h>
int clock_settime(clockid_t clock_id, const struct timespec *tsp);

返回值:若成功,返回0;若出错,返回-1 我们需要适当的特权来更改时钟值,但是有些时钟是不能修改的。

SUSv4指定gettimeofday函数现在已弃用。然而,一些程序仍然使用 这个函数,因为与time函数相比,gettimeofday提供了更高的精度(可到 微秒级)。

#include <sys/time.h>
int gettimeofday(struct timeval *restrict tp, void *restrict tzp);

tzp的唯一合法值是NULL,其他值将产生不确定的结果。某些平台
支持用tzp说明时区,但这完全依实现而定,Single UNIX Specification对 此并没有定义。

gettimeofday函数以距特定时间(1970年1月1日00 : 00 : 00)的秒数的 方式将当前时间存放在tp指向的timeval结构中,而该结构将当前时间表 示为秒和微秒。

一旦取得这种从上述特定时间经过的秒数的整型时间值后,通常要 调用函数将其转换为分解的时间结构,然后调用另一个函数生成人们可 读的时间和日期。图6-9说明了各种时间函数之间的关系。(图中以虚 线表示的3个函数localtime、mktime和strftime都受到环境变量TZ的影响, 我们将在本节的最后部分对其进行说明。点划线表示了如何从时间相关 的结构获得日历时间。)
个函数localtime和gmtime将日历时间转换成分解的时间,并将这 些存放在一个tm结构中。

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 1: [0 - 365]
*/
int  tm_isdst;  /* daylight saving time flag: <0, 0,
>0 */ };

秒可以超过59的理由是可以表示润秒。注意,除了月日字段,其他 字段的值都以0开始。如果夏令时生效,则夏令时标志值为正;如果为 非夏令时时间,则该标志值为0;如果此信息不可用,则其值为负。

Single UNIX Specification的以前版本允许双润秒,于是, tm_sec值的有效范围是0~61。
UTC的正式定义不允许双润秒,所以,现在tm_sec值的有效范围定 义为0~60。


time
#include <time.h>
struct tm *gmtime(const time_t *calptr); struct tm *localtime(const time_t *calptr);

两个函数的返回值:指向分解的tm结构的指针;若出错,返回NULL localtime和gmtime之间的区别是:localtime将日历时间转换成本地时
间(考虑到本地时区和夏令时标志),而 gmtime 则将日历时间转换成 协调统一时间的年、月、日、时、分、秒、周日分解结构。
函数mktime以本地时间的年、月、日等作为参数,将其变换成 time_t值。

#include <time.h>
time_t mktime(struct tm *tmptr);

返回值:若成功,返回日历时间;若出错,返回-1

函数strftime是一个类似于printf的时间值函数。它非常复杂,可以
通过可用的多个参数来定制产生的字符串。

#include <time.h>
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
两个较早的函数——asctime和ctime能用于产生一个26字节的可打 印的字符串,类似于date(1)命令默认的输出。然而,这些函数现在已 经被标记为弃用,因为它们易受到缓冲区溢出问题的影响。

strftime_l允许调用者将区域指定为参数,除此之外,strftime和 strftime_l函数是相同的。strftime使用通过TZ环境变量指定的区域。
tmptr参数是要格式化的时间值,由一个指向分解时间值tm结构的 指针说明。格式化结果存放在一个长度为maxsize个字符的buf数组中, 如果buf长度足以存放格式化结果及一个null终止符,则该函数返回在buf 中存放的字符数(不包括null终止符);否则该函数返回0。
format参数控制时间值的格式。如同printf函数一样,转换说明的形 式是百分号之后跟一个特定字符。format中的其他字符则按原样输出。 两个连续的百分号在输出中产生一个百分号。与printf函数的不同之处 是,每个转换说明产生一个不同的定长输出字符串,在format字符串中没有字段宽度修饰符。图6-10中列出了37种ISO C规定的转换说明。

image.png
#include <iostream>
#include <time.h>
#include <sys/time.h>
#include <stdio.h>
#include <string.h>

int main() {
    /* time of timeval. */
    struct timeval now_time;

    int ret = gettimeofday(&now_time, NULL);
    printf("now_time since 1970: %d us, %ld s\n", now_time.tv_usec, now_time.tv_sec);

    /* time of timespec. */
    struct timespec time_spec;

    /* struct of tm*/
    struct tm detail_time;
    struct tm *tm_ptr = &detail_time;

    time_t tmp_time = time(NULL);
    printf("time_t : %ld\n", tmp_time);

    /* gmtime. */
    tm_ptr = gmtime(&tmp_time);


    /* show detail time. */
    printf("year: %d\n, month: %d\n, day: %d\n, hour: %d\n, min: %d\n, second %d\n",
           detail_time.tm_year, 
           detail_time.tm_mon, 
           detail_time.tm_mday, 
           detail_time.tm_hour, 
           detail_time.tm_min, 
           detail_time.tm_sec);

    /* test mktime. */
    tmp_time = mktime(tm_ptr);
    printf("timt_t after mktime %ld\n", tmp_time);

    /* change to localtime. */
    tm_ptr = localtime(&tmp_time);
    /* test strftime. */
    char buf[255];
    strftime(buf, sizeof(buf), "%c", tm_ptr);
    printf("strftime time: %s\n", buf);



    /* time */
    memset(buf, 0, 255);
    strftime(buf, sizeof(buf), "%Y%m%d,%H:%M:%S", tm_ptr);
    printf("time: %s\n", buf);
    return 0;

    /* local time. */
}


image.png
strptime函数是strftime的反过来版本,把字符串时间转换成分解
时间。
#include <time.h>
char *strptime(const char *restrict buf, const char
*restrict format,
              struct tm *restrict tmptr);

所以记得strftime年月日时分秒

%Y-%m-%d %H:%M:%S
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345

推荐阅读更多精彩内容

  • 一.概念 在C/C++中,通过学习许多C/C++库,你可以有很多操作、使用时间的方法。但在这之前你需要了解一些“时...
    小辰带你看世界阅读 1,314评论 0 1
  • 一、Linux时间类型 在Linux系统当中,时间分为两种类型:格林威治时间和日历时间。 Coordinated ...
    konishi5202阅读 3,440评论 0 4
  • 在Python中,日期和时间的应用非常普遍。在实际应用中,大部分数据的记录和日志的处理都需要使用时间。这里将介绍P...
    泷汰泱阅读 865评论 0 0
  • 总结了一些开发中常用的函数: usleep() //函数延迟代码执行若干微秒。 unpack() //函数从二进制...
    ADL2022阅读 454评论 0 3
  • 早上好,周一。转了陈为英500-500。合计1000元。交了尚庄电费。连续2个周末没有休息去了九江,瑞昌,都昌,九江等。
    b538b2ad5da3阅读 136评论 0 0