From b2ca270099539e4faf40c4b726aa3524390a04f3 Mon Sep 17 00:00:00 2001 From: Jonathan McDowell Date: Tue, 4 Sep 2018 22:21:38 +0100 Subject: [PATCH] Add support for UK daylight savings time (GMT/BST) Doesn't fully handle date changes at the end of a month, but good enough for the clock functionality currently in use. --- clock.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 56 insertions(+), 2 deletions(-) diff --git a/clock.c b/clock.c index e8df669..a0333fd 100644 --- a/clock.c +++ b/clock.c @@ -55,6 +55,7 @@ static os_timer_t ntp_timeout; static ip_addr_t ntp_server_ip; +/* See RFC5905 7.3 */ typedef struct { uint8 options; uint8 stratum; @@ -93,6 +94,45 @@ bool ICACHE_FLASH_ATTR is_leap(uint32_t year) return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0); } +bool ICACHE_FLASH_ATTR is_dst(struct tm *time) +{ + int lastsun = time->tm_mday - time->tm_wday; + + if (time->tm_mon < 2 || time->tm_mon > 9) + return false; + if (time->tm_mon > 2 && time->tm_mon < 9) + return true; + + /* + * Starts last Sunday in March, ends last Sunday in October, which must + * be at least the 25th of the month. So must be past that in March, or + * before that in October, to be in DST. + */ + if (time->tm_mon == 2) + return (lastsun >= 25); + if (time->tm_mon == 9) + return (lastsun < 25); + + return false; +} + +/* + * Takes time, a Unix time (seconds since 1st Jan 1970) and breaks it down to: + * + * Time: + * tm_sec 0-59 + * tm_min 0-59 + * tm_hour 0-23 + * + * Date: + * tm_year + * tm_mon 0-11 + * tm_mday 1-31 + * + * tm_yday + * tm_wday Sunday = 0, Saturday = 6 + * + */ void ICACHE_FLASH_ATTR breakdown_time(uint32_t time, struct tm *result) { uint32_t era, doe, yoe, mp; @@ -119,13 +159,27 @@ void ICACHE_FLASH_ATTR breakdown_time(uint32_t time, struct tm *result) mp = (5 * result->tm_yday + 2) / 153; result->tm_mday = result->tm_yday - (153 * mp + 2) / 5 + 1; result->tm_mon = mp + (mp < 10 ? 2 : -10); - if (result->tm_mon <=2) + if (result->tm_mon <= 2) result->tm_year++; /* result->tm_yday is March 1st indexed at this point; fix up */ result->tm_yday += 28 + 31; if (is_leap(result->tm_year)) result->tm_yday++; + + result->tm_isdst = is_dst(result); + if (result->tm_isdst) + result->tm_hour++; + if (result->tm_hour > 23) { + /* + * We can ignore fixing up the date at the end of month etc. + * because all we're actually displaying is the time. + */ + result->tm_hour = 0; + result->tm_wday++; + result->tm_mday++; + result->tm_yday++; + } } static void ICACHE_FLASH_ATTR ntp_udp_timeout(void *arg) @@ -160,7 +214,7 @@ static void ICACHE_FLASH_ATTR ntp_udp_recv(void *arg, char *pdata, ntp = (ntp_t *) pdata; timestamp = ntp->trans_time[0] << 24 | ntp->trans_time[1] << 16 | ntp->trans_time[2] << 8 | ntp->trans_time[3]; - // Convert to Unix time ms + // NTP 0 is 1st Jan 1900; convert to Unix time 0 of 1st Jan 1970 timestamp -= 2208988800ULL; // Store the time -- 2.39.5