时间详解
1. UTC、GMT、墙上时间
Coordinated Universal Time(UTC)
Greenwich Mean Time(GMT)
两者都表示标准时间,或世界时,几乎没有差异,后者更加精确
墙上时间也就是本地时间,说出墙上时间的时候,需要告知时区信息,这样才有意义(所以struct tm包含timezone这个成员)。
2. typedef uint32 time_t
time_t表示“当前时刻”与“UTC 1970.1.1 0时0分0秒”的时间差,单位s
3. time(&time_t)
获取上面的值,即此函数会返回从公元1970年1月1日的UTC时间从0时0分0秒算起到现在所经过的秒数。
问题:time()返回的结果和时区有关吗?
UTC “0时0分0秒”是一个唯一的精确的时刻,“现在”也是一个唯一的精确的时刻,两者之间的差值唯一,和时区无关!
无论你是在0时区,还是东八区,返回的都是UTC “0时0分0秒” => 现在 的时间差(秒),这是一个客观存在的值。
(之所以会认为和时区有关,是因为该值的大小等于“UTC(墙上)时间 - 1970.1.1 0:0:0”,不过这个不用多考虑)
4. struct tm
墙上时间,带有时区信息
struct tm { int tm_sec; int tm_min; int tm_hour; int tm_mday; int tm_mon; int tm_year; /* 年份,其值等于实际年份减去1900 */ int tm_wday; /* 星期 – 取值区间为[0,6],其中0代表星期天,1代表星期一,以此类推 */ int tm_yday; /* 从每年的1月1日开始的天数 – 取值区间为[0,365],其中0代表1月1日,1代表1月2日,以此类推 */ int tm_isdst; /* 夏令时标识符,实行夏令时的时候,tm_isdst为正。不实行夏令时的时候,tm_isdst为0;不了解情况时,tm_isdst()为负。 long int tm_gmtoff; /*指定了日期变更线东面时区中UTC东部时区正秒数或UTC西部时区的负秒数*/ const char *tm_zone; /*当前时区的名字(与环境变量TZ有关)*/ }; 注意两个年份基准:1970和1900 5. gmtime()和gmtime_r()struct tm *gmtime(const time_t *timep) // 线程不安全
struct tm *gmtime_r(const time_t *timep, struct tm *result)
根据time_t计算得到GMT时间,即格林威治墙上时间
根据此函数的定义,只有在想要获取GMT的时候,才会使用该函数,机器代码中一般用不到!
关于线程安全:
通过观察gmtime()返回值是结构体指针,那么结构体在哪里?
其实使用localtime和gmtime获取的返回时间是保存在一个全局的变量中的;
如果调用了localtime后,返回值没有做处理,然后接着调用gmtime,gmtime会将localtime的返回值给覆盖掉!
(前者函数有一个好处,那就是时间只有一套,不会乱)
6. localtime()和localtime_r()
struct tm *localtime(const time_t *timep) // 线程不安全
struct tm *localtime_r(const time_t *timep, struct tm *result)
根据time_t计算得到GMT时间,然后再根据时区信息调整为本地时间。
比如在东八区,相比gmtime(),localtime()获得的值会大8h。
该函数比gmtime()更加常用。
7. mktime()
mktime()的作用和localtime()正好相反,用来把墙上时间转化为标准时差值(此刻具体UTC 1970年第一秒的时间差);
墙上时间带有时区信息,标准时差值以UTC为准,那么mktime()实现的时候就需要从其他地方获取timezone。
8. 常用方法
方法1:
time_t = mktime(&tm) // 拿到墙上时间,转化为标准时差值(此刻具体UTC 1970年第一秒的时间差)
tm = localtime(time_t) // 把标准时差值转化为墙上时间
方法2:
time(&time_t); // 通过其他方法获取标准时差值
tm = localtime(time_t) // 把标准时差值转化为墙上时间
https://blog.csdn.net/weixin_52622200/article/details/111478915
https://zhuanlan.zhihu.com/p/363203858