]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
lib/timeutils: parse_timestamp: parse usecs
authorThomas Weißschuh <thomas@t-8ch.de>
Fri, 20 Jan 2023 02:18:30 +0000 (02:18 +0000)
committerThomas Weißschuh <thomas@t-8ch.de>
Mon, 23 Jan 2023 13:47:01 +0000 (13:47 +0000)
Signed-off-by: Thomas Weißschuh <thomas@t-8ch.de>
lib/timeutils.c

index 79b6749078b50979355d698be7511de38824ca04..f61a77ab950acd5c3d28e9953737576e00f1db56 100644 (file)
@@ -147,6 +147,26 @@ static int parse_sec(const char *t, usec_t *usec)
        return 0;
 }
 
+static int parse_subseconds(const char *t, usec_t *usec)
+{
+       usec_t ret = 0;
+       int factor = USEC_PER_SEC / 10;
+
+       if (*t != '.' && *t != ',')
+               return -1;
+
+       while (*(++t)) {
+               if (!isdigit(*t) || factor < 1)
+                       return -1;
+
+               ret += ((usec_t) *t - '0') * factor;
+               factor /= 10;
+       }
+
+       *usec = ret;
+       return 0;
+}
+
 static int parse_timestamp_reference(time_t x, const char *t, usec_t *usec)
 {
        static const struct {
@@ -171,27 +191,35 @@ static int parse_timestamp_reference(time_t x, const char *t, usec_t *usec)
 
        const char *k;
        struct tm tm, copy;
-       usec_t plus = 0, minus = 0, ret;
+       usec_t plus = 0, minus = 0, ret = 0;
        int r, weekday = -1;
        unsigned i;
 
        /*
         * Allowed syntaxes:
         *
-        *   2012-09-22 16:34:22
-        *   2012-09-22T16:34:22
-        *   @1348331662          (seconds since the Epoch (1970-01-01 00:00 UTC))
-        *   2012-09-22 16:34     (seconds will be set to 0)
-        *   2012-09-22           (time will be set to 00:00:00)
-        *   16:34:22             (date will be set to today)
-        *   16:34                (date will be set to today, seconds to 0)
+        *   2012-09-22 16:34:22 !
+        *   2012-09-22T16:34:22 !
+        *   20120922163422      !
+        *   @1348331662         ! (seconds since the Epoch (1970-01-01 00:00 UTC))
+        *   2012-09-22 16:34      (seconds will be set to 0)
+        *   2012-09-22            (time will be set to 00:00:00)
+        *   16:34:22            ! (date will be set to today)
+        *   16:34                 (date will be set to today, seconds to 0)
         *   now
-        *   yesterday            (time is set to 00:00:00)
-        *   today                (time is set to 00:00:00)
-        *   tomorrow             (time is set to 00:00:00)
+        *   yesterday             (time is set to 00:00:00)
+        *   today                 (time is set to 00:00:00)
+        *   tomorrow              (time is set to 00:00:00)
         *   +5min
         *   -5days
         *
+        *   Syntaxes marked with '!' also optionally allow up to six digits of
+        *   subsecond granularity, separated by '.' or ',':
+        *
+        *   2012-09-22 16:34:22.12
+        *   2012-09-22 16:34:22.123456
+        *
+        *
         */
 
        assert(t);
@@ -235,6 +263,8 @@ static int parse_timestamp_reference(time_t x, const char *t, usec_t *usec)
                k = strptime(t + 1, "%s", &tm);
                if (k && *k == 0)
                        goto finish;
+               else if (k && parse_subseconds(k, &ret) == 0)
+                       goto finish;
 
                return -EINVAL;
        } else if (endswith(t, " ago")) {
@@ -271,16 +301,22 @@ static int parse_timestamp_reference(time_t x, const char *t, usec_t *usec)
        k = strptime(t, "%y-%m-%d %H:%M:%S", &tm);
        if (k && *k == 0)
                goto finish;
+       else if (k && parse_subseconds(k, &ret) == 0)
+               goto finish;
 
        tm = copy;
        k = strptime(t, "%Y-%m-%d %H:%M:%S", &tm);
        if (k && *k == 0)
                goto finish;
+       else if (k && parse_subseconds(k, &ret) == 0)
+               goto finish;
 
        tm = copy;
        k = strptime(t, "%Y-%m-%dT%H:%M:%S", &tm);
        if (k && *k == 0)
                goto finish;
+       else if (k && parse_subseconds(k, &ret) == 0)
+               goto finish;
 
        tm = copy;
        k = strptime(t, "%y-%m-%d %H:%M", &tm);
@@ -314,6 +350,8 @@ static int parse_timestamp_reference(time_t x, const char *t, usec_t *usec)
        k = strptime(t, "%H:%M:%S", &tm);
        if (k && *k == 0)
                goto finish;
+       else if (k && parse_subseconds(k, &ret) == 0)
+               goto finish;
 
        tm = copy;
        k = strptime(t, "%H:%M", &tm);
@@ -326,6 +364,8 @@ static int parse_timestamp_reference(time_t x, const char *t, usec_t *usec)
        k = strptime(t, "%Y%m%d%H%M%S", &tm);
        if (k && *k == 0)
                goto finish;
+       else if (k && parse_subseconds(k, &ret) == 0)
+               goto finish;
 
        return -EINVAL;
 
@@ -337,7 +377,7 @@ static int parse_timestamp_reference(time_t x, const char *t, usec_t *usec)
        if (weekday >= 0 && tm.tm_wday != weekday)
                return -EINVAL;
 
-       ret = (usec_t) x *USEC_PER_SEC;
+       ret += (usec_t) x * USEC_PER_SEC;
 
        ret += plus;
        if (ret > minus)
@@ -586,19 +626,24 @@ static int run_unittest_timestamp(void)
                const char * const input;
                usec_t expected;
        } testcases[] = {
-               { "2012-09-22 16:34:22", 1348331662000000 },
-               { "@1348331662"        , 1348331662000000 },
-               { "2012-09-22 16:34"   , 1348331640000000 },
-               { "2012-09-22"         , 1348272000000000 },
-               { "16:34:22"           , 1674232462000000 },
-               { "16:34"              , 1674232440000000 },
-               { "now"                , 1674180427000000 },
-               { "yesterday"          , 1674086400000000 },
-               { "today"              , 1674172800000000 },
-               { "tomorrow"           , 1674259200000000 },
-               { "+5min"              , 1674180727000000 },
-               { "-5days"             , 1673748427000000 },
-               { "20120922163422"     , 1348331662000000 },
+               { "2012-09-22 16:34:22"    , 1348331662000000 },
+               { "2012-09-22 16:34:22,012", 1348331662012000 },
+               { "2012-09-22 16:34:22.012", 1348331662012000 },
+               { "@1348331662"            , 1348331662000000 },
+               { "@1348331662.234567"     , 1348331662234567 },
+               { "2012-09-22 16:34"       , 1348331640000000 },
+               { "2012-09-22"             , 1348272000000000 },
+               { "16:34:22"               , 1674232462000000 },
+               { "16:34:22,123456"        , 1674232462123456 },
+               { "16:34:22.123456"        , 1674232462123456 },
+               { "16:34"                  , 1674232440000000 },
+               { "now"                    , 1674180427000000 },
+               { "yesterday"              , 1674086400000000 },
+               { "today"                  , 1674172800000000 },
+               { "tomorrow"               , 1674259200000000 },
+               { "+5min"                  , 1674180727000000 },
+               { "-5days"                 , 1673748427000000 },
+               { "20120922163422"         , 1348331662000000 },
        };
 
        if (unsetenv("TZ"))