]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
move fr_unix_time_from_str() to time.c
authorAlan T. DeKok <aland@freeradius.org>
Thu, 28 Oct 2021 12:35:29 +0000 (08:35 -0400)
committerAlan T. DeKok <aland@freeradius.org>
Thu, 28 Oct 2021 12:52:04 +0000 (08:52 -0400)
src/lib/util/misc.c
src/lib/util/misc.h
src/lib/util/time.c
src/lib/util/time.h

index e0ec8642a7d7c58d116819cac22eb8e45e3d4b51..b35fcd33442882386595d9b8af455b3aaa82e9d5 100644 (file)
@@ -39,10 +39,6 @@ RCSID("$Id$")
                a[0] = ((uint16_t) (val)) & 0xff;\
        } while (0)
 
-static char const *months[] = {
-       "jan", "feb", "mar", "apr", "may", "jun",
-       "jul", "aug", "sep", "oct", "nov", "dec" };
-
 /** Sets a signal handler using sigaction if available, else signal
  *
  * @param sig to set handler for.
@@ -495,373 +491,6 @@ size_t fr_snprint_uint128(char *out, size_t outlen, uint128_t const num)
 
        return strlcpy(out, p, outlen);
 }
-
-/*
- *     Sort of strtok/strsep function.
- */
-static char *mystrtok(char **ptr, char const *sep)
-{
-       char    *res;
-
-       if (**ptr == '\0') return NULL;
-
-       while (**ptr && strchr(sep, **ptr)) (*ptr)++;
-
-       if (**ptr == '\0') return NULL;
-
-       res = *ptr;
-       while (**ptr && strchr(sep, **ptr) == NULL) (*ptr)++;
-
-       if (**ptr != '\0') *(*ptr)++ = '\0';
-
-       return res;
-}
-
-/*
- *     Helper function to get a 2-digit date. With a maximum value,
- *     and a terminating character.
- */
-static int get_part(char **str, int *date, int min, int max, char term, char const *name)
-{
-       char *p = *str;
-
-       if (!isdigit((int) *p) || !isdigit((int) p[1])) return -1;
-       *date = (p[0] - '0') * 10  + (p[1] - '0');
-
-       if (*date < min) {
-               fr_strerror_printf("Invalid %s (too small)", name);
-               return -1;
-       }
-
-       if (*date > max) {
-               fr_strerror_printf("Invalid %s (too large)", name);
-               return -1;
-       }
-
-       p += 2;
-       if (!term) {
-               *str = p;
-               return 0;
-       }
-
-       if (*p != term) {
-               fr_strerror_printf("Expected '%c' after %s, got '%c'",
-                                  term, name, *p);
-               return -1;
-       }
-       p++;
-
-       *str = p;
-       return 0;
-}
-
-/** Convert string in various formats to a fr_unix_time_t
- *
- * @param date_str input date string.
- * @param date time_t to write result to.
- * @param[in] hint     scale for the parsing.  Default is "seconds"
- * @return
- *     - 0 on success.
- *     - -1 on failure.
- */
-int fr_unix_time_from_str(fr_unix_time_t *date, char const *date_str, fr_time_res_t hint)
-{
-       int             i;
-       int64_t         tmp;
-       struct tm       *tm, s_tm;
-       char            buf[64];
-       char            *p;
-       char            *f[4];
-       char            *tail = NULL;
-       fr_time_delta_t gmtoff = fr_time_delta_wrap(0);
-
-       /*
-        *      Test for unix timestamp, which is just a number and
-        *      nothing else.
-        */
-       tmp = strtoul(date_str, &tail, 10);
-       if (*tail == '\0') {
-               *date = fr_unix_time_from_nsec(fr_time_scale(tmp, hint));
-               return 0;
-       }
-
-       tm = &s_tm;
-       memset(tm, 0, sizeof(*tm));
-       tm->tm_isdst = -1;      /* don't know, and don't care about DST */
-
-       /*
-        *      Check for RFC 3339 dates.  Note that we only support
-        *      dates in a ~1000 year period.  If the server is being
-        *      used after 3000AD, someone can patch it then.
-        *
-        *      %Y-%m-%dT%H:%M:%S
-        *      [.%d] sub-seconds
-        *      Z | (+/-)%H:%M time zone offset
-        *
-        */
-       if ((tmp > 1900) && (tmp < 3000) && *tail == '-') {
-               unsigned long subseconds;
-               int tz, tz_hour, tz_min;
-
-               p = tail + 1;
-               s_tm.tm_year = tmp - 1900; /* 'struct tm' starts years in 1900 */
-
-               if (get_part(&p, &s_tm.tm_mon, 1, 13, '-', "month") < 0) return -1;
-               s_tm.tm_mon--;  /* ISO is 1..12, where 'struct tm' is 0..11 */
-
-               if (get_part(&p, &s_tm.tm_mday, 1, 31, 'T', "day") < 0) return -1;
-               if (get_part(&p, &s_tm.tm_hour, 0, 23, ':', "hour") < 0) return -1;
-               if (get_part(&p, &s_tm.tm_min, 0, 59, ':', "minute") < 0) return -1;
-               if (get_part(&p, &s_tm.tm_sec, 0, 60, '\0', "seconds") < 0) return -1;
-
-               if (*p == '.') {
-                       p++;
-                       subseconds = strtoul(p, &tail, 10);
-                       if (subseconds > NSEC) {
-                               fr_strerror_const("Invalid nanosecond specifier");
-                               return -1;
-                       }
-
-                       /*
-                        *      Scale subseconds to nanoseconds by how
-                        *      many digits were parsed/
-                        */
-                       if ((tail - p) < 9) {
-                               for (i = 0; i < 9 - (tail -p); i++) {
-                                       subseconds *= 10;
-                               }
-                       }
-
-                       p = tail;
-               } else {
-                       subseconds = 0;
-               }
-
-               /*
-                *      Time zone is GMT.  Leave well enough
-                *      alone.
-                */
-               if (*p == 'Z') {
-                       if (p[1] != '\0') {
-                               fr_strerror_printf("Unexpected text '%c' after time zone", p[1]);
-                               return -1;
-                       }
-                       tz = 0;
-                       goto done;
-               }
-
-               if ((*p != '+') && (*p != '-')) {
-                       fr_strerror_printf("Invalid time zone specifier '%c'", *p);
-                       return -1;
-               }
-               tail = p;       /* remember sign for later */
-               p++;
-
-               if (get_part(&p, &tz_hour, 0, 23, ':', "hour in time zone") < 0) return -1;
-               if (get_part(&p, &tz_min, 0, 59, '\0', "minute in time zone") < 0) return -1;
-
-               if (*p != '\0') {
-                       fr_strerror_printf("Unexpected text '%c' after time zone", *p);
-                       return -1;
-               }
-
-               /*
-                *      We set the time zone, but the timegm()
-                *      function ignores it.  Note also that mktime()
-                *      ignores it too, and treats the time zone as
-                *      local.
-                *
-                *      We can't store this value in s_tm.gtmoff,
-                *      because the timegm() function helpfully zeros
-                *      it out.
-                *
-                *      So insyead of using stupid C library
-                *      functions, we just roll our own.
-                */
-               tz = tz_hour * 3600 + tz_min;
-               if (*tail == '-') tz *= -1;
-
-       done:
-               tm->tm_gmtoff = tz;
-               *date = fr_unix_time_add(fr_unix_time_from_tm(tm), fr_time_delta_wrap(subseconds));
-               return 0;
-       }
-
-       /*
-        *      Try to parse dates via locale-specific names,
-        *      using the same format string as strftime().
-        *
-        *      If that fails, then we fall back to our parsing
-        *      routine, which is much more forgiving.
-        */
-
-#ifdef __APPLE__
-       /*
-        *      OSX "man strptime" says it only accepts the local time zone, and GMT.
-        *
-        *      However, when printing dates via strftime(), it prints
-        *      "UTC" instead of "GMT".  So... we have to fix it up
-        *      for stupid nonsense.
-        */
-       {
-               char const *tz = strstr(date_str, "UTC");
-               if (tz) {
-                       char *my_str;
-
-                       my_str = talloc_strdup(NULL, date_str);
-                       if (my_str) {
-                               p = my_str + (tz - date_str);
-                               memcpy(p, "GMT", 3);
-
-                               p = strptime(my_str, "%b %e %Y %H:%M:%S %Z", tm);
-                               if (p && (*p == '\0')) {
-                                       talloc_free(my_str);
-                                       *date = fr_unix_time_from_tm(tm);
-                                       return 0;
-                               }
-                               talloc_free(my_str);
-                       }
-               }
-       }
-#endif
-
-       p = strptime(date_str, "%b %e %Y %H:%M:%S %Z", tm);
-       if (p && (*p == '\0')) {
-               *date = fr_unix_time_from_tm(tm);
-               return 0;
-       }
-
-       strlcpy(buf, date_str, sizeof(buf));
-
-       p = buf;
-       f[0] = mystrtok(&p, " \t");
-       f[1] = mystrtok(&p, " \t");
-       f[2] = mystrtok(&p, " \t");
-       f[3] = mystrtok(&p, " \t"); /* may, or may not, be present */
-       if (!f[0] || !f[1] || !f[2]) {
-               fr_strerror_const("Too few fields");
-               return -1;
-       }
-
-       /*
-        *      Try to parse the time zone.  If it's GMT / UTC or a
-        *      local time zone we're OK.
-        *
-        *      Otherwise, ignore errors and assume GMT.
-        */
-       if (*p != '\0') {
-               fr_skip_whitespace(p);
-               (void) fr_time_delta_from_time_zone(p, &gmtoff);
-       }
-
-       /*
-        *      The time has a colon, where nothing else does.
-        *      So if we find it, bubble it to the back of the list.
-        */
-       if (f[3]) {
-               for (i = 0; i < 3; i++) {
-                       if (strchr(f[i], ':')) {
-                               p = f[3];
-                               f[3] = f[i];
-                               f[i] = p;
-                               break;
-                       }
-               }
-       }
-
-       /*
-        *  The month is text, which allows us to find it easily.
-        */
-       tm->tm_mon = 12;
-       for (i = 0; i < 3; i++) {
-               if (isalpha((int) *f[i])) {
-                       int j;
-
-                       /*
-                        *  Bubble the month to the front of the list
-                        */
-                       p = f[0];
-                       f[0] = f[i];
-                       f[i] = p;
-
-                       for (j = 0; j < 12; j++) {
-                               if (strncasecmp(months[j], f[0], 3) == 0) {
-                                       tm->tm_mon = j;
-                                       break;
-                               }
-                       }
-               }
-       }
-
-       /* month not found? */
-       if (tm->tm_mon == 12) {
-               fr_strerror_const("No month found");
-               return -1;
-       }
-
-       /*
-        *  The year may be in f[1], or in f[2]
-        */
-       tm->tm_year = atoi(f[1]);
-       tm->tm_mday = atoi(f[2]);
-
-       if (tm->tm_year >= 1900) {
-               tm->tm_year -= 1900;
-
-       } else {
-               /*
-                *  We can't use 2-digit years any more, they make it
-                *  impossible to tell what's the day, and what's the year.
-                */
-               if (tm->tm_mday < 1900) {
-                       fr_strerror_const("Invalid year < 1900");
-                       return -1;
-               }
-
-               /*
-                *  Swap the year and the day.
-                */
-               i = tm->tm_year;
-               tm->tm_year = tm->tm_mday - 1900;
-               tm->tm_mday = i;
-       }
-
-       /*
-        *  If the day is out of range, die.
-        */
-       if ((tm->tm_mday < 1) || (tm->tm_mday > 31)) {
-               fr_strerror_const("Invalid day of month");
-               return -1;
-       }
-
-       /*
-        *      There may be %H:%M:%S.  Parse it in a hacky way.
-        */
-       if (f[3]) {
-               f[0] = f[3];    /* HH */
-               f[1] = strchr(f[0], ':'); /* find : separator */
-               if (!f[1]) {
-                       fr_strerror_const("No ':' after hour");
-                       return -1;
-               }
-
-               *(f[1]++) = '\0'; /* nuke it, and point to MM:SS */
-
-               f[2] = strchr(f[1], ':'); /* find : separator */
-               if (f[2]) {
-                       *(f[2]++) = '\0';       /* nuke it, and point to SS */
-                       tm->tm_sec = atoi(f[2]);
-               }                       /* else leave it as zero */
-
-               tm->tm_hour = atoi(f[0]);
-               tm->tm_min = atoi(f[1]);
-       }
-
-       *date = fr_unix_time_add(fr_unix_time_from_tm(tm), gmtoff);
-
-       return 0;
-}
-
 int fr_size_from_str(size_t *out, char const *str)
 {
        char            *q = NULL;
index 40bae2b87f8344fcea0fc4d8bda2d6c0d88047d7..dead5f8aecedd4e113c6e838651b3412c5023fd7 100644 (file)
@@ -199,7 +199,6 @@ int         fr_blocking(int fd);
 ssize_t                fr_writev(int fd, struct iovec vector[], int iovcnt, fr_time_delta_t timeout);
 ssize_t                fr_utf8_to_ucs2(uint8_t *out, size_t outlen, char const *in, size_t inlen);
 size_t         fr_snprint_uint128(char *out, size_t outlen, uint128_t const num);
-int            fr_unix_time_from_str(fr_unix_time_t *date, char const *date_str, fr_time_res_t hint);
 
 bool           fr_multiply(uint64_t *result, uint64_t lhs, uint64_t rhs);
 uint64_t       fr_multiply_mod(uint64_t lhs, uint64_t rhs, uint64_t mod);
index 9e745cd585edd68b886299a8039558c5c17ada75..4378d7406a71d0569fa498fe674fccf2c8ed25da 100644 (file)
@@ -690,3 +690,375 @@ int64_t   fr_time_scale(int64_t t, fr_time_res_t hint)
 
        return t * scale;
 }
+
+
+/*
+ *     Sort of strtok/strsep function.
+ */
+static char *mystrtok(char **ptr, char const *sep)
+{
+       char    *res;
+
+       if (**ptr == '\0') return NULL;
+
+       while (**ptr && strchr(sep, **ptr)) (*ptr)++;
+
+       if (**ptr == '\0') return NULL;
+
+       res = *ptr;
+       while (**ptr && strchr(sep, **ptr) == NULL) (*ptr)++;
+
+       if (**ptr != '\0') *(*ptr)++ = '\0';
+
+       return res;
+}
+
+/*
+ *     Helper function to get a 2-digit date. With a maximum value,
+ *     and a terminating character.
+ */
+static int get_part(char **str, int *date, int min, int max, char term, char const *name)
+{
+       char *p = *str;
+
+       if (!isdigit((int) *p) || !isdigit((int) p[1])) return -1;
+       *date = (p[0] - '0') * 10  + (p[1] - '0');
+
+       if (*date < min) {
+               fr_strerror_printf("Invalid %s (too small)", name);
+               return -1;
+       }
+
+       if (*date > max) {
+               fr_strerror_printf("Invalid %s (too large)", name);
+               return -1;
+       }
+
+       p += 2;
+       if (!term) {
+               *str = p;
+               return 0;
+       }
+
+       if (*p != term) {
+               fr_strerror_printf("Expected '%c' after %s, got '%c'",
+                                  term, name, *p);
+               return -1;
+       }
+       p++;
+
+       *str = p;
+       return 0;
+}
+
+static char const *months[] = {
+       "jan", "feb", "mar", "apr", "may", "jun",
+       "jul", "aug", "sep", "oct", "nov", "dec" };
+
+
+/** Convert string in various formats to a fr_unix_time_t
+ *
+ * @param date_str input date string.
+ * @param date time_t to write result to.
+ * @param[in] hint     scale for the parsing.  Default is "seconds"
+ * @return
+ *     - 0 on success.
+ *     - -1 on failure.
+ */
+int fr_unix_time_from_str(fr_unix_time_t *date, char const *date_str, fr_time_res_t hint)
+{
+       int             i;
+       int64_t         tmp;
+       struct tm       *tm, s_tm;
+       char            buf[64];
+       char            *p;
+       char            *f[4];
+       char            *tail = NULL;
+       fr_time_delta_t gmt_delta = fr_time_delta_wrap(0);
+
+       /*
+        *      Test for unix timestamp, which is just a number and
+        *      nothing else.
+        */
+       tmp = strtoul(date_str, &tail, 10);
+       if (*tail == '\0') {
+               *date = fr_unix_time_from_nsec(fr_time_scale(tmp, hint));
+               return 0;
+       }
+
+       tm = &s_tm;
+       memset(tm, 0, sizeof(*tm));
+       tm->tm_isdst = -1;      /* don't know, and don't care about DST */
+
+       /*
+        *      Check for RFC 3339 dates.  Note that we only support
+        *      dates in a ~1000 year period.  If the server is being
+        *      used after 3000AD, someone can patch it then.
+        *
+        *      %Y-%m-%dT%H:%M:%S
+        *      [.%d] sub-seconds
+        *      Z | (+/-)%H:%M time zone offset
+        *
+        */
+       if ((tmp > 1900) && (tmp < 3000) && *tail == '-') {
+               unsigned long subseconds;
+               int tz, tz_hour, tz_min;
+
+               p = tail + 1;
+               s_tm.tm_year = tmp - 1900; /* 'struct tm' starts years in 1900 */
+
+               if (get_part(&p, &s_tm.tm_mon, 1, 13, '-', "month") < 0) return -1;
+               s_tm.tm_mon--;  /* ISO is 1..12, where 'struct tm' is 0..11 */
+
+               if (get_part(&p, &s_tm.tm_mday, 1, 31, 'T', "day") < 0) return -1;
+               if (get_part(&p, &s_tm.tm_hour, 0, 23, ':', "hour") < 0) return -1;
+               if (get_part(&p, &s_tm.tm_min, 0, 59, ':', "minute") < 0) return -1;
+               if (get_part(&p, &s_tm.tm_sec, 0, 60, '\0', "seconds") < 0) return -1;
+
+               if (*p == '.') {
+                       p++;
+                       subseconds = strtoul(p, &tail, 10);
+                       if (subseconds > NSEC) {
+                               fr_strerror_const("Invalid nanosecond specifier");
+                               return -1;
+                       }
+
+                       /*
+                        *      Scale subseconds to nanoseconds by how
+                        *      many digits were parsed/
+                        */
+                       if ((tail - p) < 9) {
+                               for (i = 0; i < 9 - (tail -p); i++) {
+                                       subseconds *= 10;
+                               }
+                       }
+
+                       p = tail;
+               } else {
+                       subseconds = 0;
+               }
+
+               /*
+                *      Time zone is GMT.  Leave well enough
+                *      alone.
+                */
+               if (*p == 'Z') {
+                       if (p[1] != '\0') {
+                               fr_strerror_printf("Unexpected text '%c' after time zone", p[1]);
+                               return -1;
+                       }
+                       tz = 0;
+                       goto done;
+               }
+
+               if ((*p != '+') && (*p != '-')) {
+                       fr_strerror_printf("Invalid time zone specifier '%c'", *p);
+                       return -1;
+               }
+               tail = p;       /* remember sign for later */
+               p++;
+
+               if (get_part(&p, &tz_hour, 0, 23, ':', "hour in time zone") < 0) return -1;
+               if (get_part(&p, &tz_min, 0, 59, '\0', "minute in time zone") < 0) return -1;
+
+               if (*p != '\0') {
+                       fr_strerror_printf("Unexpected text '%c' after time zone", *p);
+                       return -1;
+               }
+
+               /*
+                *      We set the time zone, but the timegm()
+                *      function ignores it.  Note also that mktime()
+                *      ignores it too, and treats the time zone as
+                *      local.
+                *
+                *      We can't store this value in s_tm.gtmoff,
+                *      because the timegm() function helpfully zeros
+                *      it out.
+                *
+                *      So insyead of using stupid C library
+                *      functions, we just roll our own.
+                */
+               tz = tz_hour * 3600 + tz_min;
+               if (*tail == '-') tz *= -1;
+
+       done:
+               tm->tm_gmtoff = tz;
+               *date = fr_unix_time_add(fr_unix_time_from_tm(tm), fr_time_delta_wrap(subseconds));
+               return 0;
+       }
+
+       /*
+        *      Try to parse dates via locale-specific names,
+        *      using the same format string as strftime().
+        *
+        *      If that fails, then we fall back to our parsing
+        *      routine, which is much more forgiving.
+        */
+
+#ifdef __APPLE__
+       /*
+        *      OSX "man strptime" says it only accepts the local time zone, and GMT.
+        *
+        *      However, when printing dates via strftime(), it prints
+        *      "UTC" instead of "GMT".  So... we have to fix it up
+        *      for stupid nonsense.
+        */
+       {
+               char const *tz = strstr(date_str, "UTC");
+               if (tz) {
+                       char *my_str;
+
+                       my_str = talloc_strdup(NULL, date_str);
+                       if (my_str) {
+                               p = my_str + (tz - date_str);
+                               memcpy(p, "GMT", 3);
+
+                               p = strptime(my_str, "%b %e %Y %H:%M:%S %Z", tm);
+                               if (p && (*p == '\0')) {
+                                       talloc_free(my_str);
+                                       *date = fr_unix_time_from_tm(tm);
+                                       return 0;
+                               }
+                               talloc_free(my_str);
+                       }
+               }
+       }
+#endif
+
+       p = strptime(date_str, "%b %e %Y %H:%M:%S %Z", tm);
+       if (p && (*p == '\0')) {
+               *date = fr_unix_time_from_tm(tm);
+               return 0;
+       }
+
+       strlcpy(buf, date_str, sizeof(buf));
+
+       p = buf;
+       f[0] = mystrtok(&p, " \t");
+       f[1] = mystrtok(&p, " \t");
+       f[2] = mystrtok(&p, " \t");
+       f[3] = mystrtok(&p, " \t"); /* may, or may not, be present */
+       if (!f[0] || !f[1] || !f[2]) {
+               fr_strerror_const("Too few fields");
+               return -1;
+       }
+
+       /*
+        *      Try to parse the time zone.  If it's GMT / UTC or a
+        *      local time zone we're OK.
+        *
+        *      Otherwise, ignore errors and assume GMT.
+        */
+       if (*p != '\0') {
+               fr_skip_whitespace(p);
+               (void) fr_time_delta_from_time_zone(p, &gmt_delta);
+       }
+
+       /*
+        *      The time has a colon, where nothing else does.
+        *      So if we find it, bubble it to the back of the list.
+        */
+       if (f[3]) {
+               for (i = 0; i < 3; i++) {
+                       if (strchr(f[i], ':')) {
+                               p = f[3];
+                               f[3] = f[i];
+                               f[i] = p;
+                               break;
+                       }
+               }
+       }
+
+       /*
+        *  The month is text, which allows us to find it easily.
+        */
+       tm->tm_mon = 12;
+       for (i = 0; i < 3; i++) {
+               if (isalpha((int) *f[i])) {
+                       int j;
+
+                       /*
+                        *  Bubble the month to the front of the list
+                        */
+                       p = f[0];
+                       f[0] = f[i];
+                       f[i] = p;
+
+                       for (j = 0; j < 12; j++) {
+                               if (strncasecmp(months[j], f[0], 3) == 0) {
+                                       tm->tm_mon = j;
+                                       break;
+                               }
+                       }
+               }
+       }
+
+       /* month not found? */
+       if (tm->tm_mon == 12) {
+               fr_strerror_const("No month found");
+               return -1;
+       }
+
+       /*
+        *  The year may be in f[1], or in f[2]
+        */
+       tm->tm_year = atoi(f[1]);
+       tm->tm_mday = atoi(f[2]);
+
+       if (tm->tm_year >= 1900) {
+               tm->tm_year -= 1900;
+
+       } else {
+               /*
+                *  We can't use 2-digit years any more, they make it
+                *  impossible to tell what's the day, and what's the year.
+                */
+               if (tm->tm_mday < 1900) {
+                       fr_strerror_const("Invalid year < 1900");
+                       return -1;
+               }
+
+               /*
+                *  Swap the year and the day.
+                */
+               i = tm->tm_year;
+               tm->tm_year = tm->tm_mday - 1900;
+               tm->tm_mday = i;
+       }
+
+       /*
+        *  If the day is out of range, die.
+        */
+       if ((tm->tm_mday < 1) || (tm->tm_mday > 31)) {
+               fr_strerror_const("Invalid day of month");
+               return -1;
+       }
+
+       /*
+        *      There may be %H:%M:%S.  Parse it in a hacky way.
+        */
+       if (f[3]) {
+               f[0] = f[3];    /* HH */
+               f[1] = strchr(f[0], ':'); /* find : separator */
+               if (!f[1]) {
+                       fr_strerror_const("No ':' after hour");
+                       return -1;
+               }
+
+               *(f[1]++) = '\0'; /* nuke it, and point to MM:SS */
+
+               f[2] = strchr(f[1], ':'); /* find : separator */
+               if (f[2]) {
+                       *(f[2]++) = '\0';       /* nuke it, and point to SS */
+                       tm->tm_sec = atoi(f[2]);
+               }                       /* else leave it as zero */
+
+               tm->tm_hour = atoi(f[0]);
+               tm->tm_min = atoi(f[1]);
+       }
+
+       *date = fr_unix_time_add(fr_unix_time_from_tm(tm), gmt_delta);
+
+       return 0;
+}
index 78e4b6edd3363877e1800d55f3c09ba217bcfd58..3be05a2478435ff17d88e5ec62c4d5ebd7ffaef4 100644 (file)
@@ -663,7 +663,9 @@ int64_t             fr_time_delta_scale(fr_time_delta_t delta, fr_time_res_t hint);
 
 void           fr_time_elapsed_update(fr_time_elapsed_t *elapsed, fr_time_t start, fr_time_t end) CC_HINT(nonnull);
 void           fr_time_elapsed_fprint(FILE *fp, fr_time_elapsed_t const *elapsed, char const *prefix, int tabs) CC_HINT(nonnull(1,2));
+
 fr_unix_time_t fr_unix_time_from_tm(struct tm *tm) CC_HINT(nonnull);
+int            fr_unix_time_from_str(fr_unix_time_t *date, char const *date_str, fr_time_res_t hint);
 
 #ifdef __cplusplus
 }