时区与time/gmtime/localtime/mktime/ctime函数联系

(Owed by: 春夜喜雨 http://blog.csdn.net/chunyexiyu)
参考:https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/mktime-mktime32-mktime64?view=msvc-170
参考:https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/localtime-localtime32-localtime64?view=msvc-170
参考:https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/gmtime-gmtime32-gmtime64?view=msvc-170
参考:https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/ctime-ctime32-ctime64-wctime-wctime32-wctime64?view=msvc-170
参考:https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/time-time32-time64?view=msvc-170

经常用time函数的时候,获取了从一个1970年1月1日0时0分0秒开始的秒数计数,但是这个计数是基于当地时区时间计数,还是格林威治时间计数,自己心里还是有问号在的。

验证测试

确认也不难,查文档,自己测试试试看,就有了下面这些记录了:

// 时间0值,代表的时间是什么时间呢?是1970.1.1,格林威治0:0:0,东8区是8:00:00
// 参考输出 time0=0 Thu Jan  1 08:00:00 1970
time_t n0 = 0;
printf("time0=%d %s\n", n0, ctime(&n0));

// 获取当前时间: 格林威治时间
// 参考 now=time(NULL)=1648340045 %86400=845 Sun Mar 27 08:14:05 2022
// 参考中可以看出,845是0:14:05时刻,这个时间值是格林威治的时刻,东8区需要+8小时
time_t now = time(NULL);
printf("now=time(NULL)=%d %86400=%d %s", n, n%86400, ctime(&n));

// gm为格林威治时间,直接使用time_t转换即可得到tm结构
// 参考 使用now转换格力威支时刻,显示的是 gm.hour=0, min=14, sec=5
struct tm* gm = gmtime(&now);
printf("gm.hour=%d, min=%d, sec=%d\n", gm->tm_hour, gm->tm_min, gm->tm_sec);

// local为当地时间,使用time_t格林威治时间+时区偏差,生成tm结构
// 参考 使用now转换当地时刻,显示的是 local.hour=8, min=14, sec=5
struct tm* local = localtime(&now);
printf("local.hour=%d, min=%d, sec=%d\n", local->tm_hour, local->tm_min, local->tm_sec);

// mktime输入的是localtime-tm结构,得到格林威治时间time_t
// ctime展示的当地时间localtime串信息
// 参考 使用local转换,显示的是 mktime=1648340045, %86400=845, Sun Mar 27 08:14:05 2022
time_t l = mktime(local);
printf("mktime=%d, %86400=%d, %s", l, l%86400, ctime(&l));

// localtime与gmtime两者关系:
例如 localtime北京时间 = gmtime格林威治时间 +8小时

如果想做时区自动转换也是可以的:
例如当前计算机采用的东八区时间,想使用timezone-0作为程序的时区设置
通过:linux版本使用tzset、windows版本使用_tzset设置时区

// 设置程序使用时区0
_putenv_s("TZ", "GMT-0");
_tzset();

// gmtime与localtime就会一致了, ctime展示出的也是设定timezone=0的时间了
struct tm* gm = gmtime(&now);
struct tm* local = localtime(&now);
printf("current: %s", ctime(&now));

叙述理解

研究时间这块,跟我之前理解偏差最大的一个点是:

  • time(NULL)总是返回的是当前格林威治时间,不论系统/程序采用的哪个时区;
  • 正常使用的情况下:time_t上的存储值总是描述格林威治时间;
  • tm结构存储值有时用来描述格林威治时间gmtime,有时用来描述当地时间localtime-当前时区时间;
  • ctime考虑了时区,输入值要求time_t是格林威治时间,输出来的值总是用来描述当地时间-当前时区时间;
  • mktime考虑了时区,输入的值总是要求localtime-tm结构-当前时区时间,输出值格林威治时间;

注意:

  • ctime返回的是静态变量地址;更要注意gmtime与localtime返回的静态变量地址是同一个,后调用的会覆盖上次调用的值;
  • tm结构上tm_year不同于time_t-从1970年1月1日开始,tm_year而是从1900年开始计数,输出时要+1900;
  • tm结构上tm_month从0开始,输出时需要+1; tm_mday是从1开始; tm_hour, tm_min, tm_sec的范围皆是[0, 59].
  • mktime时,不需要输入tm_wday and tm_yday。
  • Windows下:_mktime64/time handles dates from midnight, January 1, 1970 to 23:59:59, December 31, 3000. if the calendar time can’t be represented, returns -1.
  • Windows下:localtime/gmtime/ctime return NULL if the date passed to the function is Before midnight, January 1, 1970.

测试程序与输出

测试程序

#include <stdio.h>
#include <time.h>

int main(){
        time_t n0 = 0;
        printf("time0=%d %s\n", n0, ctime(&n0));

        time_t n = time(NULL);
        printf("now=time(NULL)=%d %86400=%d %s", n, n%86400, ctime(&n));
        struct tm* gm = gmtime(&n);
        printf("gm.hour=%d, min=%d, sec=%d\n", gm->tm_hour, gm->tm_min, gm->tm_sec);
        struct tm* local = localtime(&n);
        printf("local.hour=%d, min=%d, sec=%d\n", local->tm_hour, local->tm_min, local->tm_sec);
        time_t l = mktime(local);
        printf("mktime=%d, %86400=%d, %s\n", l, l%86400, ctime(&l));

        struct tm t;
        t.tm_year = 70;
        t.tm_mon = 1;
        t.tm_mday = 1; // 注: windows下mktime不支持东8区取1970.1.1号8点前时间;linux是可以的;windows下可以取往后延一天的0点时间值。
        t.tm_hour = 0;
        t.tm_min = 0;
        t.tm_sec = 0;
        time_t curr = mktime(&t);
        printf("local-1970.1.1=%d %86400=%d %s\n", curr, curr % 86400, ctime(&curr));

        printf("(now-local@1970.1.1)%86400 = %d\n", (n - curr) % 86400);
        return 0;
}

输出

time0=0 Thu Jan  1 08:00:00 1970

now=time(NULL)=1648340045 %86400=845 Sun Mar 27 08:14:05 2022
gm.hour=0, min=14, sec=5
local.hour=8, min=14, sec=5
mktime=1648340045, %86400=845, Sun Mar 27 08:14:05 2022

local-1970.1.1=-28800 %86400=-28800 Thu Jan  1 00:00:00 1970

(now-local@1970.1.1)%86400 = 29645

(Owed by: 春夜喜雨 http://blog.csdn.net/chunyexiyu)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

春夜喜雨

稀罕你的喜欢!!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值