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 {
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);
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")) {
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);
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);
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;
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)
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"))