Category Archives: ESP32

All things ESP32 embedded

Micropython – Adjusting for Daylight Savings and Updating the RTC of the SBC

So you are using ‘ntptime.settime()’ in Micropython to update the time in your script for whatever purpose you are using it for and you want to adjust for Daylight Savings.  Micropython doesn’t support in the ntptime module handling that automatically, so here is a short work around to adjust the time appropriately for your RTC.

Here’s my time sync function that I use, it’s pretty self explanatory as far as the code.  Adjust it to your needs as you see fit.

# Connect to wifi and synchronize the RTC time from NTP
def sync_time():
    global cset, year, month, day, wd, hour, minute, second

    # Reset the RTC time, reset if not
    try:
        rtc.datetime((2023, 1, 1, 0, 0, 0, 0, 0))  # Reset to a known good time
        year, month, day, wd, hour, minute, second, _ = rtc.datetime()
        if not all(isinstance(x, int) for x in [year, month, day, wd, hour, minute, second]):
            raise ValueError("Invalid time values in RTC")
    except (ValueError, OSError) as e:
        print(f"RTC reset required: {e}")
        rtc.datetime((2023, 1, 1, 0, 0, 0, 0, 0))  # Reset to a known good time
        year, month, day, wd, hour, minute, second, _ = rtc.datetime()
    
    if not net:
        return
    if net:
        try:
            ntptime.settime()
            print("Time set")
            cset = True
        except OSError as e:
            print(f'Exception setting time {e}')
            cset = False
    
        # Get the current time in UTC
    y, mnth, d, h, m, s, wkd, yearday = time.localtime()

    # Create a time tuple for January 1st of the current year (standard time)
    jan_1st = (year, 1, 1, 0, 0, 0, 0, 0)

    # Create a time tuple for July 1st of the current year (daylight saving time, if applicable)
    jul_1st = (year, 7, 1, 0, 0, 0, 0, 0)

    # Determine if daylight saving time (CDT) is in effect
    is_dst = time.localtime(time.mktime(jul_1st))[3] != time.localtime(time.mktime(jan_1st))[3]

    # Set the appropriate UTC offset
    utc_offset = -5  # CST

    if is_dst:
        utc_offset = -6  # CDT
    hour = (h + utc_offset) % 24

    # If hour became 0 after modulo, it means we crossed into the previous day
    if hour == 0 and h + utc_offset < 0:
        # Decrement the day, handling month/year transitions if necessary
        d -= 1
        if d == 0:
            mnth -= 1
            if mnth == 0:
                y -= 1
                mnth = 12
            # Adjust for the number of days in the previous month
            d = 31  # Start with the assumption of 31 days
            if mnth in [4, 6, 9, 11]:
                d = 30
            elif mnth == 2:
                d = 29 if (y % 4 == 0 and (y % 100 != 0 or y % 400 == 0)) else 28

    # Check all values before setting RTC
    if not (1 <= mnth <= 12 and 1 <= d <= 31 and 0 <= wkd <= 6 and 0 <= hour <= 23 and 0 <= m <= 59 and 0 <= s <= 59):
        print(f'Month: {mnth}, Day: {d}, WkDay: {wkd}, Hour: {hour}, Minute: {m}, Second: {s}')
        print("Invalid time values detected, skipping RTC update")
    else:
        try:
            rtc.datetime((y, mnth, d, wkd, hour, m, s, 0))
        except Exception as e:
            print(f'Exception setting time: {e}')

    print("Time set in sync_time function!")

That’s it, pretty simple, just clear the RTC and grab the time from NTP and then adjust for the time zone offset and then do the final adjustment for DST or not.

John