Compute offset of local timezone from UTC for every day since 1880

This commit is contained in:
Peter J. Holzer 2016-06-04 11:43:12 +02:00
commit c4f2035d21
2 changed files with 97 additions and 0 deletions

2
GNUmakefile Normal file
View File

@ -0,0 +1,2 @@
CFLAGS = -std=c11 -Wall -ftrapv
all: timezone-history

95
timezone-history.c Normal file
View File

@ -0,0 +1,95 @@
#include <assert.h>
#include <stdint.h>
#include <stdio.h>
#include <time.h>
time_t start_time(void) {
// return the start of our time range
// we want 12:00 local time on January 1st of the first year >= 1880
// we can represent (1880, because time zones based on GMT were
// enacted in 1885, so we start a little bit earlier if we can)
for (int y = 1880; y < 2000; y++) {
struct tm tm;
tm.tm_year = y - 1900;
tm.tm_mon = 0;
tm.tm_mday = 1;
tm.tm_hour = 12;
tm.tm_min = 0;
tm.tm_sec = 0;
tm.tm_isdst = -1;
time_t t = mktime(&tm);
if (t != (time_t)-1) {
return t;
}
}
assert(0); // no date before 2000 representable? mktime is broken
}
time_t end_time(void) {
// return the end of our time range
// 12:00 local time on dec. 31 of the current year seems ok.
// we might want to extend that a few years into the future, but
// it's hard to say how much: Sometimes DST changes are only
// published weeks before they happen, so even the end of the year
// is a bit optimistic.
time_t t = time(NULL);
struct tm *tmp = localtime(&t);
struct tm tm;
tm.tm_year = tmp->tm_year;
tm.tm_mon = 11;
tm.tm_mday = 31;
tm.tm_hour = 12;
tm.tm_min = 0;
tm.tm_sec = 0;
tm.tm_isdst = -1;
t = mktime(&tm);
if (t != (time_t)-1) {
return t;
}
assert(0); // end of current year not representable? mktime is broken
}
int_least32_t diff(struct tm utm, struct tm ltm) {
int_least32_t d;
// local time should be close to noon, timezones are somwhere in
// the +/- 14 hours range, so the UTC date can differ by at most one
// date. Therefore we just check whether the UTC date is earlier or
// later than the local date.
if (ltm.tm_year > utm.tm_year) {
d = 86400;
} else if (ltm.tm_year < utm.tm_year) {
d = -86400;
} else {
if (ltm.tm_mon > utm.tm_mon) {
d = 86400;
} else if (ltm.tm_mon < utm.tm_mon) {
d = -86400;
} else {
if (ltm.tm_mday > utm.tm_mday) {
d = 86400;
} else if (ltm.tm_mday < utm.tm_mday) {
d = -86400;
} else {
d = 0;
}
}
}
d += (ltm.tm_hour - utm.tm_hour) * 3600
+ (ltm.tm_min - utm.tm_min) * 60
+ (ltm.tm_sec - utm.tm_sec);
return d;
}
int main(void) {
time_t start = start_time();
time_t end = end_time();
for (time_t t = start; t <= end; t += 24*3600) {
struct tm utm = *(gmtime(&t));
struct tm ltm = *(localtime(&t));
int_least32_t d = diff(utm, ltm);
printf("%.0f %.0f\n", (double)t, (double)d);
}
}