I recently was asked to upgrade some C++11 code to add a feature by which the user can set a time duration from the command line of the program. The requirement was to have a default time of 1500 ms but to allow it to be overridden by the command line parameters if the parameters are valid; invalid conditions should result in a text message diagnostic, but the program should proceed with the default value. Negative time durations are not valid, so this code negates any value less than zero. The units of time can be ms, s, m, or h for milliseconds, seconds, minutes or hours. The parseDuration
code is shown below, along with a simple main
to demonstrate its intended use.
#include <chrono>
#include <iostream>
#include <string>
#include <unordered_map>
std::chrono::milliseconds parseDuration(std::chrono::milliseconds& dur, const std::string& num, const std::string& unit) {
static const std::unordered_map<std::string, long> suffix{ {"ms", 1}, {"s", 1000}, {"m", 60*1000}, {"h", 60*60*1000} };
try {
auto n{std::stod(num)};
if (n < 0) {
n = -n;
}
dur = std::chrono::milliseconds{static_cast<unsigned long>(n * suffix.at(unit))};
}
catch (const std::invalid_argument& e) {
std::cout << "ERROR: could not convert " << num << " to numeric value" << '\n';
}
catch (const std::out_of_range& e) {
std::cout << "ERROR: " << unit << " is not one of ms,s,m,h" << '\n';
}
return dur;
}
int main(int argc, char *argv[]) {
if (argc != 3) {
std::cerr << "Usage: duration num ms|s|m|h\n";
return 1;
}
auto duration{std::chrono::milliseconds{1500}};
parseDuration(duration, argv[1], argv[2]);
std::cout << "That's " << duration.count() << '\n';
}