Millis() rolls over after 24 days

Hello,

as the return value of millis() is an int, it rolls over after 2147483647 ms, that is 24.8 days.

long t0 = System.currentTimeMillis();
long t1 = t0 + 2147483647 + 10;
int dt = (int)(t1 - t0);
println(“dt=”+dt); // dt=-2147483639

So should we handle the rollover moment in our code, for sketches that use millis() for calculations or timers and that are supposed to run for ever ?

Or shouldn’t better use the system function System.currentTimeMillis() which returns a long, and rolls over in a few hundred years ?

Hi @schmittmachine ,

Well! I personally would use my own timer handling in such a case. Quite easy to implement…
Internally processing works with long as it uses System.currentTimeMillis()-starttime to calculate the return value for millis(), but unfortunately casting to int for return value imo due to follow a rule to keep the datatype usage simple.

Cheers
— mnse

1 Like

Yep, just use a larger type like you said System.currentTimeMillis(). It should do the job, no need to overthink it.

Indeed. It’s just that I’ve been using millis() for years, even for works running for a very long time, and now I’m wondering what magic made them work without a glitch for so long.

Hi @schmittmachine,

in the most common usage the impact will be quite low… see below.

Cheers
— mnse

PS: Nevertheless, I personally wouldn’t use millis(), if I would expect the process should run stable and longer then 24d. :grin:

final int deltaTimeMS = 1000;
int  nextStepMS;
long current;

void setup() {
  size(500, 500);
  noStroke();
  current = Integer.MAX_VALUE - 20000L;
  nextStepMS = (int)current;
}

int next() {
  current+=100L;
  return (int)current;
}

void draw() {
  background(0);
  int t = next();
 
  // Most common approach, less impact as the logic still works as both flip signs
  if (t >= nextStepMS) {
    println("do somthing: " + t);
    nextStepMS = t + deltaTimeMS;
  }
  
  fill(0, 255, 0);
  // another approach with modulus will break because of sign flip
  arc(width*.25, height/2, 100, 100, 0, radians(floor(t/100.) % 360));
  
  fill(255, 0, 0);
  // same approach but with absolute modulus, will flip rotation direction
  arc(width*.75, height/2, 100, 100, 0, radians(abs(floor(t/100.)) % 360));
}

Ok, just for the record, I understand now why my code has worked over this rollover over the years.

Most of my code moves objets according to time passed since last frame :

int millis_counter;
int previousT;
float angle = 0.0;

void setup() {
  size(500, 500);
  millis_counter = previousT = Integer.MAX_VALUE - 1000;
}

int myMillis() {
  millis_counter += 100;
  return millis_counter;
}

void draw() {
  background(0);
  
  int now = myMillis();
  int deltaT = now - previousT;
  println(" previousT="+previousT+" now="+now+" deltaT="+deltaT);
  previousT = now;
  
  // move according to time passed
  angle += deltaT*0.001;
  
  arc(width*.25, height/2, 100, 100, 0, angle % (2*PI));
}

And when rollover happens, the substraction actually works : -2147483549 - 2147483647 = 100

previousT=2147483447 now=2147483547 deltaT=100
previousT=2147483547 now=2147483647 deltaT=100
previousT=2147483647 now=-2147483549 deltaT=100
previousT=-2147483549 now=-2147483449 deltaT=100
previousT=-2147483449 now=-2147483349 deltaT=100

Thanks for the shared thoughts

3 Likes