Interrupts messing up millis() comparisson after overflow?

I have a sketch that is left running indefinitely, and within it I use comparisons to millis() for timing and debouncing events in the format below.

if (millis() - lastThingTime > (thingDebounceSeconds * 1000)) {
  lastThingTime = millis();

On day 50 of the sketch running I get the dreaded result that doThing() is no longer called. I have tried a couple of things to replicate this error in a shorter amount of time by simulating the millis() overflow. When I replace all calls to millis() in my sketch with either of the below functions everything works perfectly across the spoofed overflow.

// Causes spoof overflow 30 seconds after boot
uint32_t spoofMillis() {
  uint32_t spoof = millis();
  spoof -= 30000;
  return spoof;

// Causes spoof overflow every 65(ish) seconds
uint16_t spoofMillis() {
  uint16_t spoof = millis();
  return spoof;

I have read in various posts that disabling then interrupts, even for a short amount of time can cause issues with millis(). This sketch also uses a watchdog timer which is setup with the below function.

void watchdogSetup() {
  WDTCSR |= (1<<WDCE) | (1<<WDE);
  WDTCSR = (1<<WDIE) | (1<<WDE) | (1<<WDP3) | (0<<WDP2) | (0<<WDP1) | (0<<WDP0);


What are the chances that this momentary disabling of the interrupts is causing trouble 50 days later? I’m pretty sure, given my above testing that it is not my usage of millis() causing me issues, but that something is messing it up behind the scenes. Any ideas would be greatly appreciated, as 50 days is a long time to wait between testing tweaks!

Please post the complete program.


The problem is not the critical section, its plenty short enough not to affect millis(),
and your test for lastThingTime looks fine, but not being able to see the declarations of any variables
there is no way to say it is fine.

The problem is (as is often the case) in part of the sketch you didn’t provide. Whole sketch please…

My guess is that some of your millisecond values are not unsigned long. Without more of the sketch it is impossible to tell.

If "thingDebounceSeconds" is an 'int' greater than 32 or an 'unsigned int' greater then 65 you will get an integer overflow in "(thingDebounceSeconds * 1000)". Without more of the sketch it is impossible to tell.