Linux的时间函数
ucos中有systick这个系统时间滴答,那linux中有没有这种系统时间滴答呢?有,jiffies,但是用户空间不可以使用。那么在linux中除了使用timer定时器进行定时,可以通过时间滴答的方式来进行粗略的计时吗?下面介绍一下几个linux中使用的时间函数。
一、clock_gettime()
#include <time.h>int clock_gettime(clockid_t clk_id, struct timespec *tp);
-
clk_id
:指定要获取的时钟类型。 -
tp
:指向timespec
结构体的指针,用于存储当前时间。
第一个参数是一个时钟类型标识符:
时钟类型 | 描述 | 是否受系统时间更改 |
---|---|---|
CLOCK_REALTIME | 实时时钟(系统当前时间) | 会 |
CLOCK_MONOTONIC | 单调时钟(启动后递增) | 不会 |
其中CLOCK_MONOTONIC表示:
从某个固定时间点(通常是系统启动时间)开始递增的时间,不受系统时间修改的影响。
它的主要特性是:
-
单调递增,不会因为用户或NTP调整系统时间而倒退或跳变。
-
非常适合做 计时、超时判断、事件间隔测量。
第二个参数:
struct timespec {time_t tv_sec; // 秒long tv_nsec; // 纳秒(0 ~ 999999999)
};
示例:超时判断,毫秒级
#include <stdio.h>
#include <time.h>
#include <unistd.h>long get_current_time_ms() {struct timespec ts;clock_gettime(CLOCK_MONOTONIC, &ts); // 不受系统时间调整影响return ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
}int main() {long timeout_ms = 3000; // 设置超时时间为3000mslong start_time = get_current_time_ms();printf("开始等待...\n");while (1) {long now = get_current_time_ms();if ((now - start_time) >= timeout_ms) {printf("超时发生:已等待 %ld ms\n", now - start_time);break;}// 模拟处理usleep(100 * 1000); // 睡眠100ms}return 0;
}
二、gettimeofday
#include <sys/time.h>int gettimeofday(struct timeval *tv, struct timezone *tz);
-
tv
: 用于存储当前时间(秒+微秒) -
tz
: 通常设置为NULL
(时区参数已弃用)
struct timeval {time_t tv_sec; // 秒(从1970-01-01 00:00:00 UTC 到现在的秒数)suseconds_t tv_usec; // 微秒(0 ~ 999999)
};
这个函数与clock_gettime函数的CLOCK_REALTIME类似,不过gettimeofday的精度是微秒,clock_gettime的精度是纳秒。
适用于:时间戳记录、事件间隔计算、日志时间打点
三、Time
#include <time.h>time_t time(time_t *t);
-
返回自 1970年1月1日 00:00:00 UTC 起经过的 秒数。
-
参数
t
:-
如果不为
NULL
,会把结果存入*t
中。 -
如果是
NULL
,就只返回当前时间戳。
-
示例:
#include <stdio.h>
#include <time.h>int main() {time_t now = time(NULL);printf("当前时间:%s", ctime(&now)); // ctime 会返回格式化字符串return 0;
}当前时间:Thu Apr 25 10:40:31 2025
四、mktime(UTC0)
mktime()
是一个非常实用的 C 标准库函数,用于将一个 结构化时间(struct tm
)转换为时间戳(time_t
),即自 1970-01-01 00:00:00 UTC 起的秒数。UTC0
#include <time.h>time_t mktime(struct tm *timeptr);
-
参数:
timeptr
是一个指向struct tm
的指针,表示你构造的本地时间。 -
返回值:转换后的时间戳(
time_t
类型)。-
如果无法转换(比如时间不合法),返回
-1
。
-
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; // 年份从 1900 开始计算 (即2025年是125)int tm_wday; // 星期几 (0-6, 0是星期日) —— mktime 会帮你填充int tm_yday; // 年内第几天 (0-365) —— mktime 会填充int tm_isdst; // 夏令时标志,0表示不开启,>0表示启用,<0表示自动判断
};
示例:
#include <stdio.h>
#include <time.h>int main() {struct tm t = {0};t.tm_year = 2025 - 1900; // 年份从1900算起t.tm_mon = 3; // 4月(注意:从0算起)t.tm_mday = 25;t.tm_hour = 10;t.tm_min = 30;t.tm_sec = 0;time_t ts = mktime(&t);if (ts == -1) {printf("时间转换失败\n");} else {printf("时间戳:%ld\n", ts);printf("本地时间字符串:%s", ctime(&ts));}return 0;
}
-
构造一个未来/过去的时间戳。
-
与
difftime()
配合使用计算时间差。 -
构建“闹钟时间”、“超时时间”等目标时间点。
四、timegm
time_t timegm(struct tm *tm);
此函数与mktime的区别就是,传给mktime的时间会根据系统所在的地区减去对应的时区值。比如传2025.4.25.14.00返回值实际是2025.4.25.6.00的UTC时间戳。
而timegm的返回值是传入什么就返回什么,是对应的。比如传2025.4.25.14.00返回值实际就是2025.4.25.14.00的UTC时间戳。
-
mktime()
会把它当作本地时间转换为时间戳,会加入系统时区偏移; -
timegm()
会严格按照它就是 UTC 时间,不做时区偏移处理。
五、localtime(受当前系统时区影响或者说本身处理时区)
主要用于将 UTC 时间戳(time_t
)转换成本地时间(struct tm
结构体)。受时区影响
#include <time.h>struct tm *localtime(const time_t *timep);
-
timep
:一个指向time_t
类型的指针(即一个 UTC 时间戳)。 -
返回值:返回一个指向
struct tm
的指针,表示 本地时间结构。
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; // 自1900年以来的年数(如2025年为125)int tm_wday; // 一周中的星期 [0,6](0 = 周日)int tm_yday; // 一年中的日子 [0,365]int tm_isdst; // 夏令时标志(>0 表示夏令时,0 表示非夏令时,<0 表示未知)
};
函数 | 输出的是… |
---|---|
gmtime() | UTC 时间 |
localtime() | 本地时间(受系统时区影响) |
六、gmtime(UTC0,不受时区影响)
struct tm *gmtime(const time_t *timep);
返回一个 struct tm *
类型的指针,指向的结构体内容表示该时间戳的 UTC 时间(非本地时间)。
七、ctime(受时区影响)
将 时间戳(time_t
)转换为可读字符串
#include <time.h>char *ctime(const time_t *timep);
-
接收一个
time_t
类型的时间戳(通常由time()
得到) -
返回一个静态字符串,表示本地时间的可读格式
ctime()
返回的字符串格式如下(固定 26 字节,包括换行符和终止符):
"Wed Apr 24 15:56:29 2025\n\0"
-
返回的是一个静态字符数组的指针,不需要也不应该
free()
。 -
非线程安全,因为内部使用的是共享的静态缓冲区(使用
ctime_r()
代替可实现线程安全)。 -
总是根据本地时区来显示时间(和
localtime()
一致)。
如果你在上海(或者其他属于东八区的地方),ctime()
会自动使用当前系统设定的本地时区,也就是说:
假设你传入一个 time_t
值对应的是:
UTC 时间:2025-04-24 08:00:00
如果系统的本地时区是 Asia/Shanghai(UTC+8),那么:
printf("%s", ctime(&t));
输出会是:
Thu Apr 24 16:00:00 2025
自动加了 8 小时,因为本地时区就是比 UTC 快 8 小时。
八、asctime(不受时区影响)
将 struct tm
时间结构转成可读字符串的函数。
char *asctime(const struct tm *tm);
"Thu Apr 24 17:23:45 2025\n"
内容固定格式,长度固定为 26 字节(包括结尾的 \0
)。
-
asctime()
返回的字符串是静态分配的(每次调用都会覆盖上一次结果) -
线程不安全(多线程用
asctime_r()
) -
格式无法自定义,适合简单显示,不适合精确格式控制(如 ISO 8601)