Functional JavaScript Timer Display

In this code challenge, the problem is fairly straightforward; you’ve been given an amount of time in seconds and need to display those seconds so that a human can read them as a timer would to show time in hours, minutes and seconds. All the numbers have to be padded to the tens digit, basically this is a digital clock readout! The cool part is that we’ll do this whole challenge with 1 pretty line of functional JavaScript!

Attempting this using procedural code would take about 7 lines, but I saw solutions a lot higher than that which weren’t wrong. Remember, readability is important in code so you need to decide what feels right to you. I did this challenge with functional JavaScript and was able to solve the problem in 1 line. If your a functional programmer that probably does not shock you, but if your an imperial style coder then you might say, “Come on my good man! how did you do all that math and string formatting in one line?. Harrumphh!” Well, let’s walk through it start to finish.

We need to solve for 3 values, the hours integer, minutes integer and seconds integer. After solving for those 3 values we need to pad them and the remaining work is just joining them together with a “:” character. Luckily the modulo operator helps us to solve for each of these values without having to combine the value from one to figure out another. So while we could create 3 variables, I feel that we can minimize our code length and still maintain readability by solving for all three of these values inside an array literal, that’s where the values will end up anyways.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// We could write the variables out like this,
function getTimerDisplay() {
var hours = seconds / 3600,
mins = seconds % 3600 / 60,
secs = seconds % 60;
}

// or assign a literal array to a variable hourMinSec,
function getTimerDisplay() {
var hourMinSec = [
seconds / 3600, // Hours
seconds % 3600 / 60, // Minutes
seconds % 60 // Seconds
];
}

// or just put them into a literal array with no token…
const getTimerDisplay = (seconds) => [ seconds / 3600, seconds % 3600 / 60, seconds % 60 ]

I’d like to first bring to attention to the fact that in JavaScript the division and modulo operators are of the same operator precedence, (level 14) see MDN Operator Precedence Table. This means we don’t need parenthesis to group the operations above as they read fine left-to-right and so do most humans. If this wasn’t the case then we would want to use parenthesis for better readability and more than likely if these were any more complex or reusable we would give them their own functions and call those inline from the array. Either way, all three functions can make calls like the ones below and get back arrays that look like the following (if they all had return statements that is):


1
2
3
getTimerDisplay(40);   //[0.011111111111111112, 0.6666666666666666, 40]
getTimerDisplay(230); // [0.06388888888888888, 3.8333333333333335, 50]
getTimerDisplay(5230); // [1.4527777777777777, 27.166666666666668, 10]

Naturally the solution is far from complete. All we have is an array with some numbers, they are meaningful numbers though.


Converting from seconds to hours

The first operation, seconds / 3600, there are 3600 seconds in 1 hour so this is a simple conversion to hours from seconds and it gives us the hours as a number but not likely an integer. So we’ll move onto the next operation but not that we’re done working on the hours number, our functional programming will allow us to come back to that in a moment.


Converting the remaining time from seconds to minutes

Next operation is seconds % 3600 / 60, a calculation of how many minutes in the time remaining which includes minutes and seconds but not hours. Let’s read this left to right to understand. First seconds % 3600 is a calculation of how many seconds are in the remainder of time after solving for hours. So if we had 4000 seconds total, after solving for hours we would have 400 seconds left, 4000 % 3600 is 400. Now we can convert those seconds into minutes by dividing by 60. 400 / 60 would be 6 and 2/3 or 6.6…repeating.


One more partial example to walk-through

Quickly imagine one more senario, we want to solve our timers display for 8100 seconds. The conversion to hours would be 8100 / 3600 = 2.25. A human knows that .25 from 2.25 is the remainder from that division operation in hours. That person might then convert the remainder .25 hours into seconds by doing .25 3600 = 900 or convert the 2 hours into seconds and subtract those from the total, 8100 - (2 3600) = 900. The computer has an operator just for this, it’s the “remainder” or “modulo” operator and it just gives us that remainder answer very quickly simply by doing 8100 % 3600, we express that with seconds % 3600.


The last part solves for seconds in the remainder after dividing our total amount by 60, seconds % 60, I won’t explain this because I think you probably got it already.


And let’s bring her home!

The last parts of this solution are simple, so let’s change the example a bit and solve through the entire function at once including the number padding and display string formatting! The seconds in this last example will be 9140. After doing all 3 calculations [ seconds / 3600, seconds % 3600 / 60, seconds % 60 ] our array would equal [2.5388888888888888, 32.333333333333336, 20] and we need that to become “02:32:20” so now the fun part! First we map over it with the lamda function f => ${~~f}. I will explain what that does.


You should know that map is an array method in JavaScript based on a functional programming function that runs a “predicate” function once over each value in an array and then “maps” the results from those function calls back into the same index but in a new array. What? You can think of it like this, our numbers need more calculations done over them, we need to think of a function that when called on each item in our array will transform each value from the float form they are in now to the padded integer form we need for the timer display. The function parseInt is perfect for this, but we can also use which is a cheat way to do parseInt, basically we’re just doing ‘0’ + parseInt(f).


Let’s not use or string templates for one minute. Below I wrote out each step (not including the math from above), and a console log after each step so that you can see the progression of how the values in the array are transformed throughout the mappings.


1
2
3
4
5
6
7
let values = [2.5388888888888888, 32.333333333333336, 20];

values = values.map(f => parseInt(f));
console.log( values ); // [2, 32, 20]

values = values.map(s => ‘0’ + s)
console.log( values ); // [“02”, “032”, “020”]

After zero padding the numbers we just need to make sure that we only take the first 2 digits of each number (like a clock) and then we can join them together with a ‘:’.


1
2
3
4
5
values = values.map(s => s.substr(-2));
console.log( values ); // [“02”, “32”, “20”]

values = values.join(‘:’)
console.log( values ); // “02:32:20”

Alright, now that you understand the solution, let’s make it compact and ship it out!


1
2
3
4
5
6
function getTimerDisplay(seconds) {
return [ seconds / 3600, seconds % 3600 / 60, seconds % 60 ]
.map(f => 0<span class="subst">${~~f}</span>)
.map(s => s.substr(-2))
.join(‘:’);
}

This was a code challenge so I wanted a short and clever answer. In reality functional programming isn’t about cramming everything inline, normally you would extract functionality out into small bits of reusable code and then call those abstractions inline. But anyways, without further to-do here is the final solution:


1
2
3
4
const getTimerDisplay = (seconds) => 
[ seconds / 3600, seconds % 3600 / 60, seconds % 60 ]
.map(f => 0<span class="subst">${~~f}</span>.substr(-2))
.join(‘:’);