asctime 是 C 标准库 <time.h> 中的一个函数,用于将 struct tm 结构体中的时间信息转换为一个易读的字符串格式。

(图片来源网络,侵删)
函数原型
#include <time.h> char *asctime(const struct tm *timeptr);
- 头文件:
#include <time.h> - 参数:
timeptr: 一个指向struct tm结构体的指针,这个结构体包含了被“分解”后的时间信息(年、月、日、时、分、秒等)。
- 返回值:
- 返回一个指向静态字符数组的指针,这个字符串包含了格式化后的时间。
timeptr是NULL指针,则返回NULL。
返回值格式
asctime 生成的字符串格式是固定的,如下所示:
Www Mmm dd hh:mm:ss yyyy
Www: 星期几,"Sun", "Mon", "Tue"。Mmm: 月份,"Jan", "Feb", "Mar"。dd: 月份中的日期,格式为dd(01, 02, ..., 31)。hh:mm:ss: 时:分:秒,格式为hh:mm:ss(23:59:59)。yyyy: 四位数的年份。
字符串末尾会自动附加一个换行符 \n 和一个空字符 \0。
struct tm 结构体
要使用 asctime,你首先需要有一个填充好的 struct tm 结构体,这个结构体的定义通常如下:
struct tm {
int tm_sec; /* 秒,范围 0-59 */
int tm_min; /* 分,范围 0-59 */
int tm_hour; /* 小时,范围 0-23 */
int tm_mday; /* 一个月中的第几天,范围 1-31 */
int tm_mon; /* 月份,范围 0-11 (0=一月, 11=十二月) */
int tm_year; /* 年份,从 1900 年开始的年数 */
int tm_wday; /* 一周中的第几天,范围 0-6 (0=周日, 6=周六) */
int tm_yday; /* 一年中的第几天,范围 0-365 */
int tm_isdst; /* 夏令时标志,正数表示夏令时,0表示非夏令时,负数表示未知 */
};
特别注意:

(图片来源网络,侵删)
tm_mon是从0开始的,0代表一月。tm_year是从1900开始的偏移量,2025 年,tm_year应该是123(2025 - 1900)。tm_wday是从0开始的,0代表周日。
使用示例
示例 1:手动构建 struct tm
这个例子演示了如何手动创建一个时间结构体,并将其转换为字符串。
#include <stdio.h>
#include <time.h>
int main() {
// 1. 声明并初始化一个 struct tm 结构体
struct tm my_time = {0};
// 设置时间:2025年10月27日,下午3点30分15秒,周五
my_time.tm_sec = 15; // 秒
my_time.tm_min = 30; // 分
my_time.tm_hour = 15; // 小时 (24小时制)
my_time.tm_mday = 27; // 日
my_time.tm_mon = 9; // 月 (0-11, 10月是第9个月)
my_time.tm_year = 123; // 年 (2025 - 1900)
my_time.tm_wday = 5; // 星期 (0-6, 周五是5)
my_time.tm_isdst = 0; // 非夏令时
// 2. 调用 asctime 进行转换
char *time_str = asctime(&my_time);
// 3. 打印结果
if (time_str != NULL) {
printf("转换后的时间字符串是:\n%s", time_str);
} else {
printf("asctime 调用失败,\n");
}
return 0;
}
输出结果:
转换后的时间字符串是:
Fri Oct 27 15:30:15 2025
示例 2:与 time() 和 localtime() 结合使用
在实际编程中,我们更常见的是获取当前系统时间,而不是手动设置,这通常需要结合 time() 和 localtime() 函数。
#include <stdio.h>
#include <time.h>
int main() {
// 1. 获取当前日历时间(自1970年1月1日以来的秒数)
time_t raw_time;
time(&raw_time);
// 2. 将日历时间转换为本地时间的 struct tm 结构体
struct tm *local_time = localtime(&raw_time);
// 3. 调用 as 进行转换
char *current_time_str = asctime(local_time);
// 4. 打印结果
if (current_time_str != NULL) {
printf("当前的本地时间是:\n%s", current_time_str);
} else {
printf("asctime 调用失败,\n");
}
return 0;
}
可能的一次输出结果 (取决于你运行代码的时间):

(图片来源网络,侵删)
当前的本地时间是:
Mon Oct 28 10:05:50 2025
重要注意事项
1 线程安全问题
这是 asctime 函数最关键的问题。
- 非线程安全:
asctime返回的指针指向一个静态分配的字符数组,这意味着每次调用asctime,都会覆盖这个数组上一次的内容。 - 后果: 如果你在多线程环境中使用
asctime,或者在一个线程中调用asctime后,在另一个使用该字符串的函数(如printf)结束之前再次调用asctime,会导致数据竞争和不可预测的结果。
示例(展示问题):
#include <stdio.h>
#include <time.h>
void print_time(const char* name) {
time_t raw_time = time(NULL);
struct tm *time_info = localtime(&raw_time);
// printf 和 asctime 都在内部使用了同一个静态缓冲区
printf("[%s] %s", name, asctime(time_info));
}
int main() {
print_time("First");
print_time("Second");
return 0;
}
可能的输出 (输出顺序混乱):
[First] Mon Oct 28 10:10:00 2025
[Second] Mon Oct 28 10:10:00 2025
或者更糟,输出可能被截断或混合。
2 线程安全的替代方案
为了解决线程安全问题,C 标准库提供了 asctime_r 函数(POSIX 标准,在 Linux 和其他类 Unix 系统上可用)。
asctime_r 的原型如下:
#include <time.h> char *asctime_r(const struct tm *timeptr, char *buffer);
- 参数:
timeptr: 和asctime一样,指向struct tm。buffer: 指向一个用户提供的字符数组。asctime_r会将结果写入这个数组。
- 返回值:
- 成功时,返回传入的
buffer指针。 - 失败时,返回
NULL。
- 成功时,返回传入的
使用 asctime_r 的示例:
#include <stdio.h>
#include <time.h>
int main() {
time_t raw_time = time(NULL);
struct tm *local_time = localtime(&raw_time);
// 必须提供一个足够大的缓冲区
// "Www Mmm dd hh:mm:ss yyyy\n" + '\0' = 25 字节
char time_str[26];
// 使用 asctime_r
char *result = asctime_r(local_time, time_str);
if (result != NULL) {
printf("安全的当前时间是:\n%s", time_str);
} else {
printf("asctime_r 调用失败,\n");
}
return 0;
}
asctime_r 是线程安全的,因为它不依赖静态内存区,而是使用用户提供的缓冲区。
3 缓冲区大小
asctime 返回的字符串长度最多为 26 个字符(包括 \n 和 \0),如果你使用 asctime_r,请确保你提供的缓冲区至少有 26 个字节大小。
| 特性 | asctime |
asctime_r (推荐) |
|---|---|---|
| 线程安全 | 不安全 | 安全 |
| 返回值 | 指向静态缓冲区的指针 | 用户传入的缓冲区指针 |
| 依赖平台 | C 标准 | POSIX 标准 (Linux, macOS 等) |
| 使用场景 | 简单的单线程程序 | 任何需要线程安全或可移植性的程序 |
| 推荐度 | ⚠️ 不推荐 | ✅ 推荐 |
虽然 asctime 函数简单易用,但由于其固有的线程安全问题,在现代 C 编程中,强烈推荐使用 asctime_r,如果你在 Windows 等不支持 asctime_r 的平台上,并且必须保证线程安全,你需要自己实现一个线程安全的版本(使用互斥锁来保护对 asctime 的调用)。
