首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C語言時間日期處理完全指南:從基礎API到高級運算

     編輯:關於C語言

標準庫核心類型與函數

<time.h> 提供時間處理的核心設施:

  • time_t:日曆時間編碼(通常為自紀元以來的秒數,long或int64_t)。
  • struct tm:分解時間結構體,包含秒、分、時、日、月(0-11)、年(從1900起)、周日(0-6)、年日(0-365)、夏令時標誌。
  • clock_t:處理器時間計數。

關鍵函數速查

函數功能備註
time(time_t *t)獲取當前日曆時間參數非NULL時也寫入指向位置
localtime(const time_t *t)轉換為本地時間tm返回靜態結構體指針,非線程安全
gmtime(const time_t *t)轉換為UTC時間tm同上
mktime(struct tm *tp)將tm轉為time_t並修正字段自動處理溢出(如月份>12),返回-1表示錯誤
asctime(const struct tm *tp)格式化為固定字符串「Www Mmm dd hh:mm:ss yyyy\n\0」返回靜態緩衝區
ctime(const time_t *t)等價於asctime(localtime(t))
strftime(char *s, size_t max, const char *fmt, const struct tm *tp)自定義格式化輸出返回寫入字符數,支持豐富格式符(見下表)
difftime(time_t t1, time_t t0)計算兩時間差(秒),返回double處理time_t可能非算術類型的情況
clock()返回進程CPU時間除以CLOCKS_PER_SEC得秒數

strftime 常用格式符

符號含義示例
%Y完整年份2024
%m月份(01-12)03
%d日期(01-31)15
%H24制小時(00-23)14
%M分鐘(00-59)30
%S秒(00-60)05
%F等價%Y-%m-%d2024-03-15
%T等價%H:%M:%S14:30:05
%z時區偏移+0800
%sUnix時間戳(擴展)1710484205

時間運算實戰技巧

1. 日期加減(利用mktime自動修正)

struct tm dt = *localtime(&now);
dt.tm_mday += 30;          // 30天后
dt.tm_mon  -= 3;           // 3個月前
mktime(&dt);               // 自動修正月份/年份溢出
printf("%s", asctime(&dt));

2. 計算兩日期天數差(不依賴difftime秒精度)

// 簡化版:忽略時區/夏令時,假設同一時區午夜
double days_between(struct tm a, struct tm b) {
    a.tm_hour = b.tm_hour = 12; // 避免夏令時邊界問題
    time_t ta = mktime(&a), tb = mktime(&b);
    return fabs(difftime(ta, tb)) / 86400.0;
}

3. 高精度計時(基準測試)

struct timespec start, end;
clock_gettime(CLOCK_MONOTONIC, &start);
// ... 待測代碼 ...
clock_gettime(CLOCK_MONOTONIC, &end);
double elapsed_ms = (end.tv_sec - start.tv_sec) * 1e3 + 
                    (end.tv_nsec - start.tv_nsec) / 1e6;

注意:clock_gettime 需 POSIX(Linux/macOS),Windows 使用 QueryPerformanceCounter。

文件時間戳訪問

ANSI C無標準文件時間API,平台方案如下:

  • POSIX (Linux/macOS):stat()/fstat()/lstat() 獲取 st_atime、st_mtime、st_ctime(time_t)。
  • Windows:GetFileTime() 獲取 FILETIME(100ns間隔自1601年),需轉換為time_t。
  • C++17 <filesystem>:last_write_time(path) 統一跨平台訪問(C++20支持讀/寫)。

常見陷阱與最佳實踐

  1. 線程安全:localtime/gmtime/asctime/ctime 返回靜態緩衝區,多線程必須用 localtime_r/gmtime_r (POSIX) 或 localtime_s (C11 Annex K/Windows)。
  2. 年份表示:tm_year = 年份 - 1900,打印時必須 +1900。
  3. 月份範圍:tm_mon = 0-11,顯示/輸入時 ±1。
  4. 夏令時 (DST):tm_isdst >0 表示生效,<0 表示未知(讓mktime判斷),mktime會自動調整。跨DST邊界計算差值時,difftime給出真實秒差,mktime修正後的tm反映本地鐘面時間。
  5. time_t範圍:32位系統time_t為有符號32位整數,範圍1901-12-13 至 2038-01-19(Y2038問題)。64位系統已遷移至64位time_t,範圍擴展至數十億年。新代碼應假設64位,或使用int64_t顯式存儲時間戳。
  6. 時區處理:全局tzset()/環境變量TZ影響localtime。嵌入式/跨時區應用建議使用 date/tz (Howard Hinnant) 或 boost::local_time / std::chrono::tzdb (C++20)。

現代C++替代方案:<chrono>

C++11 <chrono> 提供類型安全、精度可控的時間庫;C++20 引入 std::chrono::sys_time、zoned_time、format、parse,實現編譯期檢查、時區感知、無縫格式化,是新項目首選。

// C++20 示例
auto now = std::chrono::system_clock::now();
std::cout << std::format("{:%Y-%m-%d %H:%M:%S %Z}", 
              std::chrono::zoned_time{std::chrono::current_zone(), now});
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved