• 正文
    • 1 與時間相關的定義
    • 2 獲取ISO8601格式的時間
    • 3 計算兩個時間的間隔
    • 3 測試代碼
    • 4 總結(jié)
  • 相關推薦
申請入駐 產(chǎn)業(yè)圖譜

Linux-C++獲取當前時間與計算時間間隔

2024/11/04
2503
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點資訊討論

嵌入式軟件開發(fā)中,有時會用到對日期時間的判斷與處理,比如記錄某個事件發(fā)生的時間,比較某個時刻已過去的時間等等。

記錄時間,可以使用ISO8601國際標準格式的時間,便于與其它軟件交互時做到統(tǒng)一。

本篇就來介紹ISO8601格式時間的生成以及兩個ISO8601格式的時間間隔的計算。

1 與時間相關的定義

在介紹具體的編程實現(xiàn)之前,需要先了解需要用到的一些與時間相關的類型定義與函數(shù)接口

1.1 類型與結(jié)構體

1.1.1 timeval

存儲秒和微秒

struct timeval
{
    long tv_sec; /*秒*/
    long tv_usec; /*微秒*/
};

1.1.2 tm

表示日歷時間格式的時間

struct tm {
        int tm_sec;     /* seconds after the minute - [0,59] 秒*/
        int tm_min;     /* minutes after the hour - [0,59] 分鐘*/
        int tm_hour;    /* hours since midnight - [0,23] 小時*/
        int tm_mday;    /* day of the month - [1,31] 日*/
        int tm_mon;     /* months since January - [0,11],月,使用時一般會加1的偏移量 */
        int tm_year;    /* years since 1900,年,使用時一般會加1900的偏移量 */
        int tm_wday;    /* days since Sunday - [0,6] 周*/
        int tm_yday;    /* days since January 1 - [0,365] */
        int tm_isdst;   /* daylight savings time flag */
};

1.2 函數(shù)

1.2.1 time

time_t time (time_t *time);

參數(shù)可以為空,用于獲取時間戳。

將自1970年1月1日以來經(jīng)過的秒數(shù)存儲在時間戳指針time指向的位置(time為空則不做此處理),并返回相等值的臨時time變量;

1.2.2 gettimeofday

int gettimeofday(struct timeval *tv, struct timezone *tz);

參數(shù)tv不可為空,tz通常不寫默認為空,用于獲取系統(tǒng)時間結(jié)構(struct tm)。

將自1970年1月1日以來經(jīng)過的精度為微秒的時間存儲于tv結(jié)構。獲取時間成功返回0,失敗返回-1。

1.2.3 localtime

struct tm *localtime (const time_t *time);

參數(shù)time不可為空。將時間戳time轉(zhuǎn)換為tm結(jié)構;

1.2.4 localtime_r

struct tm *localtime_r(const time_t *timer, struct tm *buf);

將傳入?yún)?shù)timer表示的秒數(shù)轉(zhuǎn)換為日歷時間格式,保存結(jié)果在buf,同時也會保存結(jié)果一個全局靜態(tài)變量中,返回這全局靜態(tài)變量的指針。

注:

    localtime_r函數(shù)通過傳入tm參數(shù)指針保存轉(zhuǎn)換結(jié)果,使localtime_r函數(shù)線程安全。如果使用localtime_r函數(shù)返回值表示日歷,仍然是線程不安全的,通常僅通過返回值是否為空,判斷l(xiāng)ocaltime_r函數(shù)轉(zhuǎn)換時間是否成功。

2 獲取ISO8601格式的時間

2.1 ISO8601時間格式介紹

國際標準化組織的國際標準ISO 8601是日期和時間的表示方法,全稱為《數(shù)據(jù)存儲和交換形式·信息交換·日期和時間的表示方法》。

最新為ISO8601:2019 ,第一版為ISO8601:1988,第二版為ISO8601:2000。

根據(jù)ISO8601標準,北京時間2024年11月3日16點37分可以表示為:

2024-11-03T16:37:00+08:00

2.1.1 日期格式

標準日期格式為 YYYY-MM-DD,其中:

    YYYY 代表四位數(shù)的年份,如2024;MM 代表兩位數(shù)的月份,范圍01~12;DD 代表兩位數(shù)的日,范圍01~31。

2.1.2 時間格式

完整時間表示為:HH:MM:SS

    HH表示兩位數(shù)的小時,24小時制;MM表示兩位數(shù)的分鐘;SS表示兩位數(shù)的秒;

可進一步精確到毫秒,表示為:HH:MM:SS.sss

2.1.3 日期時間格式

日期和時間的組合表示為:YYYY-MM-DDTHH:MM:SS

    T是日期和時間之間的分隔符

注:

“T” 是一個全球統(tǒng)一且不常見的字符,使用 “T” 可以清楚地區(qū)分日期和時間這兩個不同的概念,避免混淆。

2.1.4 時區(qū)表示

ISO8601支持對時區(qū)的標準化表示,使用Z表示協(xié)調(diào)世界時(UTC),或者使用±hh:mm格式表示與UTC的偏移,例如:

    Z表示 UTC 時間;+08:00表示比 UTC 快8小時的時區(qū);-05:00表示比 UTC 慢5小時的時區(qū);

例如:

    2024-03-19T15:26:00Z表示UTC時間下午3點26分0秒;2024-03-19T15:26:00+08:00表示北京時間下午3點26分0秒;

2.2 編程實現(xiàn)ISO8601時間的獲取

代碼思路如下:

    獲取自1970年1月1日以來經(jīng)過的秒和微秒,存儲在timeval中將秒數(shù)通過localtime_r轉(zhuǎn)換為日歷時間格式結(jié)合日歷時間和微妙數(shù),格式化為ISO8601格式的時間
std::string GetISO8601NowTime()
{
    timeval tv{}; //存儲自1970年1月1日以來經(jīng)過的秒和微秒
    gettimeofday(&tv, nullptr); //獲取自1970年1月1日以來經(jīng)過的秒和微秒
    
    tm stTM{}; //存儲日歷時間格式的時間
    localtime_r(&tv.tv_sec, &stTM); //將傳入?yún)?shù)的秒數(shù)轉(zhuǎn)換為日歷時間格式
    
    char sTmp[64]{}; //格式化為ISO8601格式的時間
    sprintf(sTmp, "%04d-%02d-%02dT%02d:%02d:%02d.%03ld",
                   stTM.tm_year + 1900, stTM.tm_mon + 1, stTM.tm_mday,
                   stTM.tm_hour, stTM.tm_min, stTM.tm_sec, tv.tv_usec/1000);
                   
    return std::string(sTmp) + "+08:00"; //這里時區(qū)暫使用固定的東八區(qū)  
}

3 計算兩個時間的間隔

前面實現(xiàn)了ISO8601時間的獲取,如果有兩個ISO8601格式的時間,如何計算這兩個時間的間隔呢。

在實現(xiàn)該功能前,需要再來介紹需要用到的兩個函數(shù)。

3.1 函數(shù)

3.1.1 strptime

string parse time。parse,解析,用于將string格式的時間解析為tm格式

extern char *strptime (__const char *__restrict __s,
                       __const char *__restrict __fmt, 
					 struct tm *__tp);
    參數(shù)1: 輸入一個char 的指針,可通過c_str()兼容參數(shù)2: 統(tǒng)一為一個char的指針, 用于格式控制的字符串指針,可通過c_str()兼容參數(shù)3: 分解時間的存儲,struct tm類型的指針,可定義一個struct tm類型,然后&實現(xiàn)

strftime:string format time。format,格式。把 time 格式化為 string

3.1.2 mktime

time_t mktime(struct tm *timeptr);

用于將結(jié)構體 struct tm 表示的日歷時間轉(zhuǎn)換為對應的秒數(shù)時間戳。

3.2 編程實現(xiàn)

代碼思路如下:

    將string格式的時間解析為tm格式的日歷時間再將日歷時間轉(zhuǎn)換為對應的秒數(shù)時間戳比較兩個時間戳 的差值即可
time_t ISO8601ToTimeT(std::string &dateTime)
{
    tm stTM{}; 
    //%F是一個代表完整日期的標記,等同于%Y-%m-%d; %T是一個代表完整時間的標記,等同于%H:%M:%S
    strptime(dateTime.c_str(), "%FT%T", &stTM); //將string格式的時間解析為tm格式
    
    time_t t = mktime(&stTM); //將日歷時間轉(zhuǎn)換為對應的秒數(shù)時間戳
    return t;
}

uint64_t TimeDurationSec(std::string &oldT, std::string &newT)
{
    auto oldPoint = std::chrono::system_clock::from_time_t(ISO8601ToTimeT(oldT));
    auto newPoint = std::chrono::system_clock::from_time_t(ISO8601ToTimeT(newT));
    return std::chrono::duration_cast<std::chrono::seconds>(newPoint - oldPoint).count();
}

3 測試代碼

來編寫一個測試代碼來驗證剛才實現(xiàn)的功能。

    先定義一個ISO8601格式的已過去的時間,作為測試時間間隔的old數(shù)據(jù)調(diào)用編寫的GetISO8601NowTime獲取當前的ISO8601格式的時間調(diào)用TimeDurationSec來計算兩個時間的差值,間隔的秒數(shù)以天、小時、分鐘、秒的形式打印出來過去的時間間隔
#include <stdio.h>
#include <ctime>
#include <sys/time.h>
#include <string>
#include <chrono>

//函數(shù)實現(xiàn)參考前面代碼

int main()
{
    std::string t1 = "2024-11-01T17:31:09.000";
    std::string t2 = GetISO8601NowTime();
    printf("t1(old):%snt2(now):%sn", t1.c_str(), t2.c_str());
    
    uint64_t deltaTotalSec = TimeDurationSec(t1, t2);
    uint64_t deltaDay = deltaTotalSec / (3600*24);
    uint32_t deltaHour = deltaTotalSec % (3600*24) / 3600;
    uint32_t deltaMin = deltaTotalSec % 3600 / 60;
    uint32_t deltaSec = deltaTotalSec % 60;
    printf("delta sec:%lu(%lu day, %u hour, %u min, %u sec)n", deltaTotalSec, deltaDay, deltaHour, deltaMin, deltaSec);
    
    return 0;
}

運行結(jié)果如下:

4 總結(jié)

本篇介紹了ISO8601格式時間的生成以及兩個ISO8601格式的時間間隔的計算。首先介紹需要用到的一些函數(shù),然后介紹編程實現(xiàn)的思路,編寫代碼,實現(xiàn)所需的功能,最后進行編譯運行測試。

相關推薦

登錄即可解鎖
  • 海量技術文章
  • 設計資源下載
  • 產(chǎn)業(yè)鏈客戶資源
  • 寫文章/發(fā)需求
立即登錄