struct tm定義於 <time.h>,分解時間為人類可讀欄位:
[c]
struct tm {
int tm_sec; // 秒 [0, 60] (含閏秒)
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; // 夏令時標誌
long tm_gmtoff; // UTC 偏移秒 (BSD/GNU 擴展)
char *tm_zone; // 時區縮寫 (BSD/GNU 擴展)
};
[c]
#include
#include // gettimeofday
struct tm* get_local_time() {
struct timeval tv;
gettimeofday(&tv, NULL); // 取得微秒級時間戳
time_t now = tv.tv_sec; // 秒部分
struct tm *local = localtime(&now); // 轉換為本地時間 (靜態緩衝區,非執行緒安全)
// 手動補充毫秒 (標準 tm 無毫秒欄位,借用 tm_gmtoff 或自擴展)
// local->tm_gmtoff = tv.tv_usec / 1000; // 注意:tm_gmtoff 原意是 UTC 偏移,此處僅為演示
// 調整為人類習慣表示
local->tm_year += 1900; // 實際年份
local->tm_mon += 1; // 1-12 月
return local;
}
[objc]
- (struct tm*)getTime {
struct timeval ticks;
gettimeofday(&ticks, nil);
time_t now;
time(&now);
struct tm* timeNow = localtime(&now);
timeNow->tm_gmtoff = ticks.tv_usec / 1000; // 存毫秒 (非標準用法)
timeNow->tm_year += 1900;
timeNow->tm_mon += 1;
return timeNow;
}
localtime 返回指向**靜態內部緩衝區**的指標,多執行緒並發調用會互相覆蓋。解決方案:
localtime_s (Windows) / localtime_r (POSIX) — 需自行提供 struct tm 緩衝區。localtime 依賴系統時區設定 (TZ 環境變數、/etc/localtime)。嵌入式裝置需確保時區數據正確。tm_year 從 1900 起算,tm_mon 0-based,**輸出/存儲前必須修正**,否則極易產生「2024 年變 124 年」、「1 月變 0 月」Bug。struct tm 無亞秒欄位。常見做法:
int tm_msec。struct timespec / struct timeval 並行傳遞。NSDate 快 3-4 倍,屬實。NSDate 涉及物件分配、保留/釋放、格式化器開銷;C 函數僅系統調用 + 簡單運算。[c]
char buf[64];
struct tm *t = get_local_time();
strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", t);
printf("Local time: %s\n", buf);