views:

161

answers:

3
+3  Q: 

C++ time_t problem

Hi SO,

I'm having trouble with dates management in C++ (VS 2008).

According to MSDN specifications, time_t represents:

The number of seconds since January 1, 1970, 0:00 UTC

therefore, I've written this piece of code:

#include <stdio.h>
#include <time.h>

time_t GetDate(int year, int month, int day, int hour, int min, int sec)
{
    time_t rawtime;
    struct tm * timeinfo;

    time ( &rawtime );
    timeinfo = gmtime ( &rawtime );
    timeinfo->tm_year = year - 1900;
    timeinfo->tm_mon = month - 1;
    timeinfo->tm_mday = day;
    timeinfo->tm_hour = hour;
    timeinfo->tm_min = min;
    timeinfo->tm_sec = sec;
    timeinfo->tm_isdst = 0; // disable daylight saving time

    time_t ret = mktime ( timeinfo );

    return ret;
}

int main ()
{
    time_t time_0 = GetDate(1970,1,1,0,0,0);
    // time_0 == -1 !!!
    time_t time_1 = GetDate(1970,1,1,1,0,0);
    // time_1 == 0 !!!
    return 0;
}

It seems to be shifted by 1 hour (i.e. zero time is January 1, 1970, 1:00 UTC).

Initially, I thought the problem could come from the DayLightSaving flag, but it doesn't change by changing it.

Am I doing something wrong ?

Thanks in advance


P.S. In theory, I might not mind the zero time value, because it's only a reference time.

But I need to be sure about the value, because I'm porting the code to another language and I need to get exactly the same results.


EDIT:

here's the solution, thanks to Josh Kelley Answer

time_t mktimeUTC(struct tm* timeinfo)
{
    // *** enter in UTC mode
    char* oldTZ = getenv("TZ");
    putenv("TZ=UTC");
    _tzset();
    // ***

    time_t ret = mktime ( timeinfo );

    // *** Restore previous TZ
    if(oldTZ == NULL)
    {
        putenv("TZ=");
    }
    else
    {
        char buff[255];
        sprintf(buff,"TZ=%s",oldTZ);
        putenv(buff);
    }
    _tzset();
    // ***

    return ret;
}
A: 

You have a typo. 1900 should be 1970.[edit] nevermind; time_t != struct tm. Sorry!

tenfour
A: 

Just a WAG but try the following:

timeinfo->tm_year = year - (unsigned long)1900;
timeinfo->tm_mon = month - (unsigned long)1;
Hogan
1900 is correct see --> http://msdn.microsoft.com/en-us/library/0z9czt0w%28v=VS.90%29.aspx
digEmAll
@dig, changed that.... Do you set the TM environment variable?
Hogan
Ehm...what is TM environment var ?
digEmAll
Got it you meant TZ ;)
digEmAll
yeah... josh explained it better than I did.
Hogan
+6  A: 

mktime takes a struct tm giving a local time and returns the number of seconds since January 1, 1970, 0:00 UTC. Therefore, your GetDate(1970,1,1,0,0,0); call will return 0 if your local time zone is UTC but may return other values for other time zones.

Edit: For a UTC version of mktime or your GetDate, try the following (untested):

  1. Call getenv to save the current value of the TZ environment variable (if any).
  2. Call putenv to change the TZ environment variable to "UTC".
  3. Call _tzset to make your changes active.
  4. Call mktime.
  5. Restore the old value of TZ, then call _tzset again.
Josh Kelley
Yes, I got it. And how can I get the UTC date corresponding to 1970,1,1,0,0,0 in my timezone ?
digEmAll
@digEmAll: You just did. UTC time is constant it does not matter what time zone you are in. Local time (what struct tm holds) is always relative to the current time zone. If you mean how do I get it to return zero. Work out what time it was in your local when it was 00:00:00 on Jan 1/1970 at the Meridian (I assume that is where UTC is time from).
Martin York
@Martin: sorry, my previous comment was bad-written (I'm not english). I meant that if I could get (possibly with a function) the corresponding value of 1970/1/1 0:0:0 UTC in my timezone (i.e. 1970/1/1 1:0:0) mktime would return the correct value (i.e. 0)
digEmAll
Anyway, with Josh's solution now the code works, thanks :)
digEmAll