[FFmpeg-devel] [PATCH 1/2] lavu/utils: add av_parse_iso8601_tz; use it in time parsing functions

Rodger Combs rodger.combs at gmail.com
Wed Nov 11 06:20:42 CET 2015


---
 libavformat/utils.c    | 20 ++++++++++++--------
 libavutil/parseutils.c | 43 +++++++++++++++++++++++++++++++++++++++++--
 libavutil/parseutils.h | 18 +++++++++++++++---
 3 files changed, 68 insertions(+), 13 deletions(-)

diff --git a/libavformat/utils.c b/libavformat/utils.c
index 5c4d452..f70f91e 100644
--- a/libavformat/utils.c
+++ b/libavformat/utils.c
@@ -4168,14 +4168,18 @@ int ff_find_stream_index(AVFormatContext *s, int id)
 
 int64_t ff_iso8601_to_unix_time(const char *datestr)
 {
-    struct tm time1 = { 0 }, time2 = { 0 };
-    const char *ret1, *ret2;
-    ret1 = av_small_strptime(datestr, "%Y - %m - %d %T", &time1);
-    ret2 = av_small_strptime(datestr, "%Y - %m - %dT%T", &time2);
-    if (ret2 && !ret1)
-        return av_timegm(&time2);
-    else
-        return av_timegm(&time1);
+    struct tm time = { 0 };
+    const char *ret = av_small_strptime(datestr, "%Y - %m - %d %T", &time);
+    if (!ret)
+        ret = av_small_strptime(datestr, "%Y - %m - %dT%T", &time);
+    if (ret) {
+        const char *ret2 = av_parse_iso8601_tz(ret, &time);
+        if (ret2)
+            ret = ret2;
+        return av_timegm(&time);
+    } else {
+        return -1;
+    }
 }
 
 int avformat_query_codec(const AVOutputFormat *ofmt, enum AVCodecID codec_id,
diff --git a/libavutil/parseutils.c b/libavutil/parseutils.c
index 9fb8d0a..ff47d35 100644
--- a/libavutil/parseutils.c
+++ b/libavutil/parseutils.c
@@ -536,6 +536,40 @@ char *av_small_strptime(const char *p, const char *fmt, struct tm *dt)
     return (char*)p;
 }
 
+char *av_parse_iso8601_tz(const char *p, struct tm *dt)
+{
+    if (!p || !*p)
+        return NULL;
+    if (*p == 'Z' || *p == 'z') {
+        p++;
+    } else if (*p == '-' || *p == '+') {
+        int neg = (*p == '+') ? -1 : 1;
+        const char *min;
+        p++;
+        if (p[0] < '0' || p[0] > '9' ||
+            p[1] < '0' || p[1] > '9')
+            return NULL;
+        dt->tm_hour += neg * (
+            (p[0] - '0') * 10 +
+            (p[1] - '0'));
+        p += 2;
+        min = p;
+        if (*min == ':')
+            min++;
+        if (min[0] >= '0' && min[0] <= '9' &&
+            min[1] >= '0' && min[1] <= '9') {
+            dt->tm_min += neg * (
+                (min[0] - '0') * 10 +
+                (min[1] - '0'));
+            p = min + 2;
+        }
+    } else {
+        return NULL;
+    }
+
+    return (char*)p;
+}
+
 time_t av_timegm(struct tm *tm)
 {
     time_t t;
@@ -652,8 +686,13 @@ int av_parse_time(int64_t *timeval, const char *timestr, int duration)
     if (duration) {
         t = dt.tm_hour * 3600 + dt.tm_min * 60 + dt.tm_sec;
     } else {
-        int is_utc = *q == 'Z' || *q == 'z';
-        q += is_utc;
+        int is_utc = 0;
+        const char *ptz = av_parse_iso8601_tz(q, &dt);
+        if (ptz) {
+            is_utc = 1;
+            q = ptz;
+        }
+
         if (today) { /* fill in today's date */
             struct tm dt2 = is_utc ? *gmtime_r(&now, &tmbuf) : *localtime_r(&now, &tmbuf);
             dt2.tm_hour = dt.tm_hour;
diff --git a/libavutil/parseutils.h b/libavutil/parseutils.h
index e66d24b..673d750 100644
--- a/libavutil/parseutils.h
+++ b/libavutil/parseutils.h
@@ -125,12 +125,12 @@ const char *av_get_known_color_name(int color_idx, const uint8_t **rgb);
  * @param timestr a string representing a date or a duration.
  * - If a date the syntax is:
  * @code
- * [{YYYY-MM-DD|YYYYMMDD}[T|t| ]]{{HH:MM:SS[.m...]]]}|{HHMMSS[.m...]]]}}[Z]
+ * [{YYYY-MM-DD|YYYYMMDD}[T|t| ]]{{HH:MM:SS[.m...]]]}|{HHMMSS[.m...]]]}}[Z|z|{-|+}HH[[:]MM]]
  * now
  * @endcode
  * If the value is "now" it takes the current time.
- * Time is local time unless Z is appended, in which case it is
- * interpreted as UTC.
+ * Time is local time unless a time zone specifier is appended, in which case
+ * it is interpreted in that time zone ("Z" means UTC).
  * If the year-month-day part is not specified it takes the current
  * year-month-day.
  * - If a duration the syntax is:
@@ -186,6 +186,18 @@ int av_find_info_tag(char *arg, int arg_size, const char *tag1, const char *info
 char *av_small_strptime(const char *p, const char *fmt, struct tm *dt);
 
 /**
+ * Parser for ISO 8601 time zone specifiers
+ *
+ * Works similarly to a %z in glibc's strptime. Applies the specified offset
+ * to the existing time in dt. This may result in the tm_hour and tm_min
+ * members being out of their normal ranges.
+ *
+ * @return a pointer to the first character not processed in this function
+ *         call. See av_small_strptime().
+ */
+char *av_parse_iso8601_tz(const char *p, struct tm *dt);
+
+/**
  * Convert the decomposed UTC time in tm to a time_t value.
  */
 time_t av_timegm(struct tm *tm);
-- 
2.6.2



More information about the ffmpeg-devel mailing list