struct tm tm_isdst不同意BST [英] struct tm tm_isdst disagrees with BST

查看:105
本文介绍了struct tm tm_isdst不同意BST的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在英国。我正在将C ++ Builder 10.2与clang编译器一起使用。以下代码

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

#ifdef _WIN32
#include< tchar.h>
#else
typedef char _TCHAR;
#定义_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); //如果(st.tm_isdst!= dst)
{
dst = st.tm_isdst;则将tm_isdst设置为1或0

printf(%02d /%02d /%d(%ld),mday-!dst,mon,year,tt-(!dst)* 24 * 60 * 60);
if(!dst)printf( \r\n);
}
}
getch();
}

产生以下输出

  2017/12/03(1489316400)2017/11/04(1509796800)
2018/11/03(1520766000)2018/11/03(1541246400)
10/03/2019(1552215600)02/11/2019(1572696000)
08/03/2020(1583665200)00/11/2020(1604145600)
14/03/2021(1615719600) 20年6月11日(1636200000)
13/03/2022(1647169200)05/11/2022(1667649600)
12/03/2023(1678618800)04/11/2023(1699099200)

(00/11/2020应该是2020年10月30日,但我不明白



问题在于以上日期与Wiki列出的英国夏令时完全不符-

  2017 10月26日10月29日
2018 10月25日10月25日
2019年3月31日10月27日
2020年10月29日10月29日
2021年10月28日
2022年3月27日10月30日
2023年10月26日


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



编辑:我改一下这个问题。 HITF是否获得上面的代码以使用Windows 10设置中设置的时区?无论我将时区设置为什么,仍然会出现类似的日期。我唯一获得正确答案的时间是,如果我明确地将时区(UTC-8.00)设为太平洋时间(美国和加拿大)。似乎使用该时区,而与在设置中选择的时区无关。在锁定期间醒来,不知道今天是什么日子,这已经够糟糕的了。现在,我什至都不知道现在是哪个时区。



EDIT2:我添加了行

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

到代码并在打印时



TZ set = true
TZ =欧洲/伦敦



什么都没改变。

解决方案

这些日期是加拿大裔夏令时的开始日期和结束日期。检查 TZ 环境变量指定的时区。



其他问题:




  • 您假定 struct tm 中字段的顺序,但是语言未指定顺序。 / li>
  • 您没有正确初始化 tm_isdst 字段。 -1 用于确定是否正在使用DST。假定该值用于处理DST变更中的重叠(后退)小时。

  • 您的代码假定在一年中切换到DST的时间比从DST切换的时间更早。 DST,但在南半球则相反。



已解决以下问题的程序:

  #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){
//注意,使用.tm_isdst = -1而不是正确的值
//将导致mktime在重叠时间之一内失败b $ b //来自DST的后退更改。
struct tm st = {
.tm_year = 1900年,
.tm_mon = mon-1,
.tm_mday = mday,
.tm_hour = 12,
.tm_isdst = -1,
};

mktime(& st); //将tm_isdst设置为1或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 =年;
dst_smon = mon;
dst_smday = mday;
}否则{
printf(%d-%02d-%02d%d-%02d-%02d\n,
dst_syear,dst_smon,dst_smday,
年,周一,周日);
}
}
}
}
}
}

返回0;
}

输出:

  $ TZ =欧洲/伦敦./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 =美国/多伦多./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 =澳大利亚/悉尼./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


I'm in the UK. I'm using C++ builder 10.2 with the clang compiler. The following code

#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();
}

produces the following output

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)

(The 00/11/2020 should be 30/10/2020 but I don't see the point of complicating the code to correct it).

The problem is the above dates are totally at odds with British Summer Time as listed by wiki -

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 

The BST starting dates provided by my code (left hand side) return unix timestamps that are 3600 secs (1 hour) out. From comments below it seems the output would be all correct if my TZ was set to Canadian-American but it's set to London.

EDIT: I'm rephrasing the question. HITF do you get the code above to use the time zone as set in the Windows 10 settings? No matter what I set the time zone to it still comes up with similar dates. The only time I get a correct answer is if I specifically make the time zone (UTC-8.00) Pacific Time (US & Canada). It seems to use that time zone regardless of the one selected in settings. It's been bad enough waking up during this lockdown and not knowing what day it is. Now I don't even know what time zone it is.

EDIT2: I added the lines

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

to the code and while they printed

TZ set = true TZ=Europe/London

nothing changed.

解决方案

Those dates are the first and last date of Canadian-American DST. Check what time zone is specified by the TZ environment variable.

Other issues:

  • You assume the order of fields in struct tm, but the order isn't specified by the language.
  • You don't initialize the tm_isdst field correctly. -1 should be used for if it's unknown whether DST is being used or not. The value is presumably used to handle the overlapped ("fall back") hours in a change out of DST.
  • Your code assumes the switch to DST happens earlier in the year than the switch from DST, but it would be the opposite in the southern hemisphere.

Program with these issues fixed:

#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;
}

Output:

$ 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

这篇关于struct tm tm_isdst不同意BST的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆