lib/timeutils: parse_timestamp: parse usecs

Signed-off-by: Thomas Weißschuh <thomas@t-8ch.de>
This commit is contained in:
Thomas Weißschuh 2023-01-20 02:18:30 +00:00
parent 2abb8394fa
commit c061d1a774

View file

@ -147,6 +147,26 @@ static int parse_sec(const char *t, usec_t *usec)
return 0; 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 int parse_timestamp_reference(time_t x, const char *t, usec_t *usec)
{ {
static const struct { static const struct {
@ -171,19 +191,20 @@ static int parse_timestamp_reference(time_t x, const char *t, usec_t *usec)
const char *k; const char *k;
struct tm tm, copy; struct tm tm, copy;
usec_t plus = 0, minus = 0, ret; usec_t plus = 0, minus = 0, ret = 0;
int r, weekday = -1; int r, weekday = -1;
unsigned i; unsigned i;
/* /*
* Allowed syntaxes: * Allowed syntaxes:
* *
* 2012-09-22 16:34:22 * 2012-09-22 16:34:22 !
* 2012-09-22T16:34:22 * 2012-09-22T16:34:22 !
* @1348331662 (seconds since the Epoch (1970-01-01 00:00 UTC)) * 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 16:34 (seconds will be set to 0)
* 2012-09-22 (time will be set to 00:00:00) * 2012-09-22 (time will be set to 00:00:00)
* 16:34:22 (date will be set to today) * 16:34:22 ! (date will be set to today)
* 16:34 (date will be set to today, seconds to 0) * 16:34 (date will be set to today, seconds to 0)
* now * now
* yesterday (time is set to 00:00:00) * yesterday (time is set to 00:00:00)
@ -192,6 +213,13 @@ static int parse_timestamp_reference(time_t x, const char *t, usec_t *usec)
* +5min * +5min
* -5days * -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); 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); k = strptime(t + 1, "%s", &tm);
if (k && *k == 0) if (k && *k == 0)
goto finish; goto finish;
else if (k && parse_subseconds(k, &ret) == 0)
goto finish;
return -EINVAL; return -EINVAL;
} else if (endswith(t, " ago")) { } 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); k = strptime(t, "%y-%m-%d %H:%M:%S", &tm);
if (k && *k == 0) if (k && *k == 0)
goto finish; goto finish;
else if (k && parse_subseconds(k, &ret) == 0)
goto finish;
tm = copy; tm = copy;
k = strptime(t, "%Y-%m-%d %H:%M:%S", &tm); k = strptime(t, "%Y-%m-%d %H:%M:%S", &tm);
if (k && *k == 0) if (k && *k == 0)
goto finish; goto finish;
else if (k && parse_subseconds(k, &ret) == 0)
goto finish;
tm = copy; tm = copy;
k = strptime(t, "%Y-%m-%dT%H:%M:%S", &tm); k = strptime(t, "%Y-%m-%dT%H:%M:%S", &tm);
if (k && *k == 0) if (k && *k == 0)
goto finish; goto finish;
else if (k && parse_subseconds(k, &ret) == 0)
goto finish;
tm = copy; tm = copy;
k = strptime(t, "%y-%m-%d %H:%M", &tm); 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); k = strptime(t, "%H:%M:%S", &tm);
if (k && *k == 0) if (k && *k == 0)
goto finish; goto finish;
else if (k && parse_subseconds(k, &ret) == 0)
goto finish;
tm = copy; tm = copy;
k = strptime(t, "%H:%M", &tm); 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); k = strptime(t, "%Y%m%d%H%M%S", &tm);
if (k && *k == 0) if (k && *k == 0)
goto finish; goto finish;
else if (k && parse_subseconds(k, &ret) == 0)
goto finish;
return -EINVAL; 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) if (weekday >= 0 && tm.tm_wday != weekday)
return -EINVAL; return -EINVAL;
ret = (usec_t) x *USEC_PER_SEC; ret += (usec_t) x * USEC_PER_SEC;
ret += plus; ret += plus;
if (ret > minus) if (ret > minus)
@ -586,11 +626,16 @@ static int run_unittest_timestamp(void)
const char * const input; const char * const input;
usec_t expected; usec_t expected;
} testcases[] = { } testcases[] = {
{ "2012-09-22 16:34:22", 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" , 1348331662000000 },
{ "@1348331662.234567" , 1348331662234567 },
{ "2012-09-22 16:34" , 1348331640000000 }, { "2012-09-22 16:34" , 1348331640000000 },
{ "2012-09-22" , 1348272000000000 }, { "2012-09-22" , 1348272000000000 },
{ "16:34:22" , 1674232462000000 }, { "16:34:22" , 1674232462000000 },
{ "16:34:22,123456" , 1674232462123456 },
{ "16:34:22.123456" , 1674232462123456 },
{ "16:34" , 1674232440000000 }, { "16:34" , 1674232440000000 },
{ "now" , 1674180427000000 }, { "now" , 1674180427000000 },
{ "yesterday" , 1674086400000000 }, { "yesterday" , 1674086400000000 },