Why the iPhone Timer app displays a fake time
lukashermann.dev
lukashermann.dev
It seems like the simpler explanation is that the iPhone actually rounds to the closest integer rather than rounding down. (Whether they do this invisibly by adding 0.5s and rounding down is an implementation detail.)
That’s most likely what it does indeed, much more elegant than keeping track of the extra 500ms.
It's not "fake".
I would much prefer "0 seconds remaining" to mean 0 to 0.5 seconds remaining, than any other possible case. I would find it much easier to parse.
(Alternatively, please show more accuracy for this case, where it's likely relevant)
The tidbit about it displaying 1 even if there is 0.01 left is interesting though. Makes sense.
Oh, so that's why it's telling me to wait... I always wondered that whenever I got into an argument with someone.
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.
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.
They would round it up to 60, the format it to be 01:00.
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.
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>"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).
It isn't displaying a "fake" time, it's rounding.
https://en.wikipedia.org/wiki/Rounding#Round_half_up
Edit: Note, Round Half Up != Round half away from zero but that isn't important for this scenario :D
Which is not to call apple's timer nonsensical. I agree with the author that it's a nicer experience, but I think it's likely an intentional decision to make the display look better, not a consequence of naive rounding.
That doesn't really work for a countdown timer though since the last second would then display as zero, which is nonsense for 'time remaining'. You have to round up, always.
The Android 9 countdown works intuitively, it takes a second to decrement from 5 to 4 and sounds the alarm exactly at 0. You can't pause it at zero...
> Which is not to call apple's timer nonsensical.
It pretty much is, since the last 'second' takes more than a second to elapse.
> Any sensible time handling solution will round off toward the starting value.
So a stopwatch won't display "1" until a full second has elapsed, and will look like this for five seconds: "0...1...2...3...4...5!"
A timer won't display "4" until a full second has elapsed, and will look like this: "5...4...3...2...1...0!"
In the stopwatch case, the display shows "0" for 0.999 s; in the timer case it'll show "1" for 0.999 s.
A stopwatch counts up. Therefore, it makes sense to use the floor (4.99 is still "4", not yet "5").
A timer counts down. Therefore, it makes sense to use the ceiling (3.01 is still "4", not yet "3").
In fact this was a turning point in the original article: "rounding down . . . makes a lot of sense when counting up. . . . But for a countdown timer, this is counterintuitive."
It's not a "handling of time" its just a display. And its extremely sensible to round to the nearest displayable number instead of rounding up or down, because this minimizes the error in the displayed number. And that's what you are interested in, conveying as accurately as possible what the current time is.
Theres no way this is happening because somebody called math.round() without thinking, you don't round time and the developers who make apple's clock app know that. They made a conscious decision to have the timer work this way. You can disagree with whether they made the right choice, but I'm pretty sure they thought about it.
You can
- Round (Truncation is a type of rounding, Rounding towards zero)
- Adjust the display to increase the precision it displays
- Do both by dynamically increasing the precision of the display/decreasing rounding as the distance to zero closes in.We say, "5, 4, 3, 2, 1, 0", not "4, 3, 2, 1, 0, done".
Dividing the amount of milliseconds left / 1000 is too naive. If you want that the representation "0 seconds" actually matches the instant when there are actually 0 seconds left (i.e., no more time left), you should label these millisecond ranges as follows:
* 5000 to 4001: "5 seconds"
* 4000 to 3001: "4 seconds"
* 3000 to 2001: "3 seconds"
* 2000 to 1001: "2 seconds"
* 1000 to 0001: "1 second"
* 0: "0 seconds" (which usually the user doesn't read if the screen shows something else)
Simple enough?
The thing is, yes the iPhone timer does something in between, in order to show both the initial (5) and the final (0) numbers for a non-instantaneous amount of time, but (IMHO) that's the most confusing choice.
It's a good example of how measurement of time in terms of human perception differs from the pure mathematical sense, and rounding is a good compromise here (wherever it doesn't display fractional seconds).
From iOS 10 onwards, 1000+ hours doesn't seem to phase it at all - no slow downs.
source: 1490:43:24 ago I started my timer, but I can't remember why now.
I get the feeling this pun wasn’t intentional, but it’s a good one nonetheless.
The new app where hour and minutes are separate text fields and where you can't edit an alarm you can only delete old ones and create new ones is utterly unintuitive to me and much slower and more error prone than the old one. Clicking in the hour or minute section is a much smaller target. Editing sucks. I want to set an alarm for 10:00 and it defaults to showing the current time 09:33 so I click the 09 and type 1000 but it only edits the 09 to 10. The 33 stays and I have to click the other side and enter 00.
To be snarky it's like some UX designer from Google went to Apple. This is not a UX I'd expect from Apple.
Besides, instead of truncating, it would even be sensible to do a round-up here, so that you get "5, 4, 3, 2, 1, done!" Non-mathematicians and non-programmers don't want to stare at 0 for a seconds. They likely don't want to stare at a 0 at all. That wouldn't "fake time" either.
It really gets to me that he writes such an article and his self-description is "I'm a Maker and Full Stack Developer who loves working with the Frontend, Vue.js and User Interface Design." Not a great ad for yourself..
Isn't that exactly what you did right here?
Rounding is something I learned in elementary school. If someone in elementary school was unfamiliar with rounding, it would be mean to take them to task about it. But this writer is an adult, a professional programmer, and presumes to be a teacher, by taking the time to publish an article about the subject.
In fact, the writer has even less excuse, because he knows about rounding. Twice he mentions "rounding down". So it is all the more baffling that he did not call what Apple was doing, simply, "rounding up". Instead he wrote a multi-paragraph blog post about adding 500 milliseconds of "fake time", then having to duct-tape over that by making the timer say "0" when the timer reached 500 ms.
Suppose a man bills himself as a car salesman, but every question you ask him about the car, he says the wrong thing. He says the car has 3 wheels when it has 4. He says it is red when it is black. He says the engine is in the back when it is in the front. Would it be mean for you to mention his title, by saying something like, "You say you are a car salesman, but you don't know about this car on your lot." It is right to call someone out for being less than what they say they are.
As for random blog posts on the internet, this isn't so surprising. What's surprising is that it wound up on Hacker News with over 100 votes.
One of the main benefits is that it doesn’t require the internet and can synchronize iPhones, iPads, and Apple TV’s using either peer-to-peer WiFi or Bluetooth with no manual pairing.
Also had an interval timer for exercises, group activities, etc...
Edit: sencha.app for those curious
You should show each integer value second for, ideally, one second (in the case with no display for fractional seconds). So the question is: exactly what rage of time to cover? The poster expected that for second N, it would be:
[N,N+1)
But Apple seems to do:
[N-0.5, N+0.5)
I think the Apple behavior makes perfect sense when you are displaying the current time (eg like a watch). It may be a little less obviously correct for the timer case, but still seems fine. I'd bet they implemented it for the time of day case and just re-used it for the timer case.
I think either rounding up, or rounding to the closest integer is fine. The authors expectation of always rounding down is the only option I would never expect.
"What time is it now?"
vs
"How much time is left?"