本地时间(_r)逆行为
收藏

我写了一个小程序来显示相对于GMT(或UTC)的本地时间:

struct tm l;    
time_t stamp = 1534435540;

// No TZ set
printf("TZ=%s\n",getenv("TZ"));
gmtime_r(&stamp, &l);
printf("UTC: %0u:%0u:%0u - %0u.%0u.%0u\n",l.tm_hour,l.tm_min,l.tm_sec,l.tm_mday,l.tm_mon+1,l.tm_year+1900);
localtime_r(&stamp, &l);
printf("Local: %0u:%0u:%0u - %0u.%0u.%0u\n\n",l.tm_hour,l.tm_min,l.tm_sec,l.tm_mday,l.tm_mon+1,l.tm_year+1900);

// Positive TZ: east to Greenwich (e.g. China)
setenv("TZ", "UTC+6:00", 1);    
printf("TZ=%s\n",getenv("TZ"));     
tzset();    
gmtime_r(&stamp, &l);
printf("UTC: %0u:%0u:%0u - %0u.%0u.%0u\n",l.tm_hour,l.tm_min,l.tm_sec,l.tm_mday,l.tm_mon+1,l.tm_year+1900);
localtime_r(&stamp, &l);
printf("Local: %0u:%0u:%0u - %0u.%0u.%0u\n\n",l.tm_hour,l.tm_min,l.tm_sec,l.tm_mday,l.tm_mon+1,l.tm_year+1900);

// Negative TZ: west to Greenwich (e.g. US/Canada)
setenv("TZ", "UTC-6:00", 1);    
printf("TZ=%s\n",getenv("TZ"));
tzset();    
gmtime_r(&stamp, &l);
printf("UTC: %0u:%0u:%0u - %0u.%0u.%0u\n",l.tm_hour,l.tm_min,l.tm_sec,l.tm_mday,l.tm_mon+1,l.tm_year+1900);
localtime_r(&stamp, &l);
printf("Local: %0u:%0u:%0u - %0u.%0u.%0u\n\n",l.tm_hour,l.tm_min,l.tm_sec,l.tm_mday,l.tm_mon+1,l.tm_year+1900);

此程序的输出如下:
TZ=<null>
UTC: 16:5:40 - 16.8.2018
Local: 16:5:40 - 16.8.2018

TZ=UTC+6:00
UTC: 16:5:40 - 16.8.2018
Local: 10:5:40 - 16.8.2018

TZ=UTC-6:00
UTC: 16:5:40 - 16.8.2018
Local: 22:5:40 - 16.8.2018

看起来很奇怪,不是吗?根据Wiki
例如,如果所描述的时间比UTC早一个小时(例如冬季柏林的时间),则区域标志将是“+01:00”、“+0100”或简单的“+01”
所以GMT+6意味着我在GMT的基础上加上6个小时得到当地时间。
this article about TZ variable却恰恰相反:
如果当地时区位于本初子午线以西,则为正值;如果当地时区位于东面,则为负值。
我是否遗漏了一些东西,或者Linux的行为与标准相反?


最佳答案:

unix创建者在TZ环境变量中使用了相反的符号约定,与其他地方(包括ISO 8601中)描述时区的方式相比。
unix怪癖是在POSIX.1中标准化的,这就是标准linux遵循的。
所以是的,如果您想将时区设置为utc-04:00(例如,edt,或加拿大东部或美国东部某地的东部夏时制),您可以将tz设置为UTC+04:00

    公众号
    关注公众号订阅更多技术干货!