Ok, I’ve figured it by myself.
MonoGame uses Fixed timestep by default. I’ll copy this amazing explanation of fixed time step here, originally written by Shawn Hargreaves.
By default XNA runs in fixed timestep mode, with a TargetElapsedTime of 60 frames per second. This provides a simple guarantee:
We will call your Update method exactly 60 times per second
We will call your Draw method whenever we feel like it
Digging into exactly what that means, you will realize there are several possible scenarios depending on how long your Update and Draw methods take to execute.
The simplest situation is that the total time you spend in Update + Draw is exactly 1/60 of a second. In this case we will call Update, then call Draw, then look at the clock and notice it is time for another Update, then Draw, and so on. Simple!
What if your Update + Draw takes less than 1/60 of a second? Also simple. Here we call Update, then call Draw, then look at the clock, notice we have some time left over, so wait around twiddling our thumbs until it is time to call Update again.
What if Update + Draw takes longer than 1/60 of a second? This is where things get complicated. There are many reasons why this could happen:
The computer might be slightly too slow to run the game at the desired speed.
Or the computer might be way too slow to run the game at the desired speed!
The computer might be basically fast enough, but this particular frame might have taken an unusually long time for some reason. Perhaps there were too many explosions on screen, or the game had to load a new texture, or there was a garbage collection.
You could have paused the program in the debugger.
So gameTime.ElapsedGameTime contains precisely the fixed time step value.
It is possible to set the target time step by running:
TargetElapsedTime = TimeSpan.FromSeconds(0.001);
If you were to print GameTime.ElapsedGameTime it would show 0.001.
If you wanted to disable fixed time step mode, so that gameTime.ElapsedGameTime actually shows the two seconds, you would run (although I’m not sure I recommend this)
IsFixedTimeStep = false;
MaxElapsedTime = TimeSpan.FromSeconds(2);
Having understood what fixed timestep mode is, I think the correct decision is to embrace it. I was trying to mimic Unity where you have a double deltaTime passed to each update call.