首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >结构tm tm_isdst与BST不一致

结构tm tm_isdst与BST不一致
EN

Stack Overflow用户
提问于 2020-05-25 00:49:18
回答 1查看 127关注 0票数 1

我在英国。我使用的是带有clang编译器的C++ Builder10.2。下面的代码

代码语言:javascript
复制
#include <stdio.h>
#include <conio.h>
#include <time.h>

#ifdef _WIN32
#include <tchar.h>
#else
  typedef char _TCHAR;
  #define _tmain main
#endif

int _tmain()
{

    printf("TZ set = %s\r\n",putenv("TZ=Europe/London")==0 ? "true" : "false");
    printf("TZ=%s\r\n",getenv("TZ"));

    for (int dst = 0, year = 2017; year <= 2023; year++)
        for (int mon = 1; mon <= 12; mon++)
            for (int mday = 1; mday <= 31; mday++)
            {
                struct tm st = { 0, 0, 12, mday, mon - 1, year - 1900 };
                st.tm_isdst=-1;
                time_t tt = mktime(&st); // this sets the tm_isdst to 1 or 0
                if (st.tm_isdst != dst)
                {
                    dst = st.tm_isdst;
                    printf("%02d/%02d/%d (%ld) ", mday - !dst, mon, year, tt-(!dst)*24*60*60);
                    if (!dst) printf("\r\n");
                }
            }
    getch();
}

生成以下输出

代码语言:javascript
复制
12/03/2017 (1489316400)   04/11/2017 (1509796800)
11/03/2018 (1520766000)   03/11/2018 (1541246400)
10/03/2019 (1552215600)   02/11/2019 (1572696000)
08/03/2020 (1583665200)   00/11/2020 (1604145600)
14/03/2021 (1615719600)   06/11/2021 (1636200000)
13/03/2022 (1647169200)   05/11/2022 (1667649600)
12/03/2023 (1678618800)   04/11/2023 (1699099200)

( 00/11/2020应该是30/10/2020,但我看不出为了纠正它而使代码复杂化的意义)。

问题是,上面的日期与维基列出的英国夏季时间完全不一致-

代码语言:javascript
复制
2017 26 March 29 October 
2018 25 March 28 October 
2019 31 March 27 October 
2020 29 March 25 October 
2021 28 March 31 October 
2022 27 March 30 October 
2023 26 March 29 October 

我的代码(左侧)提供的BST开始日期返回3600秒(1小时)外的unix时间戳。从下面的注释看,如果我的TZ设置为加拿大-美国人,则输出似乎都是正确的,但它设置为伦敦。

编辑:我正在重新表述这个问题。HITF您是否获得了上面的代码,以便使用Windows 10设置中设置的时区?无论我将时区设置为什么,它仍然会得出类似的日期。只有当我指定太平洋时间(美国和加拿大)时区(UTC-8.00)时,我才能得到正确答案。无论在设置中选择哪个时区,它似乎都会使用该时区。在封锁期间醒来却不知道今天是什么日子已经够糟糕的了。现在我甚至不知道它是什么时区。

EDIT2:我添加了这些行

代码语言:javascript
复制
printf("TZ set = %s\r\n",putenv("TZ=Europe/London")==0 ? "true" : "false");
printf("TZ=%s\r\n",getenv("TZ"));

在他们打印代码的时候

TZ设置= true TZ=欧洲/伦敦

什么都没变。

EN

回答 1

Stack Overflow用户

发布于 2020-05-25 01:01:05

这些日期是加拿大裔美国人夏令时的第一天和最后一天。检查TZ环境变量指定的时区。

其他问题:

  • 您假定struct tm中字段的顺序,但该顺序不是由语言指定的。
  • 您没有正确初始化tm_isdst字段。如果不知道是否正在使用DST,则应该使用-1。该值可能用于处理夏令时之外的重叠(“回退”)小时数。
  • 您的代码假定切换到夏令时的时间早于从夏令时切换到夏令时的时间,但在南半球则相反。

修复了以下问题的程序:

代码语言:javascript
复制
#include <stdio.h>
#include <time.h>

int main(void) {
   int dst = -1, dst_syear, dst_smon, dst_smday;
   for (int year=2017; year<=2023; ++year) {
      for (int mon=1; mon<=12; ++mon) {
         for (int mday=1; mday<=31; ++mday) {
            // Note that using .tm_isdst = -1 instead of the proper value 
            // will cause mktime to fail during one of the overlapped hours
            // of a "fall back" change from DST.
            struct tm st = {
               .tm_year  = year-1900,
               .tm_mon   = mon-1,
               .tm_mday  = mday,
               .tm_hour  = 12,
               .tm_isdst = -1,
            };

            mktime(&st);  // This sets the tm_isdst to 1 or 0

            if (dst == -1) {
               if (st.tm_isdst == 0) {
                  dst = 0;
               }
            } else {
               if (st.tm_isdst != dst) {
                  dst = st.tm_isdst;
                  if (st.tm_isdst) {
                     dst_syear = year;
                     dst_smon  = mon;
                     dst_smday = mday;
                  } else {
                     printf("%d-%02d-%02d %d-%02d-%02d\n",
                        dst_syear, dst_smon, dst_smday,
                        year, mon, mday);
                  }
               }
            }
         }
      }
   }

   return 0;
}

输出:

代码语言:javascript
复制
$ TZ=Europe/London ./a
2017-03-26 2017-10-29
2018-03-25 2018-10-28
2019-03-31 2019-10-27
2020-03-29 2020-10-25
2021-03-28 2021-10-31
2022-03-27 2022-10-30
2023-03-26 2023-10-29

$ TZ=America/Toronto ./a
2017-03-12 2017-11-05
2018-03-11 2018-11-04
2019-03-10 2019-11-03
2020-03-08 2020-11-01
2021-03-14 2021-11-07
2022-03-13 2022-11-06
2023-03-12 2023-11-05

$ TZ=Australia/Sydney ./a
2017-09-31 2018-04-01
2018-10-07 2019-04-07
2019-10-06 2020-04-05
2020-10-04 2021-04-04
2021-10-03 2022-04-03
2022-10-02 2023-04-02
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/61989232

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档