Question about while loop in Timelib

Dear Arduino-Community,

I’m trying to understand the inner workings of the Timelib library:

and stumbled upon the following Code snippet:

time_t now() {
	// calculate number of seconds passed since last call to now()
  while (millis() - prevMillis >= 1000) {
		// millis() and prevMillis are both unsigned ints thus the subtraction will always be the absolute value of the difference
    sysTime++;
    prevMillis += 1000;	
#ifdef TIME_DRIFT_INFO
    sysUnsyncedTime++; // this can be compared to the synced time to measure long term drift     
#endif
  }
  if (nextSyncTime <= sysTime) {
    if (getTimePtr != 0) {
      time_t t = getTimePtr();
      if (t != 0) {
        setTime(t);
      } else {
        nextSyncTime = sysTime + syncInterval;
        Status = (Status == timeNotSet) ?  timeNotSet : timeNeedsSync;
      }
    }
  }  
  return (time_t)sysTime;
}

I have a hard time understanding how the while loop works here. Usually, when I see a while loop, I immediately think of blocking issues, but surely he found a clever solution for not making that happen, I just don’t understand yet.

getTimePtr != 0

Is basically there to check, if there is any function for getting the time (NTP, RTC) I guess?

      if (t != 0) {
        setTime(t);
      } else {
        nextSyncTime = sysTime + syncInterval;
        Status = (Status == timeNotSet) ?  timeNotSet : timeNeedsSync;
      }

Is this expression there to check, if a sync was successfull and when do we actually get into the else block?

(t != 0)

Thanks for any help!
Kind regards

  // calculate number of seconds passed since last call to now()
  while (millis() - prevMillis >= 1000) {
		// millis() and prevMillis are both unsigned ints thus the subtraction will always be the absolute value of the difference
    sysTime++;
    prevMillis += 1000;	
#ifdef TIME_DRIFT_INFO
    sysUnsyncedTime++; // this can be compared to the synced time to measure long term drift     
#endif
  }

Looks like sysTime is the actual counter for the clock, in seconds, in unix time format (since it is later used for the return value for now() ).

prevMillis is synced with sysTime in the setTime() function.

When you call now(), if it has been more than 1000mS since the last call to now(), sysTime and prevMillis are both incremented by 1 second intervals until the difference between millis() and prevMillis is less than a second.

The remainder of the code is checking to see if a clock sync source has been set (by the setSyncProvider() function), and if it is time to sync the clock (by default every 300 seconds).

Thank you for your time and the explanation!

Somebody else actually had the same question and there was plenty of discussion there: Why a while-loop? · Issue #13 · PaulStoffregen/Time · GitHub

I’m using the Timelib and the DS3231 library based on the recommendation in this thread: https://forum.arduino.cc/index.php?topic=441898.msg3043340#msg3043340

After looking more into the code, I’m kinda asking myself what happens, when a re-sync through a RTC doesn’t work, because communication on the I2C-Bus failed.

I’m using RTC.get() from the library <DS3231.lib>.

The description of this function says (GitHub - JChristensen/DS3232RTC: Arduino Library for Maxim Integrated DS3232 and DS3231 Real-Time Clocks):

Reads the current date and time from the RTC and returns it as a time_t value. Returns zero if an I2C error occurs (RTC not present, etc.).

I’m using both these lines, to set the provider for the syncing and for setting the interval:

 setSyncProvider(RTC.get);   // the function to get the time from the RTC
 setSyncInterval(5);         // set the number of seconds between re-syncs

RTC.get returns 0, if a re-sync didn’t work, therefore I think this line is catching that:

      if (t != 0) {
        setTime(t);
      }

and only re-syncs the system time, if t is not 0.

Actually for debug-purposes, I would like to see, when the sync was successfull and I think, I could do this:

      if (t != 0) {
        setTime(t);
#ifdef DEBUG
        Serial.println("system time re-synced");
#endif
      }

but is there any way, to just use timeSet for that?

Originally, I’ve used in my Arduino Code:

if (timeStatus() == timeSet) {
#ifdef DEBUG
      Serial.println("Time Set");
#endif
}

But this got permanentely printed as output on my Serial monitor so it appears, that timeStatus() only gets changed, when something happens. timeStatus() always gets overwritten it seems. So this doesn’t work.

My last question would be, if a 5 second re-sync is necessary for an Arduino. I’m using a Mega 2560.
After reading that post, I think that’s necessary, when you want the system time as accurate as possible (Considering also communication errors on the I2C-Bus): https://forum.arduino.cc/index.php?topic=13289.msg99306#msg99306

gaebel90:
My last question would be, if a 5 second re-sync is necessary for an Arduino. I'm using a Mega 2560.
After reading that post, I think that's necessary, when you want the system time as accurate as possible (Considering also communication errors on the I2C-Bus): https://forum.arduino.cc/index.php?topic=13289.msg99306#msg99306

Five seconds is way too often, if you need that level of correction use the square wave output of the DS3231 to interrupt the arduino at 1-second intervals and sync the clock off that, then no further I2C communications is needed. See the DS3232RTC library for an example of how to do that - note that library also works with the DS3231.

david_2018:
Five seconds is way too often, if you need that level of correction use the square wave output of the DS3231 to interrupt the arduino at 1-second intervals and sync the clock off that, then no further I2C communications is needed. See the DS3232RTC library for an example of how to do that - note that library also works with the DS3231.

I want to take measurements every 10 seconds at set times. My syncintervall depends on the accuracy of the clock of the arduino itself. Is it unreasonable for me to think, that the Arduino system time drifts too much? In the post you quoted, there is a link I referred to. Somebody said there:

A ceramic resonator is about 0.5% accurate = 72 seconds over 4 hours or about 1 minute 12 seconds at 16MHz.

I guess that would be 300ms off per minute from the real time. I could deal with one second of inaccuracy after 3 minutes. That's not too bad so a re-sync after 300 seconds would be okay. I'm not sure though what happens, when a re-sync fails, because of faulty communication. Does a re-sync happen again after a failure or not? Or do we have to wait till the next 300 seconds happen for the next re-sync. I can't tell from the code in the timelib at the moment. That's why I set the syncintervall so high. It's a hack to make the possibility of a re-sync not happening for a long time tiny I guess.

Thanks again for the input!