下面我将详细介绍几种常见的转换方法,从最基本到更灵活的用法。

(图片来源网络,侵删)
核心函数
主要涉及 <time.h> 中的以下几个函数:
time_t time(time_t *t): 获取当前的 Unix 时间戳。struct tm *localtime(const time_t *timer): 将time_t(时间戳)转换为本地时间的struct tm结构体。struct tm *gmtime(const time_t *timer): 将time_t(时间戳)转换为 UTC (GMT) 时间的struct tm结构体。char *asctime(const struct tm *timeptr): 将struct tm结构体转换为易读的字符串(格式固定,如 "Wed Jun 30 21:49:08 1993\n")。size_t strftime(char *str, size_t maxsize, const char *format, const struct tm *timeptr): 最推荐,将struct tm结构体按照你指定的格式转换为字符串,非常灵活。
使用 localtime 和 asctime(简单但不灵活)
这是最直接的方法,但缺点是输出的格式是固定的,无法自定义。
#include <stdio.h>
#include <time.h>
int main() {
// 1. 假设我们有一个 Unix 时间戳
time_t timestamp = 1678886400; // 对应北京时间 2025-03-15 08:00:00
// 2. 使用 localtime 将时间戳转换为本地时间的 tm 结构体
// 注意:localtime 不是线程安全的,在多线程程序中应使用 localtime_r
struct tm *local_tm = localtime(×tamp);
if (local_tm == NULL) {
perror("localtime failed");
return 1;
}
// 3. 使用 asctime 将 tm 结构体转换为字符串
// asctime 会返回一个类似 "Wed Mar 15 08:00:00 2025\n" 的字符串
char *time_str = asctime(local_tm);
// 4. 打印结果
printf("Unix Timestamp: %ld\n", timestamp);
printf("Converted Time (using asctime): %s", time_str); // 注意 asctime 会自带换行符
return 0;
}
输出:
Unix Timestamp: 1678886400
Converted Time (using asctime): Wed Mar 15 08:00:00 2025
使用 localtime 和 strftime(推荐,最灵活)
这是最常用和最推荐的方法,因为它允许你完全自定义输出日期和时间的格式。

(图片来源网络,侵删)
strftime 的格式化字符( 开头)与 printf 类似,但专门用于时间:
%Y: 4位年份 (e.g., 2025)%m: 2位月份 (01-12)%d: 2位日期 (01-31)%H: 24小时制的小时 (00-23)%M: 分钟 (00-59)%S: 秒 (00-60)%F: 等同于%Y-%m-%d%T: 等同于%H:%M:%S- 等等...
#include <stdio.h>
#include <time.h>
int main() {
// 1. 定义一个 Unix 时间戳
time_t timestamp = 1678886400; // 2025-03-15 08:00:00 UTC
// 2. 定义一个足够大的字符数组来存储结果字符串
char time_str[80];
// 3. 使用 localtime 将时间戳转换为 tm 结构体
struct tm *local_tm = localtime(×tamp);
if (local_tm == NULL) {
perror("localtime failed");
return 1;
}
// 4. 使用 strftime 进行格式化转换
// 格式: "YYYY-MM-DD HH:MM:SS"
// strftime 会返回写入的字符数,如果空间不足则返回 0
if (strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S", local_tm) == 0) {
printf("strftime failed: buffer too small or other error.\n");
return 1;
}
// 5. 打印结果
printf("Unix Timestamp: %ld\n", timestamp);
printf("Converted Time (using strftime): %s\n", time_str);
// --- 更多格式化示例 ---
// 格式: "Wednesday, March 15, 2025"
strftime(time_str, sizeof(time_str), "%A, %B %d, %Y", local_tm);
printf("Formatted as (Day, Month Name, Year): %s\n", time_str);
return 0;
}
输出:
Unix Timestamp: 1678886400
Converted Time (using strftime): 2025-03-15 08:00:00
Formatted as (Day, Month Name, Year): Wednesday, March 15, 2025
处理 UTC 时间(使用 gmtime)
如果你的时间戳代表的是 UTC 时间,并且你想直接显示 UTC 时间(而不是转换为本地时区),应该使用 gmtime 而不是 localtime。
#include <stdio.h>
#include <time.h>
int main() {
// 这个时间戳代表 2025-03-15 08:00:00 UTC
time_t timestamp = 1678886400;
// 使用 gmtime 转换为 UTC 的 tm 结构体
struct tm *utc_tm = gmtime(×tamp);
if (utc_tm == NULL) {
perror("gmtime failed");
return 1;
}
char time_str[80];
// 格式化并打印 UTC 时间
strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S UTC", utc_tm);
printf("UTC Time: %s\n", time_str);
// 为了对比,我们同时打印本地时间
struct tm *local_tm = localtime(×tamp);
strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S %Z", local_tm); // %Z 会打印时区缩写,如 CST
printf("Local Time (e.g., in China): %s\n", time_str);
return 0;
}
输出(假设你在中国,时区为 CST,UTC+8):

(图片来源网络,侵删)
UTC Time: 2025-03-15 08:00:00 UTC
Local Time (e.g., in China): 2025-03-15 16:00:00 CST
可以看到,UTC 时间和北京时间正好相差8小时。
重要注意事项
-
time_t的范围:time_t在不同的系统上可能是int或long,在现代64位系统上,它通常是64位的long long,可以处理到“year 292,277,026,596”,但在一些旧的32位系统上,它是32位的int,将在 2038年1月19日 达到上限,导致“2038年问题”,如果你的应用需要处理非常遥远的未来或过去的时间,需要使用更高级的库,如 libtld 或直接处理64位整数。
-
线程安全:
localtime和asctime函数使用内部静态缓冲区来返回结果,这意味着它们不是线程安全的,如果在多线程中调用,一个线程的结果可能会被另一个线程覆盖。- 解决方案:使用它们的 "reentrant"(可重入)版本:
- 用
localtime_r替代localtime。 - 用
asctime_r替代asctime。
- 用
gmtime和strftime本身就是线程安全的。
localtime_r的用法示例:// struct tm local_tm; // localtime_r(×tamp, &local_tm); // 结果直接存入 local_tm 变量 // char *time_str = asctime_r(&local_tm, time_str_buffer);
-
错误处理:
- 总是检查
localtime和gmtime的返回值是否为NULL,如果输入的时间戳超出了struct tm能表示的范围(例如在32位系统上处理一个超出32位范围的时间戳),它们会返回NULL。
- 总是检查
| 方法 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
localtime + asctime |
代码简单,一行搞定 | 格式固定,不可自定义;线程不安全 | 快速调试,对格式无要求的简单脚本 |
localtime + strftime |
高度灵活,可自定义任意格式;strftime 是线程安全的 |
代码稍长 | 绝大多数生产环境应用的首选 |
gmtime + strftime |
处理 UTC 时间,不受本地时区影响 | 需要明确知道时间戳是 UTC | 需要显示标准时间、日志记录、网络通信等 |
对于任何严肃的 C 语言项目,强烈推荐使用 localtime (或 localtime_r) 结合 strftime 的方法,它提供了最佳的灵活性和安全性。
