seconds timekeeping

I sometimes wish there was seconds timekeeping in the Arduino core. For a recent project, I implemented seconds timekeeping in wiring.c as follows.
See seconds timekeeping and time conversion - Exhibition / Gallery - Arduino Forum for some libraries to use this.

I reviewed a couple of "userland" tools for timekeeping based on millis(), but the code complexity is high and the overhead of constantly reading millis() and correlating to a userland seconds timekeeping is pretty high. I want something where the normal timer interrupt does the work. My solution adds a dozen instructions to the timer0 overflow and 6 bytes of static variables.

volatile unsigned long timer0_sec = 0;
static unsigned int timer0_sec_fract = 0;

#if defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
ISR(TIM0_OVF_vect)
#else
ISR(TIMER0_OVF_vect)
#endif
{
	// copy these to local variables so they can be stored in registers
	// (volatile variables must be read from memory on every access)
	unsigned long m;
	unsigned int f = timer0_fract;

	m = MILLIS_INC;
	f += FRACT_INC;
	if (f >= FRACT_MAX) {
		f -= FRACT_MAX;
		m += 1;
	}

	timer0_fract = (unsigned char) f;
	timer0_millis += m;
	timer0_overflow_count++;

	/* Also keep track of seconds
	 */
	f = timer0_sec_fract + m;
	if (f >= 1000) {
            timer0_sec += 1;
	    f -= 1000;
	}
	timer0_sec_fract = f;
}

void time_set(unsigned long t)
{
   uint8_t oldSREG = SREG;
   cli();
   timer0_sec = t;
   timer0_sec_fract = 0;
   SREG = oldSREG;
}

unsigned long time_sec()
{
   unsigned long m;
   uint8_t oldSREG = SREG;

   // disable interrupts or we might get an
   // inconsistent value (e.g. in the middle of a write)
   cli();
   m = timer0_sec;
   SREG = oldSREG;

   return m;
}

How is that different from:

static unsigned long timerStart = 0;

// Set the current time in seconds
void time_set(unsigned long t)
{
   timerStart = millis() - (t*1000UL);
}

// Return the current time in seconds
unsigned long time_sec()
{
   return (millis() - timerStart) / 1000UL;
}

It does not wrap after a few days like millis() does.

gardner:
It does not wrap after a few days like millis() does.

The millis() timer wraps after about 47 days. The version I wrote should work properly across the wrap so unless you are measuring a single interval greater than 46 days it shouldn't be a problem.

johnwasser:
The version I wrote should work properly across the wrap

I do not see that. millis() is unable to tell the difference between now and 49 days 17 hours ago, or 49 days 17 hours from now. A simple unchanging offset doesn't fix that. To use millis() as the base timer for a longer term clock you have to guaranty that you sample millis() often enough (at least every two dozen days) to spot when it rolls over, and adjust the offset. There are several implementations of that around, but they are more complex than what I wanted.

unless you are measuring a single interval greater than 46 days

That is the requirement.

So you are not going to look at the time for 49 days at a time?
What a patient program.