In game development, maybe the most common way to time "events" is to use a delta time. The absolute time that is considered "now" minus the previous absolute time, gives you a delta time:
delta time = current time - previous time
You can then multiply this delta time with the events and physics of the game. This is very common but have a lot of problems that creep in later. One of those problems might appear out of nowhere, and is the wrapping point.
Consider you have an absolute time of 56670001 milliseconds, and your old absolute time was 54999198. That gives a delta time of 1670803. This delta time is positive. Since you know time always moves forward, the delta time will always stay positive. So you expect that to always be the case. What if that somehow changes? How do you deal with it? Should you deal with it?
Over many decades, milliseconds were stored as 32-bit binary values. If we do the math of converting the highest possible 32-bit value into the unit "days", we will get:
4294967295 / 1000 = 4294967.295 seconds
4294967.295 / 60 = 71582.78825 minutes
71582.78825 / 60 = 1193.04647 hours
1193.04647 / 24 = 49.71027 days
That means, after 49.7 days, the milliseconds counter will overflow, and wrap around back to 0 again.
That means, the absolute time that is considered "now", will be smaller than the previous absolute time, yielding in a negative delta time. All of a sudden, time is moving backwards. What that has as an effect depends on what the delta time is used for. But for that odd time stamp, that happens not that often, can cause real headache!
So what? Just add a check:
if (now < previous) delta = previous - now; else if (previous <= now) delta = now - previous;
Does that solve the problem?
Or what about this:
delta = abs(now - previous);
Using the absolute number, does that solve the problem?
It might solve problems, but they are not needed as you can read below...
Binary Math has a way to solving the problem for us. It comes in the form of two's complement (read about it here: Binary Math (Subtraction and Negate)). Because negative values are just very large positive values, adding or subtracting such values will automatically overflow the numbers, auto wrapping them into a relative value for us.
Take the example of an absolute time for "now" being 5, and a previous time being 4294967291 (which is -5 in 32-bit). We now have the problem that if we subtract 4294967291 from 5, we will get -4294967286 which is a negative value, and time doesn't move in the negative direction.
But what if the value was wrapping around 4294967296? How can we test this? With modulo of course! Gotta love the modulo operator (not really, as we will get into later):
delta time = (5 - 4294967291) MOD 4294967296
As you might expect, you will get the result of -4294967286, the same as before. But sadly, using the modulo operator on a negative value to begin with will not give the result we need.
Because 32-bit values can only store 4294967296 unique numbers, -4294967286 is actually represented as 10. And if you just do the math 5 - (-5), you will get 10! 10 is positive, and time is moving forward again, even if the absolute time of "now" had wrapped over from 4294967291 to 5 with 10 units. Overflow just works!
So the correct code would still just be be (no need for checks):
delta = now - previous;
But there is a reason why I bring this up. We still have the problem of modulo. If computers just work, but modulo doesn't, then we do have a problem.
The modulus operator, most commonly done with the percentage sign in C derived languages, is the integer remainder of a division:
int dividend = 55; int divisor = 9; int quotient = dividend / divisor; // quotient == 6 int remainder = dividend % divisor; // remainder == 1
55 ÷ 9 = 6 and 1
Dividend Divisor Quotient Remainder
Modulo is mostly used to wrap random numbers, and for cryptography (usually with prime numbers), and we cannot live without that in our daily lives!
Modulo is defined as x - y * floor( x / y ) for any number. Somewhat... I wouldn't like to check if that is correct.
There is a problem, and I can easiest describe it with an analog clock of 60 minutes (having at least a minutes hand). If you have a time in minutes, any time, which will be a positive number, you can find which minute the minutes hand will be at, on that clock face. Since the clock wraps around every 60 minutes, the math is:
hand = minutes MOD 60
If we have the minutes of 16571886, then the minutes hand will be on minute 6.
We know that, if we subtract 7 from 16571886, the minutes hand will be on minute 59. And that is exactly true:
16571886 - 7 = 16571879
16571879 MOD 60 = 59
Now try this one. You are on minutes 59, and you subtract 61 minutes. Try the math now. You know the result should be 58. Because if you move 60 minutes, you will on 59 again, and one more minute backwards ends you on 58. However, modulo cannot handle this!
Remember the value 16571879 above? It was 59 on the clock, so what if we subtract 61 from that?
16571879 - 61 = 16571818
16571818 MOD 60 = 58
So, that works. So there is a big problem. And that's why it is very difficult to do these wrapping point stuff that the computers do with binary numbers, with so called "real math". So how do we solve these problems with "real math" then? I am still working on a solution to this day, but it is much more complicated than that, when you try to do the above delta time, when using modulo on both absolute times in a similar way as the computer overflows binary numbers, automatically for you.