ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Linux时间操作全解析:从time_t到字符串的转换与高精度计时

Linux时间操作全解析:从time_t到字符串的转换与高精度计时 1. 从“时间戳”到“人类时间”Linux时间操作的核心逻辑在Linux应用开发里处理时间是个高频且基础的操作。无论是记录日志、定时任务、缓存过期还是分析用户行为你都得跟时间打交道。但很多开发者尤其是刚接触系统编程的朋友常常被一堆时间函数绕晕time、mktime、localtime、gmtime、strftime……它们之间到底什么关系为什么我拿到的time_t打印出来是一串看不懂的数字怎么把它变成“2024-05-27 10:30:00”这种我们能看懂的样子这背后其实是一条清晰的转换链从内核维护的“时间纪元秒数”time_t到分解的“日历时间”struct tm再到可读的“字符串时间”。理解这条链你就能游刃有余地处理所有时间问题。今天我们就来彻底拆解这几个核心函数我会结合实际的代码片段和踩坑经验告诉你它们怎么用以及更重要的——为什么要这么用。2. 时间基石time()函数与time_t的本质一切时间操作的起点通常是time()函数。它的声明很简单#include time.h time_t time(time_t *tloc);这个函数返回自协调世界时UTC1970年1月1日00:00:00这个时刻被称为“Unix纪元”或“Epoch”以来经过的秒数。这个返回值的数据类型就是time_t。你可能会问为什么是1970年这算是计算机历史的一个约定俗成Unix系统在设计时选定了这个时间点作为计时原点。time_t通常是一个长整型long但在64位系统上它足以记录到公元2920亿年左右完全不用担心溢出。关键点一time()的参数。你可以传一个time_t变量的地址进去函数会把同样的值存到这个地址里同时作为返回值。如果你不需要存储直接传NULL就行。我个人的习惯是传NULL因为多定义一个变量就多一个出错的点除非你后续明确需要用到这个变量的地址。关键点二time()的精度是秒。这意味着它不适合需要毫秒或微秒级精度的场景比如性能分析。如果你需要更高精度得求助于clock_gettime()这个我们后面会提一下。来看一个最简单的例子#include stdio.h #include time.h #include unistd.h // 用于sleep() int main() { time_t now_seconds; // 方法1使用返回值 now_seconds time(NULL); printf(Current timestamp (method 1): %ld\n, now_seconds); // 方法2使用参数传地址 time(now_seconds); printf(Current timestamp (method 2): %ld\n, now_seconds); // 让它变化一下 sleep(2); time(now_seconds); printf(Timestamp after 2 seconds: %ld\n, now_seconds); return 0; }运行这段代码你会得到一串像1716800000这样的数字。它毫无可读性但它是所有时间计算的基石因为它是一个绝对的、与时区无关的标量。数据库存储、系统间的时间戳传递用的都是这个。注意time()返回的是UTC时间。这意味着在全球任何一台设置正确的Linux系统上在同一时刻调用time()得到的数字应该是一样的忽略微小的网络时间协议误差。这为分布式系统提供了统一的时间基准。3. 时间的分解与组装localtime/gmtime 与 mktime拿到time_t这个“原始食材”后我们通常需要把它“烹饪”成更易处理的形式。这就是localtime()和gmtime()的工作。它们都接受一个time_t指针返回一个指向struct tm的指针。struct tm这个结构体定义在time.h里它把时间分解成了我们熟悉的年、月、日、时、分、秒等字段struct tm { int tm_sec; // 秒 [0, 60] (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; // 夏令时标志正数表示启用0表示未启用负数表示信息不可用 };3.1 localtime() 与 gmtime() 的核心区别这是第一个容易混淆的点。struct tm *localtime(const time_t *timer): 将time_t转换为本地时间的struct tm。这里的“本地”取决于系统的时区设置由环境变量TZ或系统配置文件如/etc/localtime决定。如果你在中国上海东八区localtime()会把UTC时间加上8小时。struct tm *gmtime(const time_t *timer): 将time_t转换为**UTC格林威治标准时间**的struct tm。这个转换不涉及时区偏移。来看代码对比#include stdio.h #include time.h int main() { time_t rawtime 1716800000; // 假设一个时间戳 struct tm *timeinfo_local, *timeinfo_utc; timeinfo_local localtime(rawtime); timeinfo_utc gmtime(rawtime); printf(Raw timestamp: %ld\n, rawtime); printf(Local time - Hour: %d, GMT offset likely 8\n, timeinfo_local-tm_hour); printf(UTC time - Hour: %d\n, timeinfo_utc-tm_hour); // 注意localtime和gmtime返回的是指向内部静态存储区的指针。 // 这意味着第二次调用会覆盖第一次的结果。 // 下面的操作是危险的 // struct tm *t1 localtime(rawtime); // struct tm *t2 gmtime(rawtime); // 此时t1指向的内容可能已被修改 // printf(t1 hour after gmtime call: %d\n, t1-tm_hour); // 结果不可预期 return 0; }运行后如果系统时区是东八区你很可能会看到localtime的小时数比gmtime的大8。踩坑实录localtime/gmtime的线程安全问题与返回值陷阱上面代码的注释里提到了一个巨坑localtime()和gmtime()返回的指针指向的是一个内部静态分配的缓冲区。这意味着非线程安全在多线程环境下如果多个线程同时调用这些函数它们会竞争修改这个共享缓冲区导致数据混乱。解决方法是使用它们的线程安全版本localtime_r()和gmtime_r()它们需要你提供一个自己分配的struct tm变量来存放结果。返回值会被覆盖连续调用localtime()和gmtime()或者再次调用localtime()都会覆盖之前的结果。所以如果你需要同时保留本地时间和UTC时间必须立即将struct tm的内容复制到自己的变量中或者使用_r系列函数。正确做法struct tm timeinfo_local, timeinfo_utc; localtime_r(rawtime, timeinfo_local); // 安全结果存入timeinfo_local gmtime_r(rawtime, timeinfo_utc); // 安全结果存入timeinfo_utc // 现在可以安全地同时使用timeinfo_local和timeinfo_utc了3.2 mktime()逆向转换与规范化mktime()的作用与localtime()相反。它接受一个指向struct tm的指针将其转换回time_t。但它的功能远不止“逆转”那么简单它还是一个强大的时间规范化工具。mktime()的声明是time_t mktime(struct tm *timeptr);这里有一个至关重要的细节mktime()会将输入的结构体视为本地时间。它根据你提供的tm结构计算出对应的time_tUTC秒数。在这个过程中它会做两件极其有用的事自动计算星期几tm_wday和一年中的第几天tm_yday你只需要正确填写年、月、日、时、分、秒mktime()会自动帮你算出这天是星期几以及是这一年的第几天并填回结构体。规范化超出范围的值这是mktime()最神奇的地方。比如你设置tm_mon12代表13月tm_mday35。mktime()不会报错而是会将这些值规范化。tm_mon12会被视为下一年的1月tm_mday35会根据月份被换算成下个月的某一天。看这个例子#include stdio.h #include time.h int main() { struct tm some_day {0}; // 初始化为0 time_t converted_time; // 设置一个“混乱”的时间2024年第15月第45天 25时70分80秒 some_day.tm_year 2024 - 1900; // 年份要减去1900 some_day.tm_mon 14; // 15月 (0-based) some_day.tm_mday 45; some_day.tm_hour 25; some_day.tm_min 70; some_day.tm_sec 80; some_day.tm_isdst -1; // 让mktime自己判断是否夏令时 printf(Before mktime:\n); printf( Year: %d, Month: %d, Day: %d\n, some_day.tm_year1900, some_day.tm_mon1, some_day.tm_mday); printf( Hour: %d, Min: %d, Sec: %d\n, some_day.tm_hour, some_day.tm_min, some_day.tm_sec); printf( Wday: %d, Yday: %d\n, some_day.tm_wday, some_day.tm_yday); converted_time mktime(some_day); if (converted_time (time_t)-1) { printf(Error: mktime failed.\n); } else { printf(\nAfter mktime (normalized):\n); printf( Timestamp: %ld\n, (long)converted_time); printf( Year: %d, Month: %d, Day: %d\n, some_day.tm_year1900, some_day.tm_mon1, some_day.tm_mday); printf( Hour: %d, Min: %d, Sec: %d\n, some_day.tm_hour, some_day.tm_min, some_day.tm_sec); printf( Wday: %d, Yday: %d\n, some_day.tm_wday, some_day.tm_yday); // 这两个字段被自动计算出来了 } return 0; }运行后你会发现mktime成功地将混乱的日期时间规范化为一个有效的time_t并且tm_wday和tm_yday也被正确填充。这个特性在计算“N天后的日期”或“上个月的最后一天”这类问题时非常方便。经验之谈mktime()的tm_isdst字段处理。这个字段表示夏令时。设置为0表示不考虑夏令时正数表示处于夏令时设置为-1是最省心的做法它告诉mktime“请根据时间和本地规则自行判断当时是否处于夏令时”。这样可以避免因手动设置错误导致的一小时偏差。4. 时间的华丽呈现strftime 与 strptime现在我们有了人类可理解的struct tm但最终展示给用户或者记录到文件里我们需要的往往是字符串。这就轮到strftime()大显身手了。strftime()函数允许你按照指定的格式将struct tm格式的时间转换为一个定制化的字符串。它的原型是size_t strftime(char *str, size_t maxsize, const char *format, const struct tm *timeptr);str: 指向存放结果字符串的缓冲区。maxsize: 缓冲区的最大容量。format: 格式控制字符串类似于printf的格式但由特定的转换说明符组成。timeptr: 指向源struct tm的指针。4.1 strftime 常用格式符格式符非常丰富这里列举最常用的%Y: 四位数的年份如2024%m: 两位数的月份01-12%d: 两位数的日期01-31%H: 24小时制的小时00-23%M: 分钟00-59%S: 秒00-6060用于闰秒%A: 完整的星期几名称如Monday%a: 缩写的星期几名称如Mon%B: 完整的月份名称如January%b或%h: 缩写的月份名称如Jan%c: 标准的日期时间表示如“Tue May 28 14:30:00 2024”%x: 本地标准的日期表示如“05/28/24”%X: 本地标准的时间表示如“14:30:00”%z: 时区偏移如0800%Z: 时区名称或缩写如CST%%: 输出一个%字符示例#include stdio.h #include time.h int main() { time_t rawtime; struct tm *timeinfo; char buffer[80]; time(rawtime); timeinfo localtime(rawtime); // 注意线程安全此处为示例简化 // 格式1: 标准日志格式 strftime(buffer, sizeof(buffer), %Y-%m-%d %H:%M:%S, timeinfo); printf(Log Format: %s\n, buffer); // 输出: 2024-05-28 14:30:00 // 格式2: 带星期和时区 strftime(buffer, sizeof(buffer), %A, %B %d, %Y %I:%M %p %Z, timeinfo); printf(Full Format: %s\n, buffer); // 输出: Tuesday, May 28, 2024 02:30 PM CST // 格式3: 自定义紧凑格式用于文件名 strftime(buffer, sizeof(buffer), backup_%Y%m%d_%H%M%S.tar.gz, timeinfo); printf(Filename: %s\n, buffer); // 输出: backup_20240528_143000.tar.gz return 0; }strftime的强大之处在于其灵活性你可以组合出任何需要的日期时间字符串格式非常适合生成日志时间戳、带时间戳的文件名等。4.2 strptime字符串解析回时间有格式化输出自然也有解析输入。strptime()是strftime()的逆过程它将一个格式化的时间字符串解析并填充到struct tm结构体中。需要注意的是strptime()不是标准C库函数而是POSIX标准的一部分在Glibc中可用。它的原型是char *strptime(const char *s, const char *format, struct tm *tm);s: 要解析的源字符串。format: 描述源字符串格式的字符串使用与strftime类似的转换说明符。tm: 指向待填充的struct tm结构的指针。返回值如果成功返回指向解析完成后剩余字符串的指针如果失败返回NULL。示例解析一个特定格式的字符串#define _XOPEN_SOURCE // 需要定义此宏以启用strptime #include stdio.h #include time.h #include string.h int main() { struct tm parsed_time {0}; char *input 2024-05-28 14:30:25; char *remain; remain strptime(input, %Y-%m-%d %H:%M:%S, parsed_time); if (remain NULL) { printf(Failed to parse time string.\n); } else { printf(Parsed successfully.\n); printf(Year: %d, Month: %d, Day: %d\n, parsed_time.tm_year 1900, parsed_time.tm_mon 1, parsed_time.tm_mday); printf(Hour: %d, Min: %d, Sec: %d\n, parsed_time.tm_hour, parsed_time.tm_min, parsed_time.tm_sec); // 注意strptime通常不会填充tm_wday和tm_yday需要后续用mktime计算 parsed_time.tm_isdst -1; time_t t mktime(parsed_time); printf(Corresponding timestamp: %ld\n, (long)t); } return 0; }strptime在处理配置文件、解析用户输入或日志文件中的时间时非常有用。注意事项strptime的格式字符串必须与输入字符串精确匹配。多余的空格、不匹配的标点都会导致解析失败。对于复杂的、可能不规范的日期字符串有时需要多次调用strptime或结合sscanf进行预处理。5. 高精度时间测量clock_gettime 与计时实践前面讲的time()精度是秒对于测量代码段执行时间、实现高精度定时器来说远远不够。这时就需要clock_gettime()出场。它能提供纳秒级的时间精度。clock_gettime()使用前需要包含time.h并链接-lrt库实时库。它的原型是int clock_gettime(clockid_t clk_id, struct timespec *tp);clk_id: 时钟源标识常用有以下几种CLOCK_REALTIME: 系统实时时间从Epoch开始计时可被系统时间修改如NTP同步影响。CLOCK_MONOTONIC: 单调时钟从系统启动开始计时不受系统时间跳变如手动修改、NTP调整影响最适合用于测量时间间隔。CLOCK_PROCESS_CPUTIME_ID: 本进程消耗的CPU时间。CLOCK_THREAD_CPUTIME_ID: 本线程消耗的CPU时间。tp: 指向struct timespec的指针用于存储获取到的时间。timespec定义如下struct timespec { time_t tv_sec; // 秒 long tv_nsec; // 纳秒 [0, 999999999] };5.1 使用CLOCK_MONOTONIC精确测量耗时这是最常用的场景。我们来写一个测量函数执行时间的例子#define _POSIX_C_SOURCE 199309L // 启用clock_gettime #include stdio.h #include time.h #include unistd.h void expensive_function() { // 模拟一个耗时操作 for (volatile long i 0; i 100000000L; i) { // 空循环消耗CPU时间 } } int main() { struct timespec start, end; long long elapsed_nsec; // 获取开始时间 if (clock_gettime(CLOCK_MONOTONIC, start) -1) { perror(clock_gettime start); return 1; } // 执行要测量的代码 expensive_function(); // 获取结束时间 if (clock_gettime(CLOCK_MONOTONIC, end) -1) { perror(clock_gettime end); return 1; } // 计算耗时纳秒 elapsed_nsec (end.tv_sec - start.tv_sec) * 1000000000LL (end.tv_nsec - start.tv_nsec); printf(Function took %lld nanoseconds.\n, elapsed_nsec); printf(Thats about %.3f milliseconds.\n, elapsed_nsec / 1000000.0); printf(Or about %.6f seconds.\n, elapsed_nsec / 1000000000.0); return 0; }编译时需要链接-lrtgcc -o benchmark benchmark.c -lrt5.2 不同时钟源的对比与选择测量耗时、实现定时器永远首选CLOCK_MONOTONIC。因为它不受系统时间突变的影响。想象一下你正在测量一个算法中途有人手动把系统时间调快了1小时如果用CLOCK_REALTIME你的测量结果就完全错了。而CLOCK_MONOTONIC只关心“物理上过了多久”结果稳定可靠。需要获取当前“日历时间”时用CLOCK_REALTIME。它的作用和time()类似但精度更高。不过要注意它的值可能会因NTP同步或管理员修改而向前或向后跳变。分析程序/线程的CPU使用率时用CLOCK_PROCESS_CPUTIME_ID或CLOCK_THREAD_CPUTIME_ID。它们只计算进程/线程实际在CPU上执行的时间睡眠、等待I/O的时间不计入。这对于性能剖析非常关键。性能剖析小技巧对于非常短的代码段几微秒到几十微秒单次测量可能受系统调度干扰。更准确的做法是循环执行该代码段成千上万次测量总时间后求平均。同时要注意编译器优化对于空循环这类代码编译器可能会直接优化掉导致测量失真。使用volatile变量或调用一个空的asm volatile语句可以防止过度优化。6. 实战构建一个简易的耗时统计工具理解了上述函数我们可以动手写一个实用的工具一个用于统计代码块执行时间的宏。这个工具应该易用、可嵌套、并且输出美观。#define _POSIX_C_SOURCE 199309L #include stdio.h #include time.h #include string.h // 定义一个简单的计时器结构 typedef struct { struct timespec start; struct timespec end; const char *tag; } timer_t; // 开始计时 static inline void timer_start(timer_t *t, const char *tag) { t-tag tag; clock_gettime(CLOCK_MONOTONIC, (t-start)); } // 结束计时并打印结果 static inline void timer_end(timer_t *t) { clock_gettime(CLOCK_MONOTONIC, (t-end)); long long elapsed (t-end.tv_sec - t-start.tv_sec) * 1000000000LL (t-end.tv_nsec - t-start.tv_nsec); const char *unit ns; double value (double)elapsed; // 自动选择合适的单位 if (elapsed 1000000000) { // 1秒 unit s; value elapsed / 1000000000.0; } else if (elapsed 1000000) { // 1毫秒 unit ms; value elapsed / 1000000.0; } else if (elapsed 1000) { // 1微秒 unit us; value elapsed / 1000.0; } // 否则用纳秒 printf([TIMER] %-20s: %.3f %s\n, t-tag, value, unit); } // 示例模拟一个多级任务 void process_data() { timer_t total_timer, stage1_timer, stage2_timer; timer_start(total_timer, Total Process); // 阶段1数据加载 timer_start(stage1_timer, Stage1-Load); // 模拟加载耗时 struct timespec sleep_time {0, 50000000}; // 50毫秒 nanosleep(sleep_time, NULL); timer_end(stage1_timer); // 阶段2数据计算 timer_start(stage2_timer, Stage2-Compute); // 模拟计算耗时 for (volatile long i 0; i 50000000L; i) {} timer_end(stage2_timer); timer_end(total_timer); } int main() { printf( Code Block Profiling \n); process_data(); return 0; }这个工具的优点使用CLOCK_MONOTONIC结果稳定。自动换算单位根据耗时长短显示纳秒、微秒、毫秒或秒阅读友好。支持嵌套和标签可以清晰地对复杂流程进行分段计时。接口简单timer_start和timer_end成对使用即可。在实际项目中你可以将这个计时器模块化或者与日志系统结合方便地进行性能瓶颈分析。7. 时区与夏令时处理环境变量TZ与tzset我们之前提到localtime()的转换依赖于系统的时区设置。在Linux中时区信息通常由环境变量TZ或系统文件如/etc/localtime软链接决定。程序可以通过tzset()函数来根据当前环境重新初始化时区转换信息。7.1 TZ环境变量TZ变量的格式可以是多种常见的一种是标准时区缩写与UTC的偏移例如export TZUTC使用协调世界时无偏移。export TZEST5使用美国东部标准时间比UTC晚5小时。export TZCST-8理论上表示比UTC早8小时但更复杂的格式如CST-8CDT,M3.2.0/2,M11.1.0/2可以指定夏令时规则。不过现代系统更推荐使用时区数据库中的名称。export TZAsia/Shanghai使用IANA时区数据库中的名称位于/usr/share/zoneinfo/这是最推荐的方式因为它包含了完整的夏令时历史规则。7.2 在程序中控制时区如果你的程序需要在不同时区下运行或者临时切换时区进行计算可以在程序中操作。#include stdio.h #include stdlib.h #include time.h void print_local_time(time_t t) { struct tm *lt localtime(t); char buf[64]; strftime(buf, sizeof(buf), %Y-%m-%d %H:%M:%S %Z, lt); printf(Local: %s\n, buf); } int main() { time_t now time(NULL); char *old_tz; // 保存旧的TZ环境变量 old_tz getenv(TZ); if (old_tz) old_tz strdup(old_tz); // 复制一份 printf(Original timezone:\n); print_local_time(now); // 临时切换到UTC printf(\nSwitching to UTC:\n); setenv(TZ, UTC, 1); // 1表示覆盖现有值 tzset(); // 关键使时区设置生效 print_local_time(now); // 临时切换到纽约时间 (美国东部时间含夏令时规则) printf(\nSwitching to America/New_York:\n); setenv(TZ, America/New_York, 1); tzset(); print_local_time(now); // 恢复原始时区 if (old_tz) { setenv(TZ, old_tz, 1); free(old_tz); } else { unsetenv(TZ); } tzset(); printf(\nRestored to original:\n); print_local_time(now); return 0; }关键函数tzset()在调用setenv修改了TZ环境变量后必须调用tzset()。这个函数会重新读取TZ变量并初始化localtime等函数内部使用的时区转换规则。如果不调用tzset()时区切换不会生效。重要提醒修改环境变量尤其是TZ可能会影响整个进程内所有线程对localtime的调用。如果只是局部代码需要特定时区更安全、更现代的做法是使用localtime_r获取UTC时间gmtime_r然后自己根据时区规则进行加减小时运算或者使用更专业的时区库如ICU。在多线程程序中全局修改TZ是危险的。8. 常见陷阱与最佳实践总结最后我们来梳理一下在Linux时间操作中那些容易踩的坑以及应该如何避免。8.1 线程安全是头等大事再次强调localtime()、gmtime()、ctime()、asctime()这些返回指针的函数都是非线程安全的因为它们使用内部静态缓冲区。解决方案始终使用它们的_r后缀版本可重入版本localtime_r()、gmtime_r()、ctime_r()、asctime_r()。它们需要一个额外的缓冲区参数。struct tm my_tm; time_t t time(NULL); localtime_r(t, my_tm); // 安全8.2 正确处理mktime的时区与夏令时mktime()将输入struct tm解释为本地时间。如果你有一个UTC时间的struct tm直接调用mktime()会得到错误的结果。你需要先手动调整小时字段或者使用timegm()函数GNU扩展非标准。设置tm_isdst -1让系统自动判断是最省心且通常最准确的做法。8.3 精度与时钟源的选择需要“墙上时钟”日历时间时用time()或clock_gettime(CLOCK_REALTIME, ...)。需要测量时间间隔、实现定时器时无条件选择clock_gettime(CLOCK_MONOTONIC, ...)。这是保证测量不受系统时间调整影响的唯一方法。8.4 时间字符串格式的兼容性strftime产生的格式是区域设置locale相关的。例如%x、%X、月份和星期名称等。如果你的程序需要在不同语言环境的系统上运行并且要求固定的输出格式如日志请避免使用这些与locale相关的说明符明确使用%Y-%m-%d %H:%M:%S这样的格式。同理使用strptime解析用户输入时也要考虑格式的严格性做好错误处理。8.5 时间值的溢出与范围检查虽然time_t在64位系统上范围极大但在与32位系统交互或进行时间算术如t 1000000000时仍需注意溢出问题。使用difftime()函数计算两个time_t的差值返回double类型的秒数比直接相减更安全。为struct tm的字段赋值时虽然mktime()能规范化但最好还是赋予合理的值避免依赖规范化行为导致理解上的混淆。8.6 一个综合性的安全时间处理示例下面是一个集成了线程安全、错误检查、格式化的完整函数示例用于获取当前时间的字符串#include stdio.h #include time.h #include string.h #include errno.h int get_current_time_string(char *buf, size_t buf_size, const char *fmt) { if (buf NULL || fmt NULL || buf_size 1) { errno EINVAL; return -1; } time_t rawtime; struct tm timeinfo; // 1. 获取当前时间戳 if (time(rawtime) (time_t)-1) { perror(time() failed); return -1; } // 2. 转换为本地时间线程安全 if (localtime_r(rawtime, timeinfo) NULL) { perror(localtime_r() failed); return -1; } // 3. 格式化为字符串 if (strftime(buf, buf_size, fmt, timeinfo) 0) { // 缓冲区可能太小 fprintf(stderr, strftime failed: buffer too small or format error.\n); errno EOVERFLOW; return -1; } return 0; // 成功 } int main() { char time_buf[64]; const char *format %Y-%m-%d %H:%M:%S %Z (Week %A); if (get_current_time_string(time_buf, sizeof(time_buf), format) 0) { printf(Current time: %s\n, time_buf); } else { printf(Failed to get current time.\n); } return 0; }掌握从time_t到struct tm再到字符串这条主线理解每个函数的行为、陷阱和适用场景你就能在Linux应用开发中从容应对绝大多数时间相关的任务。记住核心原则获取间隔用单调时钟转换时间注意时区处理字符串严格匹配多线程环境务必使用_r版本。把这些点做到位时间操作就不会再成为你程序中的“暗坑”。
返回列表