H-uru/Plasma — pull request #186 by cwalther (2012-03-30 20:26:45+00:00)
Title: Fix KI daylight saving time calculation

I have done some automated testing on the new KI time DST code from f6ef9d5d78ac504e64da462f22faf0c2e5c13d31 and found a couple of bugs:

- DST was truncated to end of October
- DST start was off by one week in years where March 1st is a Monday
- DST start was off by one second (1:59:59 -> 2:00:00 -> 3:00:01 instead of the correct 1:59:59 -> 3:00:00 -> 3:00:01)

The attached commit fixes that.

Here’s the code I used to test it – if anyone ever feels like setting up a unit test framework, that could be integrated there:

```c++
// from zoneinfo/America/Denver version 2011g
static const time_t dsttransitions[] = {
0x45F3C510, 0x472D7C00,
0x47D3A710, 0x490D5E00,
0x49B38910, 0x4AED4000,
0x4B9CA590, 0x4CD65C80,
0x4D7C8790, 0x4EB63E80,
0x4F5C6990, 0x50962080,
0x513C4B90, 0x52760280,
0x531C2D90, 0x5455E480,
0x54FC0F90, 0x5635C680,
0x56E52C10, 0x581EE300,
0x58C50E10, 0x59FEC500,
0x5AA4F010, 0x5BDEA700,
0x5C84D210, 0x5DBE8900,
0x5E64B410, 0x5F9E6B00,
0x604DD090, 0x61878780,
0x622DB290, 0x63676980,
0x640D9490, 0x65474B80,
0x65ED7690, 0x67272D80,
0x67CD5890, 0x69070F80,
0x69AD3A90, 0x6AE6F180,
0x6B965710, 0x6CD00E00,
0x6D763910, 0x6EAFF000,
0x6F561B10, 0x708FD200,
0x7135FD10, 0x726FB400,
0x7315DF10, 0x744F9600,
0x74FEFB90, 0x7638B280,
0x76DEDD90, 0x78189480,
0x78BEBF90, 0x79F87680,
0x7A9EA190, 0x7BD85880,
0x7C7E8390, 0x7DB83A80,
0x7E5E6590, 0x7F981C80
};

FILE* f = fopen("out.txt", "w");
for (int i = 0; i < sizeof(dsttransitions)/sizeof(dsttransitions[0]); i += 2) {
time_t dni1, dni2;
struct tm *tm;
bool fail = false;
dni1 = cyMisc::ConvertGMTtoDni(dsttransitions[i] - 1);
dni2 = cyMisc::ConvertGMTtoDni(dsttransitions[i]);
tm = gmtime(&dni1);
if (tm->tm_hour != 1 || tm->tm_min != 59 || tm->tm_sec != 59) {
char buf[128];
strftime(buf, sizeof(buf), "%a %d-%m-%Y %H:%M:%S", tm);
fprintf(f, "start before: expected 1:59:59, actual %s\n", buf);
fail = true;
}
tm = gmtime(&dni2);
if (tm->tm_hour != 3 || tm->tm_min != 0 || tm->tm_sec != 0) {
char buf[128];
strftime(buf, sizeof(buf), "%a %d-%m-%Y %H:%M:%S", tm);
fprintf(f, "start after: expected 3:00:00, actual %s\n", buf);
fail = true;
}

dni1 = cyMisc::ConvertGMTtoDni(dsttransitions[i+1] - 1);
dni2 = cyMisc::ConvertGMTtoDni(dsttransitions[i+1]);
tm = gmtime(&dni1);
if (tm->tm_hour != 1 || tm->tm_min != 59 || tm->tm_sec != 59) {
char buf[128];
strftime(buf, sizeof(buf), "%a %d-%m-%Y %H:%M:%S", tm);
fprintf(f, "end before: expected 1:59:59, actual %s\n", buf);
fail = true;
}
tm = gmtime(&dni2);
if (tm->tm_hour != 1 || tm->tm_min != 0 || tm->tm_sec != 0) {
char buf[128];
strftime(buf, sizeof(buf), "%a %d-%m-%Y %H:%M:%S", tm);
fprintf(f, "end after: expected 1:00:00, actual %s\n", buf);
fail = true;
}
if (!fail) fprintf(f, "%d ok\n", tm->tm_year + 1900);
}
fclose(f);
```