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

C 語言時間日期處理完整指南:time.h 標準庫、時間運算、文件時間戳與跨平台實踐

     編輯:關於C語言

C 語言時間日期處理完整指南

ANSI C <time.h> 提供完整的時間獲取、解碼、格式化、運算功能。本文系統梳理核心數據結構、標準函數、時間運算技巧、文件時間戳獲取、跨平台注意事項,並提供可直接使用的代碼模板。

核心數據結構


struct tm {
    int tm_sec;   // 秒 [0,61] (含閏秒)
    int tm_min;   // 分 [0,59]
    int tm_hour;  // 時 [0,23]
    int tm_mday;  // 日 [1,31]
    int tm_mon;   // 月 [0,11] (0=一月)
    int tm_year;  // 年 (從1900起)
    int tm_wday;  // 星期 [0,6] (0=星期日)
    int tm_yday;  // 年內天數 [0,365]
    int tm_isdst; // 夏令時標志 (>0 生效, 0 未生效, <0 未知)
};

核心函數速查表

函數功能關鍵說明
time()獲取日曆時間 (time_t)參數為 NULL 時返回值;非 NULL 時也寫入參數指向位置
localtime()time_t → 本地時間 tm返回**靜態結構體指針**,非線程安全,不可多線程共用
gmtime()time_t → UTC 時間 tm同 localtime,返回靜態結構體
ctime()time_t → 固定格式字符串等價 asctime(localtime(&t)),返回靜態緩衝區
asctime()tm → 固定格式字符串返回靜態緩衝區
strftime()tm → 自定義格式字符串**線程安全**,緩衝區由調用者提供,格式化符見下表
mktime()本地時間 tm → time_t**修正 tm 字段越界值** (如月=12→年+1,月=0),更新 wday/yday
difftime()兩 time_t 差值 (秒)返回 double,避免 time_t 可能為無符號類型導致的溢出

strftime 格式化符完整表

符號含義示例
%Y四位年份2024
%m兩位月份01-12
%d兩位日期01-31
%H24制小時00-23
%M分鐘00-59
%S秒00-61
%A完整星期名Monday
%B完整月份名January
%c標準日期時間Mon Jan 01 12:00:00 2024
%x標準日期01/01/2024
%X標準時間12:00:00
%Z時區名CST
%%字面 %%

時間運算實戰模板

1. 計算未來/過去日期


struct tm t = *localtime(&now);
t.tm_mday += 30;          // 30 天后
mktime(&t);               // 自動修正月份/年份溢出
printf("30 days later: %s", asctime(&t));

2. 程序執行耗時測量


time_t start = time(NULL);
// ... 執行任務 ...
time_t end = time(NULL);
printf("Elapsed: %.0f seconds\n", difftime(end, start));

3. 精確日期差計算 (年/月/日) — 不依賴 time_t 範圍


typedef struct { int year, month, day; } Date;

Date date_diff(Date earlier, Date later) {
    Date diff = {0,0,0};
    // 日差
    diff.day = later.day - earlier.day;
    if (diff.day < 0) {
        // 借位:上個月天數
        int prev_month = (later.month == 1) ? 12 : later.month - 1;
        int prev_year = (later.month == 1) ? later.year - 1 : later.year;
        diff.day += days_in_month(prev_year, prev_month);
        later.month--;
    }
    // 月差
    diff.month = later.month - earlier.month;
    if (diff.month < 0) {
        diff.month += 12;
        later.year--;
    }
    // 年差
    diff.year = later.year - earlier.year;
    return diff;
}

文件時間戳獲取 (跨平台)

ANSI C 無標準文件時間 API。POSIX stat() / Windows _stat() / GetFileTime() 是主流方案。

POSIX/Linux/macOS


#include 
#include 

time_t get_file_mtime(const char *path) {
    struct stat st;
    if (stat(path, &st) == 0) return st.st_mtime;
    return (time_t)-1;
}

Windows (MSVC)


#include 
#include 

time_t get_file_mtime(const char *path) {
    struct _stat st;
    if (_stat(path, &st) == 0) return st.st_mtime;
    return (time_t)-1;
}

比較兩文件新舊


int is_newer(const char *file1, const char *file2) {
    time_t t1 = get_file_mtime(file1);
    time_t t2 = get_file_mtime(file2);
    return (t1 != (time_t)-1 && t2 != (time_t)-1) && difftime(t1, t2) > 0;
}

Touch 文件 (更新時間戳)


int touch_file(const char *path) {
    FILE *f = fopen(path, "r+b"); // 二進制讀寫,不截斷
    if (!f) f = fopen(path, "wb"); // 不存在則創建
    if (!f) return -1;
    // 寫入首字節 (不改變內容) 觸發時間戳更新
    fseek(f, 0, SEEK_SET);
    int ch = fgetc(f);
    fseek(f, 0, SEEK_SET);
    fputc(ch, f);
    fclose(f);
    return 0;
}

線程安全最佳實踐

  • **禁用** localtime/gmtime/ctime/asctime (返回靜態緩衝區)
  • **使用** localtime_r (POSIX) / localtime_s (C11/MSVC) — 調用者提供 struct tm 緩衝區
  • strftime 天然線程安全 (用戶提供緩衝區)

時區處理

  • 環境變量 TZ 控制 localtime 行為
  • setenv("TZ", "Asia/Shanghai", 1); tzset(); (POSIX)
  • Windows: _putenv("TZ=GMT-8"); _tzset();
  • 現代應用建議:內部統一用 UTC (time_t/gmtime),僅在顯示層按用戶時區格式化

掌握 time.h 核心結構與函數、strftime 格式化、mktime 修正特性、跨平台 stat 獲取文件時間、線程安全 API 選擇,即可應對 99% 的 C 語言時間日期處理需求。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved