简体   繁体   English

在Linux下使用gcc在C中进行夏令时和mktime

[英]Daylight savings and mktime in C using gcc under Linux

I am working with detecting Daylight saving time (summer time) transitions. 我正在检测夏令时(夏令时)转换。 I have come across something that I don't understand, and was hoping for some explanation. 我遇到了一些我不理解的东西,希望得到一些解释。

I have stripped down my code to a nearly bare minimum to show the problem. 我已经将我的代码剥离到几乎没有最低限度来显示问题。

int main(void)
{
  struct tm tm1,tm2;
  time_t time1, time2;
  int order=0;//change this betwee 0 and 1

  tm1.tm_hour=2;
  if (order)
  {
    tm1.tm_hour=1;
  }
  tm1.tm_min=0;
  tm1.tm_sec=0;
  tm1.tm_mday=1;
  tm1.tm_mon=10;
  tm1.tm_year=115;  
  tm1.tm_isdst=-1;
  time1=mktime(&tm1);

  //insert here

  tm2.tm_hour=1;
  if (order)
  {
    tm2.tm_hour=2;
  }
  tm2.tm_min=0;
  tm2.tm_sec=0;
  tm2.tm_mday=1;
  tm2.tm_mon=10;
  tm2.tm_year=115;  
  tm2.tm_isdst=-1;
  time2=mktime(&tm2);


  printf("\n\n time stamp 1=%zu time stamp 2=%zu difference=%zi\n\n",time1 ,time2, time2-time1);
  exit(0);
}

The output when order = 0 is: order = 0时的输出是:

time stamp 1=1446368400 time stamp 2=1446364800 difference=-3600

The output when order = 1 is: order = 1时的输出是:

time stamp 1=1446361200 time stamp 2=1446368400 difference=7200

(note that this is intentionally the time of the end of daylight saving time, one second after 01:59:59 on November 1st of 2015, it will be 01:00:00.) (请注意,这是夏令时结束的时间,在2015年11月1日01:59:59之后的一秒,它将是01:00:00。)

To put it simply, the conversion of the structure when hour = 2 depends on the conversion that occurred immediately before it. 简而言之,当hour = 2时结构的转换取决于紧接在它之前发生的转换。 One o'clock can (correctly) be either 1446364800 (standard time) or 1446361200 (DST). 一点钟(正确)可以是1446364800(标准时间)或1446361200(DST)。 if the conversion before is found to DST, the second choice is used and vice versa. 如果之前的转换被发现是DST,则使用第二个选择,反之亦然。 The obvious solution is that mktime sets some variable, that it uses the next time. 显而易见的解决方案是mktime设置了一些变量,它将在下次使用。 However I can't find any record of it. 但是我找不到它的任何记录。 mktime does set three (four?) external variables, tzname[0],tzname[1], timezone and daylight, but these don't seem to be causing the effect. mktime确实设置了三个(四个?)外部变量,tzname [0],tzname [1],时区和日光,但这些似乎没有造成影响。 (I did a more complicated version of my test program to test for that.) (我做了一个更复杂的测试程序版本来测试它。)

My time zone is America/Edmonton ( MST(UTC-7)/MDT(UTC -6) ) 我的时区是America / Edmonton(MST(UTC-7)/ MDT(UTC -6))

$ gcc --version<br>
gcc (Ubuntu 4.8.4-2ubuntu1~14.04) 4.8.4

Kubuntu 14.04 LTS Kubuntu 14.04 LTS

Any insight or pointers would be much appreciated. 任何见解或指示将非常感激。

Edit: replys to comments: 1) Jonathan -- glibc version 2.19 2) chux -- printing the values of tmX.tm_isdst, tmX.tm_hour after the mktime() doesn't provide me any insight. 编辑:回复评论:1)Jonathan - glibc版本2.19 2)chux - 在mktime()之后打印tmX.tm_isdst,tmX.tm_hour的值并没有提供任何见解。 (is that because I'm blind?) The one O'clock conversion shows an hour of one and a is_dst of either 0 or 1, exactly as infered by the timestamp. (那是因为我是瞎子吗?)一次转换显示一小时为1,is_dst为0或1,与时间戳完全相同。 The two O'clock conversion, of course, shows an hour of 2 and an is_dst of 0. 当然,两点转换显示一小时为2,is_dst为0。

reply to chux's(?) answer: I wonder If I have not fully explained myself. 回答chux的(?)回答:我想知道如果我没有完全解释自己。 I realize what is going on: There is an ambiguity, and it has to "guess". 我意识到发生了什么:存在歧义,它必须“猜测”。 What I am wondering is why (and how) can it's guess depend on the previous conversion? 我想知道为什么(以及如何)它的猜测取决于之前的转换?

second edit: 第二次编辑:

to confirm Wumpus Q. Wumbley's answer inserted the following code in the place indicated in the code above: 确认Wumpus Q. Wumbley的答案在上面的代码中指出的地方插入了以下代码:

tm0.tm_hour=0;
tm0.tm_min=0;
tm0.tm_sec=0;
tm0.tm_mday=1;
tm0.tm_mon=10;
tm0.tm_year=115;  
tm0.tm_isdst=-1;
time0=mktime(&tm0);

(Basically a throw away conversion) I now get two hours difference regardless of order, so I get the DST version either way. (基本上是扔掉转换)我现在得到两个小时的差异,无论顺序如何,所以我得到了DST版本。

Thanks for the explanation. 感谢您的解释。

In the current glibc source code, at time/mktime.c line 410 there is a relevant comment: 在当前的glibc源代码中,在time/mktime.c第410行有一个相关的注释:

/* Invert CONVERT by probing.  First assume the same offset as last
   time.  */

It intentionally uses the same offset in consecutive calls when possible. 它尽可能在连续呼叫中使用相同的偏移量。 There is no global variable you can set to change this, or inspect to detect it. 没有可以设置的全局变量来更改它,或者检查以检测它。 It's kept in the static time_t localtime_offset; 它保存在static time_t localtime_offset; at line 578. 在第578行。

The issue comes down to the value of tmX.tm_isdst before / after the mktime() call. 问题归结为mktime()调用之前 / 之后tmX.tm_isdst的值。

"A negative value causes it to attempt to determine whether Daylight Saving Time is in effect for the specified time." “负值使其尝试确定夏令时是否在指定时间内有效。” C11dr §7.27.2.3 2 footnote C11dr§7.27.2.32脚注

I added printf("H:%d DST:%d\\n", tm1 (or 2).tm_hour, tm1.tm_isdst); 我添加了printf("H:%d DST:%d\\n", tm1 (or 2).tm_hour, tm1.tm_isdst); after each: 每个之后:

// order 0
H:2 DST:0
H:1 DST:1
time stamp 1=1446364800 time stamp 2=1446357600 difference=-7200

// order 1
H:1 DST:1
H:2 DST:0
time stamp 1=1446357600 time stamp 2=1446364800 difference=7200

The values are correct for the assumption made by the system concerning the underspecified "YMD H:M:S dst=unknown" time-stamp which could go either way. 该值对于系统关于未指定的“YMD H:M:S dst =未知”时间戳的假设是正确的,该时间戳可以是任何一种方式。

Since C does not specified what should be used during this transition hour, either assuming dst is true/false is reasonable and not necessarily consistent across various platforms. 由于C未指定在此转换时间内应使用的内容,因此假设dst为true / false是合理的,并且在各种平台上不一定一致。 A given system, for example, could use the previous isdst setting, always 0 or flip a coin. 例如,给定系统可以使用先前的isdst设置,始终为0或翻转硬币。 It simply is not specified. 它没有具体说明。


Note: This is an example of why some laws say "bars must close 2 hours after midnight rather than 2:00 AM in areas where DST transitions occurs in the 2:00/3:00 AM hour. 2 hours after midnight occurs only once - everyday. 2:00 AM occurs twice on that special transition night once a year. 注意:这是一个例子,说明为什么有些法律规定“酒吧必须在午夜后2小时关闭,而不是凌晨2:00在DST转换发生在2:00/3:00 AM小时的区域。午夜后2小时仅发生一次 - 每天。凌晨2:00在特殊的过渡之夜一年两次。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM