Parsing an ISO datetime in MicroPython to get weekday

200 Views Asked by At

Is there no way to parse an ISO datetime object in MicroPython? My Raspberry Pi Pico calls a REST API that contains date items in the ISO 8601 format:

{"title":"Green","date":"2023-10-18T00:00:00"}

but MicroPython only appears to have a time function, not a datetime function and the time function doesn't seem to be capable of parsing strings.

I basically need to turn ISO strings into "Wednesday 18" for example.

1

There are 1 best solutions below

2
On BEST ANSWER

There's an algorithm for determining the day of the week for a given date that works for dates back to 1753.

sample = {"title":"Green","date":"2023-10-18T00:00:00"}

def day_string_from_iso8601_date(date_str):
    month_keys = (1,4,4,0,2,5,0,3,6,1,4,6)
    days_of_week = ("Saturday", "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday")
    [yyyy, mm, dd] = [int(i) for i in date_str.split('T')[0].split('-')]
    leap_year_modifier = 0
    if ((yyyy % 400 == 0) or (yyyy % 100 != 0) and (yyyy % 4 == 0)) and mm in (1, 2):
        leap_year_modifier = -1
    a = yyyy % 100
    b = a // 4
    year_modifier = 0
    if yyyy < 1800:
        year_modifier = 4
    elif 1799 < yyyy < 1900:
        year_modifier = 2
    elif 1999 < yyyy < 2100:
        year_modifier = -1
    day = (a + b + dd + month_keys[mm-1] + leap_year_modifier + year_modifier) % 7
    return f"{days_of_week[day]} {dd}"


day_string_from_iso8601_date(sample["date"])

Output:

'Wednesday 18'

EDIT: There is a simpler way to solve this using the time module in Python or utime in Micropython. January 1 2000 fell on a Saturday. This piece of information along with the number of days to the date to be parsed can be used to calculate the week day.

Python's time.mktime() function takes a tuple containing 9 elements corresponding to struct_time as an argument and returns the seconds passed since epoch (1 January 1970).

import time

# January 1 2000 as dummy time struct
jan_1_2000 = (2000, 1, 1, 1, 0, 0, 0, 0, 0)
seconds_in_a_day = 24 * 60 * 60 # 86400
days_since_epoch = time.mktime(jan_1_2000) // seconds_in_a_day # 10957.0

Saturday, 1 January 2000 was 10,957 days after Thursday, 1 January 1970. The 86400 and 10957 constants can be used to save a little bit of computing power on the micro processor.

import utime

def day_string_from_iso8601(date_str):
    days_of_week = ("Saturday", "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday")
    [yyyy, mm, dd] = [int(i) for i in date_str.split('T')[0].split('-')]
    the_date = (yyyy, mm, dd, 1, 0, 0, 0, 0, 0)
    day = int((utime.mktime(the_date) // 86400) - 10957) % 7
    return f"{days_of_week[day]} {dd}"