2
votes

This small program reproduces the bug in my project. time_t variable is converted to struct_tm, then to string, and serialized to file. Later, this string is loaded from the file, and should be converted back to time_t. Resulting time_t differs from original by one hour (possibly because of daylight saving time). I can change only deserialization part, because file format should remain unchanged.

#include "stdafx.h"
#include <iostream>
#include <string>
#include <time.h>

using namespace std;

string FormatDateTime(struct tm* time);
void Test();


int _tmain(int argc, _TCHAR* argv[])
{
    Test();
    return 0;
}


string FormatDateTime(struct tm* time)
{
    static const char* months[] =
    {
        "Jan", "Feb",  "Mar", "Apr", "May", "Jun",  "Jul", "Aug",  "Sep", "Oct",  "Nov", "Dec"
    };

    char s[30];
    const char* month;

    if ( time->tm_mon >= 0  &&  time->tm_mon < 12 )
    {
        month = months[time->tm_mon];
    }
    else
    {
        month = "??";
    }

    sprintf(s, "%d-%s-%02d %02d:%02d:%02d",
        time->tm_year + 1900,
        month,
        time->tm_mday,
        time->tm_hour,
        time->tm_min,
        time->tm_sec);

    return s;
}

void Test()
{
    // time_t variable is initialized with current time
    time_t t = time(NULL);

    // time_t variable is converted to struct tm and then to string
    struct tm* ptm = localtime(&t);

    char buffer[100];

    sprintf(buffer, "%d %d %d %d %d %d",
        ptm->tm_mday, ptm->tm_mon + 1, ptm->tm_year + 1900, ptm->tm_hour, ptm->tm_min, ptm->tm_sec);

    cout << buffer << endl;         // string is OK


    // string is saved to the file

    // *********************************************************************************************

    // later this string is restored from the file

    // **** I can change something only after this line **** //

    struct tm stm;
    memset(&stm, 0, sizeof(stm));

    sscanf(buffer, "%d %d %d %d %d %d",
        &stm.tm_mday, &stm.tm_mon, &stm.tm_year, &stm.tm_hour, &stm.tm_min, &stm.tm_sec);

    stm.tm_mon -= 1;
    stm.tm_year -= 1900;

    string s = FormatDateTime(ptm);

    cout << s << endl;              // OK

    // *********************************************************************************************
    // Now I need to convert struct tm to time_t and keep it in the variable

    time_t t1 = mktime(&stm);       // not the same time - 1 hour difference

    if ( t1 == t )
    {
        cout << "t1 == t" << endl;
    }
    else
    {
        cout << "t1 != t   !!!!!" << endl;
    }

    // time_t is printed - result is incorrect

    // Utilities::FormatDateTime
    struct tm* ptm1 = localtime(&t1);

    s = FormatDateTime(ptm1);

    cout << s << endl;
}

Local time is 11.33. Result:

19 7 2012 11 33 17
2012-Jul-19 11:33:17
t1 != t   !!!!!
2012-Jul-19 12:33:17

How can I change the last part of this program to get correct result?

2
What's this: if ( time->tm_mon >= 0 && time->tm_mon tm_mon]; }?SingerOfTheFall
@SingerOfTheFall - the question is edited.Alex F
Can't reproduce, it totally works for me: 19 7 2012 12 45 48 2012-Jul-19 12:45:48 t1 == t 2012-Jul-19 12:45:48SingerOfTheFall
@SingerOfTheFall maybe you are in another timezone so you don't notice it.AndersK
@SingerOfTheFall - can you tell me what is ptm->tm_isdst in your case? My guess is that it should be 0 (daylight saving time is not applied), in my case it is 1, since daylight saving is applied in my country.Alex F

2 Answers

4
votes

my guess is that tm_isdst is different in your both tm structs. In one case its 0 and in the other 1.

-1
votes

That will not solve the probleme but for compatibility issues that might come later time 0 should represent january 1st 1970 and not 1900