1. 简述
在Linux系统中,时间操作函数是编程中经常使用的一部分,它们允许程序获取和设置系统时间,以及对时间进行各种处理。以下是一些常用的时间操作函数的详细介绍。
便于记忆,可以按照如下的规律。
gettimeofday和settimeofday为一组,分别用于获取时间和设置时间,精度为微秒级。
time用于获取epoch utc时间(epoch秒数)。
clock_settime和clock_gettime用于获取和设置UTC时间,精度为纳秒级(这一组用来替代gettimeofday和settimeofday)。
接下来的两组均是在Epoch秒数与可读时间(struct tm)之间互转。
localtime和mktime互为逆操作,前者将Epoch UTC时间转换为本地时区时间,后者将本地时区时间转换为Epoch UTC时间。
gmtime和timegm互为逆操作,前者将Epoch UTC时间转换为UTC可读时间,后者将UTC可读时间转换为Epoch UTC时间。
需要特别注意的是,位系统设置时间时,都是设置UTC时间。当我们执行“date”指令时,系统将会根据时区自动转换时间,如CST = UTC + 8。
2. 获取时间
gettimeofdat、time和clock_gettime获取的都是UTC时间,而不受当前系统时区的影响。也就是说,即使当前系统的时区是CST,即北京时间,gettimeofdat、time和clock_gettime获取的仍然是UTC时间。
(1) time: 获取1970年1月1日以来的总的秒计数
time() 函数是时间操作中最基础的函数之一,它返回自1970年1月1日(UTC)以来的秒数。这个时间点也被称为Unix纪元或Epoch。
#include <time.h>
time_t time(time_t *timer);
timer 参数是一个可选的指针,如果提供了这个参数,time() 会将当前的UTC时间存储在 timer 指向的位置。
函数返回当前的UTC时间(time_t类型),如果出现错误,则返回 -1。
(2) gettimeofday: 获取高精度时间
gettimeofday() 函数用于获取当前UTC时间的更高精度(微秒级)。
#include <sys/time.h>
int gettimeofday(struct timeval *tv, struct timezone *tz);
struct timeval {
time_t tv_sec; // 秒
suseconds_t tv_usec; // 微秒
};
struct timezone {
int tz_minuteswest; // 与UTC的时差(分钟)
int tz_dsttime; // 夏令时信息
};
tv 参数是一个指向 timeval 结构的指针,用于存储当前的时间信息。
tz 参数是一个可选的指向 timezone 结构的指针,用于存储有关时区和夏令时的信息。
函数返回0表示成功,返回-1表示错误。
(3) clock_gettime: 获取UTC时间
clock_gettime用于获取UTC时间,经度精确到纳秒级。
#include <time.h>
int clock_gettime(clockid_t clk_id, struct timespec *tp);
clk_id:始终类型,取值如下:
CLOCK_REALTIME 系统实时时钟,表示自1970-01-01 00:00:00 UTC 起的当前时间。
CLOCK_MONOTONIC 单调时钟,不受系统时间修改影响,适用于测量时间间隔。
CLOCK_PROCESS_CPUTIME_ID 进程级别的 CPU 时间,适用于测量进程消耗的 CPU 时间。
CLOCK_THREAD_CPUTIME_ID 线程级别的 CPU 时间,适用于测量线程消耗的 CPU 时间。
CLOCK_MONOTONIC_RAW 未经过调整的单调时钟,提供更精确的时间测量。
CLOCK_BOOTTIME 从系统启动到当前的时间,包括系统挂起的时间。
tp: struct timespec类型的,结构类型如下:
struct timespec {
time_t tv_sec; // 秒
long tv_nsec; // 纳秒
};
3. 时间转换
(1) localtime: 转换为本地时间(本地时区)
localtime() 函数将UTC时间转换为本地时间,并将其存储在 tm 结构中。
#include <time.h>
struct tm *localtime(const time_t *timer);
struct tm结构体如下。
struct tm {
int tm_sec; ///< 秒
int tm_min; ///< 分钟
int tm_hour; ///< 小时
int tm_mday; ///< 日期(1-31, 当月的第几天)
int tm_mon; ///< 月(0-11)
int tm_year; ///< 自 1900 起的年数
int tm_wday; ///< 星期(0-6,本周的第几天)
int tm_yday; ///< 自年初以来的天数(0-365, 本年的第几天)
int tm_isdst; ///< 夏令时标识符(小于0表示没有夏令时, 自动判别;等于0表示不知道;大于0表示夏令时)
};
timer 参数是一个指向 time_t 类型的指针,指向要转换的UTC时间。
函数返回一个指向 tm 结构的指针,其中包含了转换后的本地时间信息。
(2) mktime:将本地时间转换为UTC时间
mktime() 函数将本地时间转换为UTC时间,功能上与localtime() 互为逆操作。
#include <time.h>
time_t mktime(struct tm *timeptr);
timeptr 参数是一个指向 tm 结构的指针,该结构包含了本地时间信息。
函数返回转换后的UTC时间(time_t类型)。如果 tm 结构中的日期无效,则返回 -1。
(3) gmtime: 转换为可读的UTC时间
gmtime() 函数将UTC时间转换为可读时间,并将其存储在 tm 结构中。与localtime不同的是,gmtime是转换为0时区的本地时间。
#include <sys/time.h>
struct tm *gmtime(const time_t *timer);
(4) timegm: 将刻度的UTC时间转换为EPOCH UTC时间。
time_t timegm(struct tm *tm);
4. 设置时间
(1) settimeofday:设置时间
settimeofday() 函数用于设置系统时钟的时间。这个函数在大多数系统上已经被废弃,因为它允许未经授权的修改系统时间,可能会带来安全问题。
#include <sys/time.h>
int settimeofday(const struct timeval *tv, const struct timezone *tz);
tv 参数是一个指向 timeval 结构的指针,包含了要设置的新时间。
tz 参数是一个指向 timezone 结构的指针,包含了时区信息。
函数返回0表示成功,返回-1表示错误。
(2) clock_settime: 设置时间
#include <time.h>
int clock_settime(clockid_t clk_id, const struct timespec *tp);
clockid_t clk_id 用于指定计时时钟的类型,有以下4种:
CLOCK_REALTIME:系统实时时间,随系统实时时间改变而改变,即从UTC1970-1-1 0:0:0开始计时,中间时刻如果系统时间被用户该成其他,则对应的时间相应改变
CLOCK_MONOTONIC:从系统启动这一刻起开始计时,不受系统时间被用户改变的影响
CLOCK_PROCESS_CPUTIME_ID:本进程到当前代码系统CPU花费的时间
CLOCK_THREAD_CPUTIME_ID:本线程到当前代码系统CPU花费的时间
struct timespect *tp用来存储当前的时间,其结构如下:
struct timespec
{
time_t tv_sec; /* seconds */
long tv_nsec; /* nanoseconds */
};
返回值。0成功,-1失败