Skip to content

Commit

Permalink
Add onCheckTimeZoneOffset() method to SystemClock, update demo
Browse files Browse the repository at this point in the history
  • Loading branch information
mikee47 committed Apr 23, 2024
1 parent 8cd057c commit 1c2cf76
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 3 deletions.
3 changes: 3 additions & 0 deletions Sming/Core/SystemClock.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ time_t SystemClockClass::now(TimeZone timeType) const
uint32_t systemTime = RTC.getRtcSeconds();

if(timeType == eTZ_Local) {
if(checkTimeZoneOffset) {
checkTimeZoneOffset(systemTime);
}
systemTime += timeZoneOffsetSecs;
}

Expand Down
27 changes: 27 additions & 0 deletions Sming/Core/SystemClock.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,23 @@ enum TimeZone {
class SystemClockClass
{
public:
/**
* @brief Optional callback which can be used to automate handling of timezone changes
* @param systemTime The current system time
*
* Although the timezone offset only changes twice a year, when it does change the
* corresponding offset should be updated promptly.
*
* `setTimeZoneOffset()` is typically called when updating via real-time clock chip or NTP,
* but this can still leave a considerable gap during which the local time will be wrong.
*
* The callback should check the provided systemTime and determine if the time zone offset
* requires changing and, if so, call `setTimeZoneOffset()`.
* One way to make this efficient is to cache the `time_t` value for the *next* change,
* rather than attemtpting to compute the offset on every call.
*/
using CheckTimeZoneOffset = Delegate<void(time_t systemTime)>;

/** @brief Get the current date and time
* @param timeType Time zone to use (UTC / local)
* @retval DateTime Current date and time
Expand Down Expand Up @@ -88,7 +105,17 @@ class SystemClockClass
return timeSet;
}

/**
* @brief Set/clear a callback which is invoked whenever local time is queried.
* @note This callback is *only* invoked when `now()` is called.
*/
void onCheckTimeZoneOffset(CheckTimeZoneOffset callback)
{
checkTimeZoneOffset = callback;
}

private:
CheckTimeZoneOffset checkTimeZoneOffset;
int timeZoneOffsetSecs = 0;
bool timeSet = false;
};
Expand Down
2 changes: 1 addition & 1 deletion Sming/Libraries/Timezone
37 changes: 35 additions & 2 deletions samples/SystemClock_NTP/app/NtpClientDemo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,21 @@ time_t getNextSunriseSet(bool isSunrise)
return t;
}

void checkTimeZoneOffset(time_t systemTime)
{
static time_t nextChange;
static const TimeChangeRule* rule;

if(!rule) {
tz.toLocal(systemTime, &rule);
} else if(systemTime < nextChange) {
return;
}

SystemClock.setTimeZoneOffset(rule->offset * SECS_PER_MIN);
nextChange = tz.getNextChange(systemTime, &rule);
}

} // namespace

void NtpClientDemo::ntpResult(NtpClient& client, time_t ntpTime)
Expand All @@ -46,9 +61,10 @@ void NtpClientDemo::ntpResult(NtpClient& client, time_t ntpTime)
* Update the system clock and calculate the correct time offset,
* accounting for time zone and daylight savings.
*/
auto localTime = tz.toLocal(ntpTime);
SystemClock.setTime(ntpTime, eTZ_UTC);
SystemClock.setTimeZoneOffset(localTime - ntpTime);

// Now we've set the clock, we can determine the initial active timezone and maintain the offset
SystemClock.onCheckTimeZoneOffset(checkTimeZoneOffset);

/*
* Display the new time
Expand All @@ -64,4 +80,21 @@ void NtpClientDemo::ntpResult(NtpClient& client, time_t ntpTime)
DateTime sunset = getNextSunriseSet(false);
Serial << _F("Next sunrise at ") << sunrise.toShortTimeString() << _F(", sunset at ") << sunset.toShortTimeString()
<< endl;

/*
* Display points at which daylight savings changes.
*/
DateTime dt(ntpTime);

auto& dstRule = tz.getRule(true);
DateTime dstDateTime = dstRule(dt.Year);
Serial << dstRule.tag << _F(" starts ") << dstDateTime.toHTTPDate() << endl;

auto& stdRule = tz.getRule(false);
DateTime stdDateTime = stdRule(dt.Year);
Serial << stdRule.tag << _F(" starts ") << stdDateTime.toHTTPDate() << endl;

const TimeChangeRule* rule;
time_t nextChange = tz.getNextChange(dt, &rule);
Serial << _F("Next change to ") << rule->tag << _F(" is ") << DateTime(nextChange).toHTTPDate() << endl;
}

0 comments on commit 1c2cf76

Please sign in to comment.