From f2be55e3efff550e5fdb474cab14c33170dc024d Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Fri, 11 Apr 2025 19:25:13 +0200 Subject: [PATCH] sys/fmt: split up scn_time_tm_iso8601() --- sys/fmt/fmt.c | 70 ++++++++++++++++++++++++++++++++--------------- sys/include/fmt.h | 44 +++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+), 22 deletions(-) diff --git a/sys/fmt/fmt.c b/sys/fmt/fmt.c index 199cd9c0f8..78d1dbb70c 100644 --- a/sys/fmt/fmt.c +++ b/sys/fmt/fmt.c @@ -619,12 +619,9 @@ ssize_t scn_buf_hex(void *_dest, size_t dest_len, const char *hex, size_t hex_le return len; } -int scn_time_tm_iso8601(struct tm *tm, const char *str, char separator) +int scn_time_tm_iso8601_date(struct tm *tm, const char *str) { - assert(tm); - assert(str); - memset(tm, 0, sizeof(*tm)); - tm->tm_isdst = -1; /* undefined */ + uint32_t num; if (!fmt_is_digit(str[0]) || !fmt_is_digit(str[1]) || !fmt_is_digit(str[2]) || !fmt_is_digit(str[3]) || @@ -635,34 +632,63 @@ int scn_time_tm_iso8601(struct tm *tm, const char *str, char separator) return -EINVAL; } - uint32_t num = scn_u32_dec(str, 4); + num = scn_u32_dec(&str[0], 4); tm->tm_year = num - 1900; - num = scn_u32_dec(str + 5, 2); + num = scn_u32_dec(&str[5], 2); tm->tm_mon = num - 1; - num = scn_u32_dec(str + 8, 2); + num = scn_u32_dec(&str[8], 2); tm->tm_mday = num; + return 10; +} + +int scn_time_tm_iso8601_time(struct tm *tm, const char *str) +{ + uint32_t num; + + if (!fmt_is_digit(str[0]) || !fmt_is_digit(str[1]) || + str[2] != ':' || + !fmt_is_digit(str[3]) || !fmt_is_digit(str[4]) || + str[5] != ':' || + !fmt_is_digit(str[6]) || !fmt_is_digit(str[7])) { + return -EINVAL; + } + + num = scn_u32_dec(&str[0], 2); + tm->tm_hour = num; + num = scn_u32_dec(&str[3], 2); + tm->tm_min = num; + num = scn_u32_dec(&str[6], 2); + tm->tm_sec = num; + + tm->tm_isdst = -1; /* undefined */ + + return 8; +} + +int scn_time_tm_iso8601(struct tm *tm, const char *str, char separator) +{ + assert(tm); + assert(str); + memset(tm, 0, sizeof(*tm)); + + int res = scn_time_tm_iso8601_date(tm, str); + if (res < 0) { + return res; + } + if (str[10] == '\0') { /* no time, just date */ - return 10; + return res; } if (str[10] != separator) { return -EBADF; } - if (!fmt_is_digit(str[11]) || !fmt_is_digit(str[12]) || - str[13] != ':' || - !fmt_is_digit(str[14]) || !fmt_is_digit(str[15]) || - str[16] != ':' || - !fmt_is_digit(str[17]) || !fmt_is_digit(str[18])) { - return -EINVAL; - } - num = scn_u32_dec(str + 11, 2); - tm->tm_hour = num; - num = scn_u32_dec(str + 14, 2); - tm->tm_min = num; - num = scn_u32_dec(str + 17, 2); - tm->tm_sec = num; + res = scn_time_tm_iso8601_time(tm, &str[11]); + if (res < 0) { + return res; + } return 19; } diff --git a/sys/include/fmt.h b/sys/include/fmt.h index 75a36a7648..32869ec14c 100644 --- a/sys/include/fmt.h +++ b/sys/include/fmt.h @@ -474,6 +474,48 @@ uint32_t scn_u32_hex(const char *str, size_t n); */ ssize_t scn_buf_hex(void *dest, size_t dest_len, const char *hex, size_t hex_len); +/** + * @brief Convert an ISO 8601 time string to time structure + * + * This function parses a string in the format YYYY-MM-DD. + * + * A terminating '\0' is not required. + * + * This function does only take care of format validity + * and not of date validity. + * + * @note This function will keep unrelated fields of @p tm intact. + * + * @param[out] tm Pointer to time structure + * @param[in] str Pointer to string to read from + * + * @return Number of characters read from @p str on success (10) + * + * @retval -EINVAL if @p str has an invalid format + */ +int scn_time_tm_iso8601_date(struct tm *tm, const char *str); + +/** + * @brief Convert an ISO 8601 date string to time structure + * + * This function parses a string in the format HH:MM:SS + * + * A terminating '\0' is not required. + * + * This function does only take care of format validity + * and not of time validity. + * + * @note This function will keep unrelated fields of @p tm intact. + * + * @param[out] tm Pointer to time structure + * @param[in] str Pointer to string to read from + * + * @return Number of characters read from @p str on success (8) + * + * @retval -EINVAL if @p str has an invalid format + */ +int scn_time_tm_iso8601_time(struct tm *tm, const char *str); + /** * @brief Convert an ISO 8601 string to time structure * @@ -485,6 +527,8 @@ ssize_t scn_buf_hex(void *dest, size_t dest_len, const char *hex, size_t hex_len * This function does only take care of format validity * and not of date/time validity. * + * @note This function will overwrite all fields of @p tm + * * @param[out] tm Pointer to time structure * @param[in] str Pointer to string to read from * @param[in] separator Date and time separator