[MINOR] implement a time parsing function

This new function accepts inputs in various default units, from
the microsecond to the day. It detects suffixes after numbers
and performs the appropriate conversions between the user's unit
and the program's unit, considering a unit-less number in the
default unit.
diff --git a/include/common/standard.h b/include/common/standard.h
index 0dde6db..3f7bed9 100644
--- a/include/common/standard.h
+++ b/include/common/standard.h
@@ -238,4 +238,22 @@
 	localtime_r(&now, tm);
 }
 
+/* This function parses a time value optionally followed by a unit suffix among
+ * "d", "h", "m", "s", "ms" or "us". It converts the value into the unit
+ * expected by the caller. The computation does its best to avoid overflows.
+ * The value is returned in <ret> if everything is fine, and a NULL is returned
+ * by the function. In case of error, a pointer to the error is returned and
+ * <ret> is left untouched.
+ */
+extern const char *parse_time_err(const char *text, unsigned *ret, unsigned unit_flags);
+
+/* unit flags to pass to parse_time_err */
+#define TIME_UNIT_US   0x0000
+#define TIME_UNIT_MS   0x0001
+#define TIME_UNIT_S    0x0002
+#define TIME_UNIT_MIN  0x0003
+#define TIME_UNIT_HOUR 0x0004
+#define TIME_UNIT_DAY  0x0005
+#define TIME_UNIT_MASK 0x0007
+
 #endif /* _COMMON_STANDARD_H */
diff --git a/src/standard.c b/src/standard.c
index 07aa5e4..40ad47e 100644
--- a/src/standard.c
+++ b/src/standard.c
@@ -496,6 +496,84 @@
 	return 0;
 }
 
+/* This function parses a time value optionally followed by a unit suffix among
+ * "d", "h", "m", "s", "ms" or "us". It converts the value into the unit
+ * expected by the caller. The computation does its best to avoid overflows.
+ * The value is returned in <ret> if everything is fine, and a NULL is returned
+ * by the function. In case of error, a pointer to the error is returned and
+ * <ret> is left untouched. Values are automatically rounded up when needed.
+ */
+const char *parse_time_err(const char *text, unsigned *ret, unsigned unit_flags)
+{
+	unsigned imult, idiv;
+	unsigned omult, odiv;
+	unsigned value;
+
+	omult = odiv = 1;
+
+	switch (unit_flags & TIME_UNIT_MASK) {
+	case TIME_UNIT_US:   omult = 1000000; break;
+	case TIME_UNIT_MS:   omult = 1000; break;
+	case TIME_UNIT_S:    break;
+	case TIME_UNIT_MIN:  odiv = 60; break;
+	case TIME_UNIT_HOUR: odiv = 3600; break;
+	case TIME_UNIT_DAY:  odiv = 86400; break;
+	default: break;
+	}
+
+	value = 0;
+
+	while (1) {
+		unsigned int j;
+
+		j = *text - '0';
+		if (j > 9)
+			break;
+		text++;
+		value *= 10;
+		value += j;
+	}
+
+	imult = idiv = 1;
+	switch (*text) {
+	case '\0': /* no unit = default unit */
+		imult = omult = idiv = odiv = 1;
+		break;
+	case 's': /* second = unscaled unit */
+		break;
+	case 'u': /* microsecond : "us" */
+		if (text[1] == 's') {
+			idiv = 1000000;
+			text++;
+		}
+		break;
+	case 'm': /* millisecond : "ms" or minute: "m" */
+		if (text[1] == 's') {
+			idiv = 1000;
+			text++;
+		} else
+			imult = 60;
+		break;
+	case 'h': /* hour : "h" */
+		imult = 3600;
+		break;
+	case 'd': /* day : "d" */
+		imult = 86400;
+		break;
+	default:
+		return text;
+		break;
+	}
+
+	if (omult % idiv == 0) { omult /= idiv; idiv = 1; }
+	if (idiv % omult == 0) { idiv /= omult; omult = 1; }
+	if (imult % odiv == 0) { imult /= odiv; odiv = 1; }
+	if (odiv % imult == 0) { odiv /= imult; imult = 1; }
+
+	value = (value * (imult * omult) + (idiv * odiv - 1)) / (idiv * odiv);
+	*ret = value;
+	return NULL;
+}
 
 /*
  * Local variables: