Linux时间函数3-strftime时间格式转换、asctime时间固定格式、asctime_r线程安全、strftime/asctime/ctime区别
目录
1.strftime时间格式转换
1.1通用格式说明符:
1.2 strftime函数
1.2.1 C语言测试
1.2.2 shell脚本测试
2.asctime 函数
2.1 asctime多线程不安全
2.2 asctime_r线程安全版本
3.asctime、ctime、strftime区别
1.strftime时间格式转换
strftime 是用于将时间格式化为字符串的函数。它的核心是通过格式说明符(如 %Y、%m 等)将日期和时间转换为自定义字符串。
1.1通用格式说明符:
符号 | 含义 | 示例 |
---|---|---|
%Y | 四位年份 | 2025 |
%m | 两位月份 | 04 |
%d | 两位日期 | 07 |
%H | 24 小时制小时 | 15 |
%I | 12 小时制小时 | 03 |
%M | 分钟 | 30 |
%S | 秒 | 45 |
%A | 星期全称 | Monday |
%a | 星期简写 | Mon |
%B | 月份全称 | April |
%b | 月份简写 | Apr |
%p | AM/PM | PM |
%F | 等价于 %Y-%m-%d | 2025-04-07 |
%T | 等价于 %H:%M:%S | 15:30:45 |
%c | 本地日期时间 | Mon Apr 7 15:30:45 2025 |
%x | 本地日期(等价于 | 04/07/25 (2025年4月7日) |
%X | 本地时间(等价于 %H:%M:%S) | 20:33:42 |
%Z | 时区名称 | CST |
%z | 时区偏移 | +0800 |
%j | 一年中的第几天(001-366) | 097 |
%U | 一年中的第几周(周日为一周起始) | 14 |
%W | 一年中的第几周(周一为一周起始) | 14 |
1.2 strftime函数
1.2.1 C语言测试
函数原型:
#include <time.h>
size_t strftime(char *str, size_t maxsize, const char *format, const struct tm *timeptr);
参数:
str:目标字符串缓冲区。
maxsize:缓冲区最大容量(防止溢出)。
format:格式字符串(使用 % 开头的符号)。
timeptr:指向 tm 结构体的指针(通过 localtime 或 gmtime 生成)。
程序:
#include <stdio.h>
#include <time.h>
/*
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 表示 1 月)
int tm_year; // 年(实际年份 = tm_year + 1900)
int tm_isdst; // 夏令时标志(>0: 生效,0: 不生效,<0: 自动判断)
};
*/
/*
关键步骤
1.使用 time() 获取当前时间戳(time_t 类型)。
2.通过 localtime() 将时间戳转换为本地时间的 tm 结构体。
3.调用 strftime 将 tm 结构体格式化为字符串。
*/
int main()
{
time_t raw_time;
struct tm *time_info;
char buffer[64] = "";
// 获取当前时间戳
time(&raw_time);
//将当前时间戳 转换为本地时间结构体
time_info = localtime(&raw_time);
// 格式化为字符串
strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S 星期:%A ", time_info);
printf("strftime Time: %s\n", buffer);
/*
%F 等价于 %Y-%m-%d 2025-04-07
%T 等价于 %H:%M:%S 15:30:45
*/
strftime(buffer, sizeof(buffer), "%F %T 星期:%A ", time_info);
printf("strftime Time: %s\n", buffer);
// Mon Apr 7 20:33:42 2025 - 04/07/25 - 20:33:42
strftime(buffer, sizeof(buffer), "%c - %x - %X ", time_info);
printf("strftime Time: %s\n", buffer);
// CST - +0800 - 097 - 14 - 14
strftime(buffer, sizeof(buffer), "%Z - %z - %j - %U - %W", time_info);
printf("strftime Time: %s\n", buffer);
return 0;
}
运行结果:
注意:buffer空间大小需要大于存储时间字节。
1.2.2 shell脚本测试
程序:
#!/bin/bash
echo "strftime 时间格式符 shell脚本测试"
# 示例:输出当前时间(格式:2025-04-07 15:30:45)
date +"%Y-%m-%d %H:%M:%S"
# 输出:Monday, April 07, 2025 03:30 PM
date +"%A, %B %d, %Y %I:%M %p"
# 输出时间戳(秒级)
date +"%s"
str=$(date +"%F %T")
#输出变量
echo "str:"
echo $str
运行结果:
2.asctime 函数
2.1 asctime多线程不安全
函数功能:
asctime 是 C 标准库中的函数,用于将 struct tm 时间结构体转换为固定格式的字符串。 输出格式示例:Wed Jun 30 21:49:08 1993\n(末尾自动添加换行符 \n 和终止符 \0)
函数原型:
#include <time.h>
char *asctime(const struct tm *timeptr);
参数:
timeptr – 指向 struct tm 结构体的指针(通常由 localtime 或 gmtime 生成)。
返回值:
返回静态分配的字符串指针(格式固定),多线程不安全。
输出格式:
输出格式说明
生成的字符串格式固定为:
星期缩写 月份缩写 日 时:分:秒 年份\n\0
字段细节:
星期缩写:3 字母(如 Mon, Tue)。
月份缩写:3 字母(如 Jan, Apr)。
日:若为个位数,前方补空格(如 7 显示为 7)。
时间:24 小时制(如 15:30:45)。
年份:4 位数字(如 2025)。
程序:
#include <stdio.h>
#include <time.h>
/*
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 表示 1 月)
int tm_year; // 年(实际年份 = tm_year + 1900)
int tm_isdst; // 夏令时标志(>0: 生效,0: 不生效,<0: 自动判断)
};
*/
int main()
{
time_t raw_time;
struct tm *time_info;
// 获取当前时间戳
time(&raw_time);
// 转换为本地时间的 tm 结构体
time_info = localtime(&raw_time);
// 转换为固定格式字符串
char *time_str = asctime(time_info);
printf("asctime: %s", time_str);
// 输出示例:Wed Apr 7 15:30:45 2025
return 0;
}
运行结果:
2.2 asctime_r
线程安全版本
asctime_r 是 Linux 特有的线程安全函数,需手动提供缓冲区:
函数原型:
#include <time.h>
char *asctime_r(const struct tm *timeptr, char *buf);
参数:
timeptr:指向 struct tm 结构体的指针(通常由 localtime_r
或 gmtime_r 生成)。
buf:用户提供的缓冲区,长度至少为 26 字节(固定格式字符串占 26 字节,
包含换行符 \n 和终止符 \0)。
返回值:
成功:返回指向 buf 的指针。
失败:返回 NULL(如 timeptr 或 buf 为非法指针)。
使用步骤:
- 定义缓冲区(≥26 字节)。
- 获取时间戳并转换为 struct tm(使用线程安全的 localtime_r 或 gmtime_r)。
- 调用 asctime_r 转换时间格式
程序:
#include <stdio.h>
#include <time.h>
/*
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 表示 1 月)
int tm_year; // 年(实际年份 = tm_year + 1900)
int tm_isdst; // 夏令时标志(>0: 生效,0: 不生效,<0: 自动判断)
};
*/
int main()
{
time_t raw_time;
struct tm time_info;
char buffer[64]; // 必须至少 26 字节
// 获取当前时间戳
time(&raw_time);
// 转换为本地时间(线程安全)
localtime_r(&raw_time, &time_info);
// 转换为固定格式字符串
if (asctime_r(&time_info, buffer) != NULL)
{
printf("Time: %s", buffer); // 输出示例:Mon Apr 7 15:30:45 2025\n
}
else
{
perror("asctime_r failed");
}
return 0;
}
运行结果:
3.asctime、ctime、strftime区别
特性 | asctime | ctime | strftime |
---|---|---|---|
输入类型 | struct tm | time_t | struct tm |
输出格式 | 固定格式 | 固定格式(本地时间) | 完全自定义 |
线程安全 | 否 | 否 | 是 |
缓冲区来源 | 静态内存 | 静态内存 | 用户提供 |
灵活性 | 低 | 低 | 高 |
替代方案 | asctime_r (线程安全) | ctime_r (线程安全) | 无(本身安全) |
1.关键区别
(1)输入参数:
- asctime 处理 struct tm。
- ctime 处理 time_t(自动转换为本地时间)。
- strftime 处理 struct tm,但允许自定义格式。
(2)线程安全:
- asctime 和 ctime 非线程安全(依赖静态内存)。
- strftime 线程安全(需用户管理缓冲区)。
(3)格式控制:
- asctime 和 ctime 输出固定格式。
- strftime 支持任意格式(如 %Y-%m-%d)。
2.选择建议
- 简单输出:单线程下用 asctime 或 ctime。
- 多线程:改用 asctime_r/ctime_r 或 strftime。
- 自定义格式:必须使用 strftime。