C時間函式strftime、struct timespec 和 struct timeval

新時代的碼農發表於2023-05-18

由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給出了標準值。

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;}

當時鍾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

要對特定的時鐘設定時間,可以呼叫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字串中沒有欄位寬度修飾符。

#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. */}
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

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70030103/viewspace-2953022/,如需轉載,請註明出處,否則將追究法律責任。