问题
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.
回答1:
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
来源:https://stackoverflow.com/questions/61989232/struct-tm-tm-isdst-disagrees-with-bst