Search code examples
pythondatetimeparsingmicropythoniso8601

Parsing an ISO datetime in MicroPython to get weekday


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.


Solution

  • 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}"