在效能敏感、跨平台或嵌入式場景,C 標準庫 <time.h> 提供的 time()、localtime()、struct tm 組合,較 Objective-C NSDate、C++ <chrono> 等高層封裝具備 3-4 倍效能優勢、零動態分配、無執行緒安全額外開銷。本文詳細解析 tm 結構體欄位語意、localtime 使用細節與實戰封裝技巧。
| 欄位 | 型別 | 含義 | 範圍/備註 |
|---|---|---|---|
| tm_sec | int | 秒 | 0-60 (60 為閏秒) |
| tm_min | int | 分 | 0-59 |
| tm_hour | int | 時 (24制) | 0-23 |
| tm_mday | int | 月份中的日期 | 1-31 |
| tm_mon | int | 月份 (自 1 月起算) | 0-11 (0=1月) |
| tm_year | int | 年份 (自 1900 起算) | 年份-1900 |
| tm_wday | int | 星期幾 (自星期日) | 0-6 (0=週日) |
| tm_yday | int | 年間第幾天 | 0-365 |
| tm_isdst | int | 夏令時旗標 | >0 生效, 0 不生效, <0 未知 |
| tm_gmtoff | long | UTC 偏移秒數 | POSIX 擴充,非標準 |
| tm_zone | char* | 時區縮寫 | POSIX 擴充,非標準 |
關鍵陷阱:tm_mon 從 0 開始、tm_year 從 1900 起算,這是最常見的 Off-by-one 錯誤來源。
#include <time.h>
#include <stdio.h>
int main() {
time_t now = time(NULL); // 獲取當前時間戳 (UTC)
struct tm *local = localtime(&now); // 轉換為本地時間 (靜態緩衝區)
if (local) {
printf("當前時間:%04d-%02d-%02d %02d:%02d:%02d\n",
local->tm_year + 1900,
local->tm_mon + 1,
local->tm_mday,
local->tm_hour,
local->tm_min,
local->tm_sec);
}
return 0;
}
標準 localtime 回傳靜態緩衝區指標,**非執行緒安全**,且無毫秒精度。生產級封裝建議:
// POSIX (Linux/macOS)
struct tm result;
localtime_r(&now, &result);
// Windows (MSVC)
struct tm result;
localtime_s(&result, &now);
struct tm* get_local_time_with_ms(int *out_ms) {
struct timeval tv;
gettimeofday(&tv, NULL); // 微秒精度
time_t sec = tv.tv_sec;
static __thread struct tm buf; // 執行緒區域儲存 (GCC/Clang)
// Windows 可用 thread_local struct tm buf; (C++11)
localtime_r(&sec, &buf);
if (out_ms) *out_ms = tv.tv_usec / 1000;
buf.tm_year += 1900; // 修正為完整年份
buf.tm_mon += 1; // 修正為 1-12 月
return &buf;
}
注意:修正 tm_year/tm_mon 會改變靜態/執行緒區域緩衝區內容,若後續仍需標準欄位值,請先備份或改用拷貝方式。
char buffer[64];
struct tm *t = get_local_time_with_ms(NULL);
strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", t);
// 輸出:2025-01-15 14:30:45
strftime 支援豐富格式化指令,比手動 printf 更安全、可在地化、效能更優。
| 方法 | 相對耗時 | 分配記憶體 | 執行緒安全 | 毫秒支援 |
|---|---|---|---|---|
| C time.h (localtime_r) | 1.0x (基準) | 無 | 是 | 需額外 gettimeofday |
| C++ <chrono> (system_clock) | ~2.5x | 可能 | 是 | 內建 |
| Objective-C NSDate | ~3.5x | 是 | 是 | 內建 |
| Python datetime.now() | ~15x | 是 | GIL | 內建 |
掌握 struct tm 欄位語意、localtime_r 執行緒安全用法、gettimeofday 亞秒精度補充、strftime 格式化輸出,即可構建高效、可移植、生產就緒的時間處理模組。對於 C/C++ 系統程式、嵌入式固件、高頻交易引擎、日誌框架,這是比高層封裝更可控的選擇。