2025-02-27 4:01 PM - last edited on 2025-02-28 1:19 AM by mƎALLEm
Does STM currently have a guideline or recommendation(s) for handling the 2038 problem?
Solved! Go to Solution.
2025-02-28 4:58 AM - edited 2025-02-28 5:06 AM
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 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();
}
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.
2025-02-27 7:44 PM
What is it?
2025-02-27 9:56 PM
2025-02-28 12:04 AM
You mean the year 2038 problem - as @repaint suggested ?
Where do you see that being a specific issue for the STM32 ?
2025-02-28 3:38 AM
You ask about a problem with systems which measure Unix time .
But here is not a Unix system, but just a controller with RTC , that has only years 10 + 1 in BCD : 2025 is only "25" in RTC :
So its up to you, how you handle the full date in your software :
if using a uint_16t to store the "full" year, you will get a problem in the year 65536 - if your device still running and in use. How long you expect it working and be in use ?
2025-02-28 4:34 AM
Depends a lot on the robustness of design. Many RTC and calendars assume 2100 is a leap year.
Seen too many with a 1901 to 2099 limit, not that it's likely to be an issue, but people get lazy, and fewer are maintaining and understanding systems.
2025-02-28 4:58 AM - edited 2025-02-28 5:06 AM
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 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();
}
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.
2025-02-28 12:10 PM
Thank you for the responses. A lot of useful information that answers my original question. I thought perhaps STM would have some core guidelines for this sort thing and therefore wanted to ask about it.