Hacker News new | ask | show | jobs
by cafeoh 1992 days ago
I've never seen something so confusing. I've been (and quite frankly still am) seriously considering this is a big prank that's going over my head. The author even mentions that because time goes up and countdowns go down, rounding down is confusing. Wouldn't the logical conclusion be that you needed to round up?

Wouldn't rounding up be the most logical option ANYWAY? If someone counts me down, I expect them to say "5, 4, 3, 2, 1, GO", and I expect a timer to do the exact same thing. This fixes seemingly every issue, starting on 5, not having to round to nearest integer (or add 500ms, which is an odd way to look at it, but sure), and not showing 0 (which I'd find quite weird). I just checked my own (Android) timer, and sure enough it rounds up, which is what I expected and what I expect from a countdown in general.

Maybe what seems to me like the most obvious behaviour for a timer is not as obvious as I think, but why did the author not even mention rounding up as a solution, or how it could conflict with his own expectations?

I'll just assume this to be a shower thought that didn't fully mature before making it into an article, but there seems to be enough effort that I'm still left quite confused. Oh and don't mistake this for a euphemism for me critiquing the intelligence of the author, at worst it's just a funny blindspot (as we all experience) but I'm seeing very little mentions in the comments here, which only adds to my bafflement.

2 comments

> If someone counts me down, I expect them to say "5, 4, 3, 2, 1, GO", and I expect a timer to do the exact same thing.

"Exact same thing" isn't really possible here because the timer needs to show each integer for a duration of 1 second, while the spoken words each have a duration of much less than 1 second. So much less that they're really identifying a moment (perhaps the initial consonant, or the peak amplitude) rather than a window of time. This is why "go" is able to be intuitively anticipated accurately.

If the timer app flashed each number briefly, with no display for the vast majority of each second, then it could do the "exact same thing" as spoken English. Considering the transition from displaying one number to displaying the next as analogous to a spoken word is about as good as we'll get, in which case "1" ought to be displayed for one second immediately prior to "go" (don't display "0" for the last second and certainly not for a half second).

Original author here.

I have thought about your and other peoples comments. It could well be just rounded to the nearest integer, making my +500ms assumption wrong. However, this would result in 59.51s being displayed as 0:60, though it should be 1:00. Rounding up has the same problem.

I went through the same assumptions coding my own timer. Let's just round everything. But this resulted in 51.0s being displayed as 1:51 on the timer, with rounding up it's even worse resulting in 1:01:51. So at least hours and minutes have to be rounded down. But that makes it even more confusing that seconds are NOT Math.floor().

So in the end I "gave up" and used the date-fns package (works great) but it also rounds everything down. That's why I believe that iOS adds 500ms so the minutes and hours work properly.

> this resulted in 51.0s being displayed as 1:51

What?

> with rounding up it's even worse resulting in 1:01:51

Huh?

If you are making some kind of timer, you first should convert the time to pure seconds, or in whatever the smallest unit is that you care to deal with (milliseconds?). It is only at that point that the data is ready for any kind of arithmetic (for example, to subtract 1 second). Then, when you wish to display it, you first convert it.

For example, if the user sets your timer to 2 minutes, you would convert "2:00" to 120 seconds. Then you subtract 1 second. Now the internal value is 119. Then you convert back to the display format: "1:59". But be sure to keep "119" in some internal variable, for the next change.

    <form name=f>
        <input type=number name=h min=0 max=99 value=0>
        <input type=number name=m min=0 max=59 value=00>
        <input type=number name=s min=0 max=59 value=00>
        <input type=submit value=Start>
        <output name=r></output>
    </form>

    <script>

    document.forms.f.addEventListener('submit', function (ev) {

        ev.preventDefault();

        let f = ev.target,
            s = Number(f.h.value * 60 * 60) +
                Number(f.m.value * 60) +
                Number(f.s.value);

        function show(f, s) {

            let h = Math.floor(s / 60 / 60);
            s -= (h * 60 * 60);

            let m = Math.floor(s / 60);
            s -= (m * 60);

            m = String(m).padStart(2, '0');
            s = String(s).padStart(2, '0');

            f.elements.r.value = [h, m, s].join(':');
        }

        show(f, s);

        if (f.timer) { clearInterval(f.timer); }
        f.timer = setInterval(function () {
            if (0 === s) { clearInterval(f.timer); return; }
            s -= 1;
            show(f, s);
        }, 1000);
    });

    </script>
> However, this would result in 59.51s being displayed as 0:60, though it should be 1:00. Rounding up has the same problem.

Surely one shouldn't round _after_ splitting the time into minutes and seconds.

You floor() or ceil() the time, depending on if you're counting up or down, to the lowest unit your timer is showing, then you display it and in the process split it into hours, minutes etc.

So ceil(59.51s) = 60s, which is then converted to 0h 1m 0s for display.

> However, this would result in 59.51s being displayed as 0:60, though it should be 1:00.

They would round it up to 60, the format it to be 01:00.