Time Bug...

Discussion to talk about software related topics only.
Post Reply
User avatar
pbreed
Posts: 1080
Joined: Thu Apr 24, 2008 3:58 pm

Time Bug...

Post by pbreed »

If you use the function timegm....

As of January 1 2017 its off by on day..... (has to do with leap year calcs and off by one)

So if you use this please make a support request to get new code.

Paul
SeeCwriter
Posts: 606
Joined: Mon May 12, 2008 10:55 am

Re: Time Bug...

Post by SeeCwriter »

According to the release notes for v2.8.3, the leap year error was supposed to be fixed. It seems to be fixed for the MOD5441X, but its been made worse for the NANO. When compiled with v.2.8.1, reading the date is off by a day. But when the same code is compiled with v2.8.3, the date comes out as January 1, 1970. This only reading, not trying to set the time. If I load the v2.8.1 build again, reading the date returns to normal, 1 day off.
SeeCwriter
Posts: 606
Joined: Mon May 12, 2008 10:55 am

Re: Time Bug...

Post by SeeCwriter »

I did a little more digging to try to find out why time can't be set in the Nano with v2.8.3. You'll note that the time and date read from the RTC is correct. It's setting and/or reading the system time that fails. So it's not an i2c bus issue.

Here is my test function:

Code: Select all

void InitTime()
{
	struct tm bts, *ptm;

	tzsetchar("PST8PDT7");

	int rv = RTCGetTime( bts );  // This returns the correct time & date.
	if ( rv ) {
		puts("Error Getting time");
		return;
	}
	puts("Time from RTC:");
	iprintf("Year: %d\r\n", bts.tm_year );
	iprintf("Mon:  %d\r\n", bts.tm_mon  );
	iprintf("Day:  %d\r\n", bts.tm_mday );
	iprintf("Hour: %d\r\n", bts.tm_hour );
	iprintf("Min:  %d\r\n", bts.tm_min  );
	iprintf("Sec:  %d\r\n", bts.tm_sec  );

	time_t t = timegm( &bts );
	iprintf("Set GMTime: %ld\r\n", t );
	set_time( t );

	OSTimeDly(TICKS_PER_SECOND );

	t = 0;
	time( &t );
	iprintf("Get GMTime: %ld\r\n", t );

	ptm = gmtime( &t );
	puts("Sys Time:");
	iprintf("Year: %d\r\n", ptm->tm_year );
	iprintf("Mon:  %d\r\n", ptm->tm_mon  );
	iprintf("Day:  %d\r\n", ptm->tm_mday );
	iprintf("Hour: %d\r\n", ptm->tm_hour );
	iprintf("Min:  %d\r\n", ptm->tm_min  );
	iprintf("Sec:  %d\r\n", ptm->tm_sec  );

	struct tm *ltime = localtime(&t);
	puts("Local Time:");
	iprintf("Year: %d\r\n", ltime->tm_year );
	iprintf("Mon:  %d\r\n", ltime->tm_mon  );
	iprintf("Day:  %d\r\n", ltime->tm_mday );
	iprintf("Hour: %d\r\n", ltime->tm_hour );
	iprintf("Min:  %d\r\n", ltime->tm_min  );
	iprintf("Sec:  %d\r\n", ltime->tm_sec  );

	return;

	// Set time from offboard RTC chip.
	//if ( RTCSetSystemFromRTCTime() )
	//	puts("Error Setting time");
}
Output:
==============
Time from RTC:
Year: 117
Mon: 2
Day: 28
Hour: 9
Min: 43
Sec: 57

Set GMTime: 8415837
Get GMTime: 8415838

Sys Time:
Year: 70
Mon: 3
Day: 8
Hour: 9
Min: 43
Sec: 58

Local Time:
Year: 70
Mon: 3
Day: 8
Hour: 2
Min: 43
Sec: 58
SeeCwriter
Posts: 606
Joined: Mon May 12, 2008 10:55 am

Re: Time Bug...

Post by SeeCwriter »

Since function timegm() is calculating the wrong value for the number of seconds since 1/1/1970,
I copied the source to my project and renamed it, and made a few tweeks. You'll notice that the
first original calculation is suppose to calculate the number of seconds in the years since 1970.
But it loads the value into ttDays, instead of ttYears as I would have expected. Then two calcs
later under comment "Extract time_t seconds from tm_mon" it calculates the number of seconds in
the months of the current year and overwrites the first calculation for years. Looks suspicious
to me.

After my changes, it now comes very close to the actual time. It's off by an hour when using time(),
but that may be the leap-year issue. And off by 7 hours when using localtime() (UTC setting?).
In any case, at least it's in the ballpark now. I compared the same function in v2.8.1 with the
one in v2.8.3, and they appear to be the same, so I can't explain why v2.8.1 works and v2.8.3 doesn't.

Maybe someone who knows more about this than me can shed some light on it.

Code: Select all

time_t mytimegm(struct tm *bts)
{
    time_t ttYears = 0;     // Seconds converted from tm_year (since 1900)
    time_t ttMonths = 0;    // Seconds converted from tm_mon (0-11)
    time_t ttDays = 0;      // Seconds converted from tm_mday (1-31)
    time_t ttHours = 0;     // Seconds converted from tm_hour (0-23)
    time_t ttMinutes = 0;   // Seconds converted from tm_min (0-59)
    time_t ttSecs = 0;      // Cumulative seconds including tm_sec (0-59)
	time_t numYears=0;

    int daysPerMonth[] = { 31 /* Jan */, 28 /* Feb */, 31 /* Mar */,
                           30 /* Apr */, 31 /* May */, 30 /* Jun */,
                           31 /* Jul */, 31 /* Aug */, 30 /* Sep */,
                           31 /* Oct */, 30 /* Nov */, 31 /* Dec */ };

    // Extract time_t seconds from tm_year (time_t starts from 1970-01-01)
	 #ifdef foo
   if(bts->tm_year<69) 
	 ttDays -= (((69-bts->tm_year)+3) / 4) * 24 * 3600;
	 else
     ttDays += (((bts->tm_year - 69)) / 4) * 24 * 3600;      // Add leap days excluding current year
	 #else
	 numYears = (bts->tm_year+1900) - 1970;
	 ttYears  = numYears * 365 * 86400;	// Calc seconds of years since 1970.
	 ttYears += (numYears / 4) * 86400; // Add a day of sec for each leap year.
	 #endif

    // Extract time_t seconds from tm_mon
    for (int i = 0; i < bts->tm_mon; i++ ) { ttMonths += daysPerMonth[i]; }
    ttMonths *= 24 * 3600;

    // Extract time_t seconds from tm_mday
    ttDays = (bts->tm_mday - 1) * 24 * 3600;
	#ifdef foo
    ttDays += ((bts->tm_year - 70) / 4) * 24 * 3600;      // Add leap days excluding current year
	#endif
    
    // Extract time_t seconds from tm_hour
    ttHours = bts->tm_hour * 3600;
    
    // Extract time_t seconds from tm_min
    ttMinutes = bts->tm_min * 60;
    
    // Tally up extracted seconds including tm_sec
    ttSecs = bts->tm_sec + ttMinutes + ttHours + ttDays + ttMonths + ttYears;
    iprintf("Sec: %d, Min: %ld, Hrs: %ld, Days: %ld, Mon: %ld, Yrs: %ld\r\n",
						bts->tm_sec, ttMinutes, ttHours, ttDays, ttMonths, ttYears );
    // Determine if current leap year and add add leap day if necessary
    if (((bts->tm_year % 4) == 0) && (bts->tm_mon > 1)) {
        ttSecs += 24 * 3600;   
    }

    return ttSecs;
}
Post Reply