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-03-01 2:34 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 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.
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-03-01 2:34 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 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.
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.
2025-03-01 12:01 AM
If you are using UNIX-epoch time, as used by functions prototyped in <time.h>, either by converting from calendar-style time or using the natively binary feature of RTCv1 or some incarnations of RTCv3 - and you use gcc with newlib, you may want to check the version of newlib you are using.
JW