/** * TODO file description * * Created on 2019/09/13. */ #ifndef CSPEMU_DATETIME_H #define CSPEMU_DATETIME_H #include #include enum weekday { MONDAY = 1, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY }; _Static_assert(MONDAY==1, "enum weekday numbering Mon"); _Static_assert(SUNDAY==7, "enum weekday numbering Sun"); enum month { JANUARY = 1, FEBRUARY, MARCH, APRIL, MAY, JUNE, JULY, AUGUST, SEPTEMBER, OCTOBER, NOVEMBER, DECEMBER }; _Static_assert(JANUARY==1, "enum month numbering Jan"); _Static_assert(DECEMBER==12, "enum month numbering Dec"); /** Abbreviated weekday names */ extern const char *DT_WKDAY_NAMES[]; /** Full-length weekday names */ extern const char *DT_WKDAY_NAMES_FULL[]; /** Abbreviated month names */ extern const char *DT_MONTH_NAMES[]; /** Full-length month names */ extern const char *DT_MONTH_NAMES_FULL[]; typedef struct datetime { uint16_t year; enum month month; uint8_t day; uint8_t hour; uint8_t min; uint8_t sec; enum weekday wkday; // 1=monday } datetime_t; // Templates for printf #define DT_FORMAT_DATE "%d/%d/%d" #define DT_SUBS_DATE(dt) (dt).year, (dt).month, (dt).day #define DT_FORMAT_TIME "%d:%02d:%02d" #define DT_SUBS_TIME(dt) (dt).hour, (dt).min, (dt).sec #define DT_FORMAT_DATE_WK DT_FORMAT_WK " " DT_FORMAT_DATE #define DT_SUBS_DATE_WK(dt) DT_SUBS_WK(dt), DT_SUBS_DATE(dt) #define DT_FORMAT_WK "%s" #define DT_SUBS_WK(dt) DT_WKDAY_NAMES[(dt).wkday] #define DT_FORMAT_DATE_TIME DT_FORMAT_DATE " " DT_FORMAT_TIME #define DT_SUBS_DATE_TIME(dt) DT_SUBS_DATE(dt), DT_SUBS_TIME(dt) #define DT_FORMAT DT_FORMAT_DATE_WK " " DT_FORMAT_TIME #define DT_SUBS(dt) DT_SUBS_DATE_WK(dt), DT_SUBS_TIME(dt) // base century for two-digit year conversions #define DT_CENTURY 2000 // start year for weekday computation #define DT_START_YEAR 2019 // January 1st weekday of DT_START_YEAR #define DT_START_WKDAY TUESDAY // max date supported by 2-digit year RTC counters (it can't check Y%400==0 with only two digits) #define DT_END_YEAR 2399 typedef union __attribute__((packed)) { struct __attribute__((packed)) { uint8_t ones : 4; uint8_t tens : 4; }; uint8_t byte; } bcd_t; _Static_assert(sizeof(bcd_t) == 1, "Bad bcd_t len"); /** Check if a year is leap */ static inline bool is_leap_year(int year) { return year % 400 == 0 || (year % 4 == 0 && year % 100 != 0); } /** * Check if a datetime could be valid (ignores leap years) * * @param[in] dt * @return basic validations passed */ bool datetime_is_valid(const datetime_t *dt); /** * Set weekday based on a date in a given datetime * * @param[in,out] dt * @return success */ bool datetime_set_weekday(datetime_t *dt); /** * Get weekday for given a date * * @param year - year number * @param month - 1-based month number * @param day - 1-based day number * @return weekday */ enum weekday date_weekday(uint16_t year, enum month month, uint8_t day); #endif //CSPEMU_DATETIME_H