7 years, 10 months ago.

mktime bug for year 2038?

similiar to this question https://developer.mbed.org/questions/68608/Year-2038-Bug-rtc_timeh-and-timeh-32bit-/ i have another problem for which i think mktime is behaving wrong. mktime generates a date with year 1902 when the struct tm has year 2038.

Serial pc(SERIAL_TX, SERIAL_RX);
const char* TIME_PATTERN = "%d-%m-%Y";

std::string getTimeAsString(tm * seconds, std::string pattern) {
	char buf[40];
	strftime(buf, 40, pattern.c_str(), seconds);
	std::string time = buf;
	return time;
}

std::string getTimeAsString(time_t seconds, std::string pattern) {
	char buf[40];
	strftime(buf, 40, pattern.c_str(), localtime(&seconds));
	std::string time = buf;
	return time;
}

time_t getTimeAsObject(std::string timeString, std::string patternOfTimeString) {
	struct tm time_buffer;
	time_buffer.tm_year = (uint8_t)100;
	time_buffer.tm_mon = (uint8_t)0;
	time_buffer.tm_mday = (uint8_t)1;
	time_buffer.tm_hour = (uint8_t)1;
	time_buffer.tm_min = (uint8_t)0;
	time_buffer.tm_sec = (uint8_t)0;

	strptime(timeString.c_str(), patternOfTimeString.c_str(), &time_buffer);
	pc.printf("Here is always correct --> %s\n", getTimeAsString(&time_buffer, TIME_PATTERN).c_str());
	time_t desired_time = mktime(&time_buffer);   //<------I THINK THIS LINE IS BEHAVING WRONG
	return desired_time;
}

int main() {
	pc.baud(9600);

	time_t dateTime1 = getTimeAsObject("31-12-2037", TIME_PATTERN);
	std::string time = getTimeAsString(dateTime1, TIME_PATTERN);
	pc.printf("Correct : %s\n", time.c_str());
	dateTime1 = getTimeAsObject("31-12-2038", TIME_PATTERN);
	time = getTimeAsString(dateTime1, TIME_PATTERN);
	pc.printf("----Wrong-----: %s\n", time.c_str());
}

the output of the program is

Here is always correct --> 31-12-2037
Correct : 31-12-2037
Here is always correct --> 31-12-2038
----Wrong-----: 24-11-1902

So is this a bug or how can i generate the right date as string?

2 Answers

7 years, 10 months ago.

If you calculate with a signed integer starting from 1970 it overflows in 2038, so there you have your problem.

It even has its own wiki page: https://en.wikipedia.org/wiki/Year_2038_problem

So kinda working as intended, although eventually they probably are going to need to switch to either 64-bit or unsigned integers.

Accepted Answer

Hi Erik, thanks for your answer. So it means that for the moment there is no way how to go around this problem with mktime on mbed? I am making use of difftime(time_t, time_t) to compare time instances thats why i used mktime. Is there another way to do time comparison except manually comparing struct tm member variables one by one?

posted by anteo c 02 Jun 2016

You can make your own code which handles it I guess. However in principle no, the standard code on mbed (and apparantly lot of other places), won't do it for you. Next question would be, who cares for the coming 20 years?

posted by Erik - 03 Jun 2016

yes you are right. just wanted to make it bullet proof using the standard libraries ;)

posted by anteo c 03 Jun 2016
7 years, 10 months ago.

Hello,

When I tried to compile the code I have got
Error: Identifier "strptime" is undefined in "main.cpp", Line: 33, Col: 6
So I was not able to fully test your code. Anyway, maybe this helps you find the bug:

After commenting out the strptime function and setting the time_buffer to 2038-12-31 manually:

time_t getTimeAsObject(std::string timeString, std::string patternOfTimeString) {
    struct tm time_buffer;
    time_buffer.tm_year = (uint8_t)(2038 - 1900);
    time_buffer.tm_mon = (uint8_t)(12 - 1);
    time_buffer.tm_mday = (uint8_t)31;
    time_buffer.tm_hour = (uint8_t)1;
    time_buffer.tm_min = (uint8_t)0;
    time_buffer.tm_sec = (uint8_t)0;
 
//    strptime(timeString.c_str(), patternOfTimeString.c_str(), &time_buffer);
    pc.printf("Here is always correct --> %s\n", getTimeAsString(&time_buffer, TIME_PATTERN).c_str());
    time_t desired_time = mktime(&time_buffer);   //<------I THINK THIS LINE IS BEHAVING WRONG
    return desired_time;
}
 
int main() {
    pc.baud(9600);
 
    time_t dateTime1 = getTimeAsObject("31-12-2037", TIME_PATTERN);
    std::string time = getTimeAsString(dateTime1, TIME_PATTERN);
    pc.printf("Correct : %s\n", time.c_str());
    dateTime1 = getTimeAsObject("31-12-2038", TIME_PATTERN);
    time = getTimeAsString(dateTime1, TIME_PATTERN);
    pc.printf("----Wrong-----: %s\n", time.c_str());
}


I have got a correct printout:

Here is always correct --> 31-12-2038
Correct : 31-12-2038
Here is always correct --> 31-12-2038
----Wrong-----: 31-12-2038


So it seems that the mktime function works correctly.

Hi Zoltan, thanks for your answer. That is strange since your change is causing following output in my board

Here is always correct --> 31-12-2038
Correct : 24-11-1902
Here is always correct --> 31-12-2038
----Wrong-----: 24-11-1902

Are you testing on any mbed board?. I have a NucleoF401 and strptime is part of time.h. I think what Erik wrote is the answer to my problem that as it seams can not be solved.

posted by anteo c 02 Jun 2016

Hello Anteo, Yes it seems strange. I tested the code on a NUCLEO-F103RB board. I also tried to compile it for the NUCLEO-F401RE or LPC1768 board with the time.h header file included but it did not allow me to use the strptime function. Are you using only the mbed library?

posted by Zoltan Hudak 02 Jun 2016

Hi Zoltan, yes u are right the online compiler does not allow to use it. I am using eclipse together with platformio and the time.h comes there from "./platformio/packages/toolchain-gccarmnoneeabi/arm-none-eabi/include/time.h"

posted by anteo c 03 Jun 2016