Let’s assume that we have some kind of time duration stored in milliseconds.

Our goal is to represent this time duration in following format

HH:MM:SS,mmm

Few examples:

Below you can find working (but pretty brutal) piece of code for this task.

The code above should be pretty straight forward. We want to createString for given milliseconds.

The algorithm for extracting hours works in the following way:

  1. calculate how many hours are in the given duration,
  2. if there are less than 10 hours add “0” to the beginning of the string,
  3. add number of hours,
  4. return the string.

In other words we have 3 possible scenarios here:

  1. Time period given in milliseconds is less than 1 hour.
  2. Time period given in milliseconds is less than 10 hours.
  3. Time period given in milliseconds is greater than 10 hours.

For the first two cases hours will be equal to 0 (less than 10), so we will return “0” + “X” (for X <0, 9>).

For the third case hours will be greater than 10, so we do not need to add anything to hold “two digit precision” for our number of hours. We will just return this number converted to string.

So can we make this code better? Hell yeah we can! But firstly – what problems do we have here?

  1. too many functions
  2. a lot of “ifs”
  3. magic numbers
  4. hard-coded hours, minutes and seconds extraction
  5. unnecessary additional framework (boost)

The idea is very simple and everyone knows what this code should do. There are plenty ways of doing this but let’s try to refactor given code. What we are doing here most of the time is time conversion. We are keeping counting how many hours, minutes and seconds are in given time duration in milliseconds. There is a class in standard library for working with date and time, chrono. This class can do plenty of things but for now we are looking for some ways of time conversion / representation. Chrono has exactly what we needed: std::chrono::milliseconds, std::chrono::seconds, std::chrono::minutes and std::chrono::hours.

At this point we can create array of tuples which will store following information for each time unit:

  • time unit (milliseconds),
  • width (int),
  • separator (const char*).

Now we can create function which will iterate through tuples in formats array and prepare ostringstream in format which we want.

tuple_for_each takes two arguments – container (our array of tuples) and functor (lambda in our case). tuple_for_each iterates through all the tuples in the array and executes lambda on each tuple. Now information stored in each tuple can be used as follows:

  • time unit (milliseconds) – denominator,
  • width (int) – stream width,
  • separator (const char*) – separator.

So for now we have ended with something like this.

00:01:40.000

Program ended with exit code: 0

What else can we do here? Any ideas?

About 

I believe you can call me a geek. Um, and I like C++.

  • linkedin

Leave a Reply