如何正确将struct timespec转换为struct timeval?
解决struct timespec转struct timeval适配lutimes()的EINVAL问题
我之前在处理文件时间戳转换时也踩过这个坑,咱们先把问题拆解清楚:
你遇到的EINVAL错误核心原因很明确——转换后的struct timeval里tv_usec超出了0 <= tv_usec < 1000000的范围,而根源是你拿到的struct timespec本身可能存在纳秒值超过999,999,999的情况(比如你用touch调试发现的tv_sec=0但tv_nsec>1e9)。
正确的转换逻辑
struct timespec的tv_nsec规范范围是0~999,999,999,但实际场景中可能出现超出这个范围的值(比如相对时间计算、某些系统调用返回的异常值)。转换时必须先处理纳秒的进位,再转成微秒:
- 把超出1e9的纳秒部分转换成秒,加到
tv_sec上 - 剩余的纳秒值取模1e9,确保在合法范围内
- 将剩余纳秒除以1000,得到微秒值赋值给
tv_usec - 额外处理负数情况(如果是负的相对时间)
代码实现示例
#include <sys/time.h> #include <time.h> void timespec_to_timeval(const struct timespec *ts, struct timeval *tv) { // 先处理纳秒的进位,把超过1e9的部分转成秒 time_t total_sec = ts->tv_sec + ts->tv_nsec / 1000000000; long remaining_nsec = ts->tv_nsec % 1000000000; // 处理负数纳秒的情况(比如ts是负的偏移量) if (remaining_nsec < 0) { total_sec -= 1; remaining_nsec += 1000000000; } // 赋值给timeval结构体 tv->tv_sec = total_sec; tv->tv_usec = remaining_nsec / 1000; // 纳秒转微秒 }
针对你场景的验证
比如你遇到的tv_sec=0、tv_nsec=1500000000的情况:
- 转换后
total_sec = 0 + 1500000000 / 1e9 = 1 remaining_nsec = 1500000000 % 1e9 = 500000000tv_usec = 500000000 / 1000 = 500000
这个结果完全符合struct timeval的规范,传给lutimes()就不会再返回EINVAL错误了。
内容的提问来源于stack exchange,提问作者Cobra_Fast
相关产品推荐
相关产品推荐

