#include #include #include #include "common_utils/datetime.h" const char *DT_WKDAY_NAMES[] = { [MONDAY] = "Mon", [TUESDAY] = "Tue", [WEDNESDAY] = "Wed", [THURSDAY] = "Thu", [FRIDAY] = "Fri", [SATURDAY] = "Sat", [SUNDAY] = "Sun" }; const char *DT_WKDAY_NAMES_FULL[] = { [MONDAY] = "Monday", [TUESDAY] = "Tuesday", [WEDNESDAY] = "Wednesday", [THURSDAY] = "Thursday", [FRIDAY] = "Friday", [SATURDAY] = "Saturday", [SUNDAY] = "Sunday" }; const char *DT_MONTH_NAMES[] = { [JANUARY] = "Jan", [FEBRUARY] = "Feb", [MARCH] = "Mar", [APRIL] = "Apr", [MAY] = "May", [JUNE] = "Jun", [JULY] = "Jul", [AUGUST] = "Aug", [SEPTEMBER] = "Sep", [OCTOBER] = "Oct", [NOVEMBER] = "Nov", [DECEMBER] = "Dec" }; const char *DT_MONTH_NAMES_FULL[] = { [JANUARY] = "January", [FEBRUARY] = "February", [MARCH] = "March", [APRIL] = "April", [MAY] = "May", [JUNE] = "June", [JULY] = "July", [AUGUST] = "August", [SEPTEMBER] = "September", [OCTOBER] = "October", [NOVEMBER] = "November", [DECEMBER] = "December" }; static const uint16_t MONTH_LENGTHS[] = { /* 1-based, normal year */ [JANUARY]=31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; _Static_assert(sizeof(MONTH_LENGTHS) / sizeof(uint16_t) == 13, "Months array length"); static const uint16_t MONTH_YEARDAYS[] = { /* 1-based */ [JANUARY]=0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 // // days until 1st of month }; _Static_assert(sizeof(MONTH_YEARDAYS) / sizeof(uint16_t) == 13, "Months array length"); _Static_assert(MONDAY < SUNDAY, "Weekday ordering"); bool datetime_is_valid(const datetime_t *dt) { if (dt == NULL) return false; // check month first to avoid out-of-bounds read from the MONTH_LENGTHS table if (!(dt->month >= JANUARY && dt->month <= DECEMBER)) return false; int monthlen = MONTH_LENGTHS[dt->month]; if (dt->month == FEBRUARY && is_leap_year(dt->year)) { monthlen = 29; } return dt->sec < 60 && dt->min < 60 && dt->hour < 24 && dt->wkday >= MONDAY && dt->wkday <= SUNDAY && dt->year >= DT_START_YEAR && dt->year <= DT_END_YEAR && dt->day >= 1 && dt->day <= monthlen; } bool datetime_set_weekday(datetime_t *dt) { dt->wkday = MONDAY; // prevent the validator func erroring out on invalid weekday if (!datetime_is_valid(dt)) return false; dt->wkday = date_weekday(dt->year, dt->month, dt->day); return true; } enum weekday date_weekday(uint16_t year, enum month month, uint8_t day) { uint16_t days = (DT_START_WKDAY - MONDAY) + (year - DT_START_YEAR) * 365 + MONTH_YEARDAYS[month] + (day - 1); for (uint16_t i = DT_START_YEAR; i <= year; i++) { if (is_leap_year(i) && (i < year || month > FEBRUARY)) days++; } return MONDAY + days % 7; }