Year 2038 Problem
Does STM currently have a guideline or recommendation(s) for handling the 2038 problem?
Does STM currently have a guideline or recommendation(s) for handling the 2038 problem?
STM32 RTCs store year as last 2 digits. They also have a primitive leap-year calculation that only checks remainder of 4.
So the year will go from 0 to 99 and then wrap (overflow). So a fixed offset of 2000 means the year will fail at 2100.
Also leap years will fail in 2100 as 2100 is seen as a leap year, when it's not.
So they have two year-2100 problems.
I have a fix for both:
run this before processing rtc dates:
HAL_RTC_GetTime(&hrtc, &systemTimeTemp, RTC_FORMAT_BIN);
HAL_RTC_GetDate(&hrtc, &systemDateTemp, RTC_FORMAT_BIN); // Always call GetDate after GetTime (RTC locking)
//leap year correction to allow proper leap year until 2400
if (systemDateTemp.Year == 0 && systemDateTemp.Month == 2 && systemDateTemp.Date == 29)
{
//skip leap year as year is multiple of 100, but not multiple of 400
systemDateTemp.Month = 3;
systemDateTemp.Date = 1;
__disable_irq();
SystemTime = systemTimeTemp;
SystemDate = systemDateTemp;
__enable_irq();
HAL_RTC_SetTime(&hrtc, &SystemTime, RTC_FORMAT_BIN);
HAL_RTC_SetDate(&hrtc, &SystemDate, RTC_FORMAT_BIN);
}
else
{
__disable_irq();
SystemTime = systemTimeTemp;
SystemDate = systemDateTemp;
__enable_irq();
}
(Note that this only works if the routine is run every 24 hours. So if the device is not turned on when it thinks there is a leap year (monday march 1st 2100) it won't work. You would need some algorithm to flag if it skipped the leap day that year. You could probably use some spare RTC memory for this. So if it is after march 1st and this flag has not been set, then you should add 1 day to the date and set that flag. Clear the flag if the date is before feb 29 or if it is not 2100, 2200 or 2300. An alternative algorithm would keep the date in the calendar invalid and add an offset of 1 day to a copy.)
Use this to convert RTC year to absolute year:
#define DATE_TO_YEAR(d) (d[7] == '?' ? 1900 : \
(((d[7] - '0') * 1000 ) + (d[8] - '0') * 100 + (d[9] - '0') * 10 + d[10] -'0'))
#define BUILD_YEAR DATE_TO_YEAR(__DATE__)
// allow operation beyond 2099 (up to BUILD_YEAR + 99)
uint16_t yearAbs = systemDateCopy.Year + (BUILD_YEAR/100)*100;
if (yearAbs < BUILD_YEAR)
{
yearAbs += 100;
}
If you want the program to work longer you need to periodically update the firmware to update the build date. Or you store the year in eeprom every year. RTC battery will fail before 2100. But you can always replace the battery and set the time again. It would be nice if products made now won't be automatically obsolete in 2100.
Enter your E-mail address. We'll send you an e-mail with instructions to reset your password.