加入星計(jì)劃,您可以享受以下權(quán)益:

  • 創(chuàng)作內(nèi)容快速變現(xiàn)
  • 行業(yè)影響力擴(kuò)散
  • 作品版權(quán)保護(hù)
  • 300W+ 專業(yè)用戶
  • 1.5W+ 優(yōu)質(zhì)創(chuàng)作者
  • 5000+ 長期合作伙伴
立即加入
  • 正文
    • 1 linux獲取時區(qū)
    • 2 ISO8601格式時間增加時間
    • 3 總結(jié)
  • 相關(guān)推薦
  • 電子產(chǎn)業(yè)圖譜
申請入駐 產(chǎn)業(yè)圖譜

Linux中時區(qū)獲取與ISO8601時間完善

11/18 13:10
352
閱讀需 14 分鐘
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點(diǎn)資訊討論

上篇文章:Linux-C++獲取當(dāng)前時間與計(jì)算時間間隔,介紹了ISO8601格式時間的生成,但未包含時區(qū)部分。

本篇,來介紹時區(qū)部分的獲取。

1 linux獲取時區(qū)

1.1 編程實(shí)現(xiàn)

Linux系統(tǒng)中,可以通過localtime來獲取時間,并通過tm_gmtoff來獲取時區(qū)偏移量,進(jìn)而得到時區(qū)。

std::string GetTimeZone() 
{
    // 獲取當(dāng)前時間結(jié)構(gòu)體
    time_t currentTime;
    time(&currentTime);

    // 將時間結(jié)構(gòu)體轉(zhuǎn)換為本地時間結(jié)構(gòu)體
    struct tm *localTime = localtime(&currentTime);

    // 獲取時區(qū)偏移量(以秒為單位)
    int timezoneOffset = localTime->tm_gmtoff;

    // 根據(jù)偏移量計(jì)算時區(qū)差值(以小時為單位)
    int timezoneDiffHours = timezoneOffset / 3600;
    int timezoneDiffMinutes = (timezoneOffset % 3600) / 60;
    
    // 輸出時區(qū)信息
    char tmpBuff[32] = {0};
    sprintf(tmpBuff, "%1s%02d:%02d", timezoneOffset>=0 ? "+" : "-", std::abs(timezoneDiffHours), std::abs(timezoneDiffMinutes));
    std::string timeZone = std::string(tmpBuff);

    return timeZone;
}

int main() 
{
    printf("%sn", GetTimeZone().c_str());

    return 0;
}

測試結(jié)果如下:

1.2 修改linux系統(tǒng)時區(qū)

中國的時區(qū)為東八區(qū),Linux系統(tǒng)中,可以通過一些指令來修改時區(qū)。我們可以修改時區(qū)候,再來驗(yàn)證下剛才編寫的函數(shù)功能。

1.2.1 查看當(dāng)前時區(qū)

timedatectl指令可以查看當(dāng)前設(shè)置的時區(qū)

xxpcb@xxpcb-ubuntu20:~/myTest/cpp/linux/Time$ timedatectl
               Local time: 日 2024-11-17 15:08:43 CST
           Universal time: 日 2024-11-17 07:08:43 UTC
                 RTC time: 日 2024-11-17 07:08:43    
                Time zone: Asia/Shanghai (CST, +0800)
System clock synchronized: yes                       
              NTP service: active                    
          RTC in local TZ: no

1.2.2 查看時區(qū)列表

timedatectl list-timezones指令可以查看支持的時區(qū)

xxpcb@xxpcb-ubuntu20:~/myTest/cpp/linux/Time$ timedatectl list-timezones
Africa/Abidjan
#省略...
Africa/Cairo
#省略...
America/New_York
#省略...
Antarctica/Vostok
#省略...
Asia/Shanghai
#省略...

1.2.3 修改時區(qū)

timedatectl set-timezone指令可以修改時區(qū),并立即生效

timedatectl set-timezone Africa/Cairo
timedatectl set-timezone America/New_York
timedatectl set-timezone Asia/Shanghai

1.3 測試結(jié)果

測試結(jié)果如下,測試了3個不同的時區(qū),并運(yùn)行編寫的時區(qū)獲取函數(shù)查看運(yùn)行結(jié)果:

2 ISO8601格式時間增加時間

上篇文章,編寫了GetISO8601NowTime()來獲取ISO8601格式的時間,并通過ISO8601ToTimeT()來將ISO8601格式的時間轉(zhuǎn)換為time_t格式的時間,用于計(jì)算兩個ISO8601格式時間的時間差。這兩個接口都是沒有對時區(qū)進(jìn)行處理的。

下面,繼續(xù)來實(shí)現(xiàn)兩個有對時區(qū)進(jìn)行處理的接口,從而實(shí)現(xiàn)對于時區(qū)有區(qū)分要求的函數(shù)功能。

2.1 編程實(shí)現(xiàn)

    GetISO8601NowTimeWithTimeZone()用來獲取ISO8601格式的時間,通過追加時區(qū)信息來實(shí)現(xiàn)帶有時區(qū)信息的ISO8601格式時間ISO8601WithTimeZoneToTimeT()先對沒有時區(qū)的部分轉(zhuǎn)換,然后對時區(qū)部分進(jìn)行轉(zhuǎn)換,這里先使用正則表達(dá)式,來檢查輸入的時間格式是否正確,然后對時區(qū)中的正負(fù)號,小時和分鐘的偏移量進(jìn)行處理,最后將兩個部分的時間進(jìn)行疊加
std::string GetISO8601NowTimeWithTimeZone()
{
    return GetISO8601NowTime() + GetTimeZone();
}

time_t ISO8601WithTimeZoneToTimeT(std::string &dateTime)
{
    time_t t = ISO8601ToTimeT(dateTime); //先對沒有時區(qū)的部分轉(zhuǎn)換
    
    std::string pattern{".*([-+])([0-1][0-9]):([0-5][0-9])"}; //+08:00
    try
    {
        std::regex re(pattern); //正則表達(dá)式檢查時間格式是否正確
        std::smatch result;
        if (!std::regex_match(dateTime, result, re))
        {
            printf("[%s] regex not matchn", __func__);
            return 0;
        }
        
        //再對時區(qū)進(jìn)行轉(zhuǎn)換
        std::string zone = result[1].str(); //提取的時區(qū)
        int hour = std::stoi(result[2].str()); //提取的時區(qū)中的小時
        int minute = std::stoi(result[3].str()); //提取的時區(qū)中的分析
        int s = hour * 3600 + minute * 60;
        if ("-" == zone) s = 0 - s;
        
        return t + s;
    }
    catch(std::regex_error &e)
    {
        printf("[%s] regex err:%dn", __func__, e.code());
        return 0;
    }
}

2.2 正則表達(dá)式分析

首先來看定義的一個正則表達(dá)式模式的含義:

std::string pattern{".*([-+])([0-1][0-9]):([0-5][0-9])"}; //+08:00

這里定義了一個正則表達(dá)式模式 pattern,用于匹配包含時區(qū)信息的字符串:

.*:表示匹配任意字符零次或多次,這是為了允許在時區(qū)信息之前可以有其他任意內(nèi)容(比如完整的日期時間字符串中的日期部分等)

([-+]):這是一個捕獲組,用于捕獲時區(qū)的正負(fù)標(biāo)識,即+-

([0-1][0-9]):也是一個捕獲組,用于捕獲時區(qū)中的小時數(shù),它限制小時數(shù)的范圍是從0019(因?yàn)榈谝晃粩?shù)字只能是01,第二位數(shù)字可以是09),不過按照常見的時區(qū)偏移量,實(shí)際上一般不會出現(xiàn)大于14的情況(UTC + 14 是常見的最大偏移量)

([0-5][0-9]):同樣是捕獲組,用于捕獲時區(qū)中的分鐘數(shù),它限制分鐘數(shù)在0059之間,并且按照常規(guī),分鐘數(shù)通常是15的倍數(shù)(如0015、30、45),但這里的正則表達(dá)式允許任意0059的分鐘數(shù)

然后看下提取時區(qū)信息并轉(zhuǎn)換為秒偏移量:

std::string zone = result[1].str(); //提取的時區(qū)
int hour = std::stoi(result[2].str()); //提取的時區(qū)中的小時
int minute = std::stoi(result[3].str()); //提取的時區(qū)中的分析
int s = hour * 3600 + minute * 60;
if ("-" == zone) s = 0 - s;

這里:

    • 通過result[1].str()、
    • result[2].str()
    • 和result[3].str()
    • 分別提取出正則表達(dá)式匹配結(jié)果中的時區(qū)正負(fù)標(biāo)識、小時數(shù)和分鐘數(shù)然后計(jì)算出以秒為單位的時間偏移量s,
    • 先將小時數(shù)乘以3600
      • (因?yàn)橐恍r有3600秒),再將分鐘數(shù)乘以60
      • (因?yàn)橐环昼娪?0秒),兩者相加得到總的時間偏移量如果時區(qū)標(biāo)識為-,則將計(jì)算出的偏移量取相反數(shù),以正確反映與 UTC 時間的負(fù)偏移關(guān)系

2.3 測試結(jié)果

測試函數(shù),有一個固定的舊時間,然后獲取當(dāng)前時間,計(jì)算兩個時間的時間差

int main()
{
    std::string t1 = "2024-11-17T15:31:09.000-06:00";
    std::string t2 = GetISO8601NowTimeWithTimeZone();
    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é)果如下:

3 總結(jié)

本篇介紹了通過編程實(shí)現(xiàn)linux系統(tǒng)中時區(qū)的獲取,并完善上篇的ISO8601格式時間的生成,增加了時區(qū)的處理。

相關(guān)推薦

電子產(chǎn)業(yè)圖譜

控制科學(xué)與工程碩士,日常分享單片機(jī)、嵌入式、C/C++、Linux等學(xué)習(xí)經(jīng)驗(yàn)干貨~