in src/kudu/gutil/strings/human_readable.cc [327:430]
bool HumanReadableElapsedTime::ToDouble(const string& str, double* value) {
struct TimeUnits {
const char* unit; // unit name
double seconds; // number of seconds in that unit (minutes => 60)
};
// These must be sorted in decreasing length. In particulary, a
// string must exist before and of its substrings or the substring
// will match;
static const TimeUnits kUnits[] = {
// Long forms
{ "nanosecond", 0.000000001 },
{ "microsecond", 0.000001 },
{ "millisecond", 0.001 },
{ "second", 1.0 },
{ "minute", 60.0 },
{ "hour", 3600.0 },
{ "day", 86400.0 },
{ "week", 7 * 86400.0 },
{ "month", 30 * 86400.0 },
{ "year", 365 * 86400.0 },
// Abbreviated forms
{ "nanosec", 0.000000001 },
{ "microsec", 0.000001 },
{ "millisec", 0.001 },
{ "sec", 1.0 },
{ "min", 60.0 },
{ "hr", 3600.0 },
{ "dy", 86400.0 },
{ "wk", 7 * 86400.0 },
{ "mon", 30 * 86400.0 },
{ "yr", 365 * 86400.0 },
// nano -> n
{ "nsecond", 0.000000001 },
{ "nsec", 0.000000001 },
// micro -> u
{ "usecond", 0.000001 },
{ "usec", 0.000001 },
// milli -> m
{ "msecond", 0.001 },
{ "msec", 0.001 },
// Ultra-short form
{ "ns", 0.000000001 },
{ "us", 0.000001 },
{ "ms", 0.001 },
{ "s", 1.0 },
{ "m", 60.0 },
{ "h", 3600.0 },
{ "d", 86400.0 },
{ "w", 7 * 86400.0 },
{ "M", 30 * 86400.0 }, // upper-case M to disambiguate with minute
{ "y", 365 * 86400.0 }
};
char* unit_start; // Start of unit name.
double work_value = 0;
int sign = 1;
const char* interval_start = SkipLeadingWhiteSpace(str.c_str());
if (*interval_start == '-') {
sign = -1;
interval_start = SkipLeadingWhiteSpace(interval_start + 1);
} else if (*interval_start == '+') {
interval_start = SkipLeadingWhiteSpace(interval_start + 1);
}
if (!*interval_start) {
// Empty string and strings with just a sign are illegal.
return false;
}
do {
// Leading signs on individual values are not allowed.
if (*interval_start == '-' || *interval_start == '+') {
return false;
}
double factor = strtod(interval_start, &unit_start);
if (interval_start == unit_start) {
// Illegally formatted value, no values consumed by strtod.
return false;
}
unit_start = SkipLeadingWhiteSpace(unit_start);
bool found_unit = false;
for (int i = 0; !found_unit && i < KUDU_ARRAYSIZE(kUnits); ++i) {
const size_t unit_len = strlen(kUnits[i].unit);
if (strncmp(unit_start, kUnits[i].unit, unit_len) == 0) {
work_value += factor * kUnits[i].seconds;
interval_start = unit_start + unit_len;
// Allowing pluralization of any unit (except empty string)
if (unit_len > 0 && *interval_start == 's') {
interval_start++;
}
found_unit = true;
}
}
if (!found_unit) {
return false;
}
interval_start = SkipLeadingWhiteSpace(interval_start);
} while (*interval_start);
*value = sign * work_value;
return true;
}