Create an account

Very important

  • To access the important data of the forums, you must be active in each forum and especially in the leaks and database leaks section, send data and after sending the data and activity, data and important content will be opened and visible for you.
  • You will only see chat messages from people who are at or below your level.
  • More than 500,000 database leaks and millions of account leaks are waiting for you, so access and view with more activity.
  • Many important data are inactive and inaccessible for you, so open them with activity. (This will be done automatically)


Thread Rating:
  • 250 Vote(s) - 3.5 Average
  • 1
  • 2
  • 3
  • 4
  • 5
localtime returns GMT for windows programs running on cygwin shells

#1
Consider the following code:

time_t t;
t = time( NULL );
elog << "timezone: " << getenv( "TZ" )
<< ", current local time: " << asctime( localtime( &t ));

If I build this code using MSVC, and run it under the windows DOS shell, I get the correct local time:

timezone: , current local time: Wed Jul 25 13:05:08 2012

But if I run the same program under a cygwin shell like bash, this code returns GMT!

timezone: America/New_York, current local time: Wed Jul 25 18:05:08 2012

If I run this program in Linux or OsX, it also returns the correct local time.

Why?


@Update: It is now a year later and I found that the answer I gave below does not always work.

It seems that for some programs unsetting TZ does not always work. I don't know why. But there is a cumbersome workaround. Basically, right after you unset TZ, you have to check that local time is indeed no longer returning GMT, but only if you aren't actually in the GMT time zone, and compute a manual adjustment to time_t's when you call localtime() or maketime()


u64 localTimeOffset = 0;

static void unsetTz()
{
static bool unsetTZ = false;
if ( !unsetTZ )
{
putenv( "TZ=" );
unsetTZ = true;

// unsetting TZ does not always work. So we have to check if it worked
// and make a manual adjustment if it does not. For long running programs
// that may span DST changes, this may cause the DST change to not take
// effect.
s32 tzOffset = getTzOffset();

if ( tzOffset )
{
static char timeBuf[48];
char* s = &(timeBuf[0]);
struct tm* timeInfoGMT;
struct tm* timeInfoLocal;

time_t zero = 86400;
timeInfoGMT = gmtime( &zero );
u32 GMTHour = timeInfoGMT->tm_hour;

timeInfoLocal = localtime( &zero );
u32 localHour = timeInfoLocal->tm_hour;

if ( localHour == GMTHour )
{
// unsetting tz failed. So we have to make a manual adjustment
localTimeOffset = tzOffset * 60 * 60;
}
}
}
}

s32 getTzOffset()
{
TIME_ZONE_INFORMATION tzInfo;
GetTimeZoneInformation( &tzInfo );
s32 tz = ( tzInfo.Bias / 60 );
return tz;
}

A call to local time:

time_t t = getAtTimeFromSomewhere();
t -= localTimeOffset;
timeInfo = localtime( &t );

A call to maketime:

struct tm timestr;
makeATMFromAStringForExample( time, timestr );
time_t timet = mktime( &timestr );
timet += localTimeOffset;

Good times.

Reply

#2
Try to set the <b>tm_isdst</b> flag in a struct tm.

The Daylight Saving Time flag (tm_isdst) is greater than zero if Daylight Saving Time is in effect, zero if Daylight Saving Time is not in effect, and less than zero if the information is not available.

If I remember well, in Windows it has to be -1 to work properly.
Reply

#3
This took me some time to figure out, and I'm hoping it will be useful to others.

POSIX functions like `localtime` will use the environment variable `TZ` to determine what timezone to use. If `TZ` is not set it will use the system's default timezone.

If I run under Linux or OS X, `TZ` is set correctly and everything works. If I run this program in the shell on Windows, `TZ` is not set, so the function returns the operating system's default timezone, which again produces correct results.

If I run in a Cygwin shell, `TZ` is set - but since I built the program using MSVC, using MSVC's own stdc library - it cannot interpret Cygwin's `TZ` variable. So it defaults to GMT.

Had the program been built with GCC under Cygwin I bet it would work correctly in Cygwin shells.

So the answer is to make sure in programs that call POSIX time functions like `localtime()`, if you want the time functions to work right under Cygwin shells you have to unset `TZ`.

I did it like so:

void getLocalTime()
{
#ifdef WIN32
static bool unsetTZ = false;
if ( !unsetTZ )
{
putenv( "TZ=" );
unsetTZ = true;
}
#endif // !WIN32

time_t t;
t = time( NULL );
elog << "timezone: " << getenv( "TZ" )
<< ", current local time: " << asctime( localtime( &t ));
}
Reply

#4
Use `export TZ=""` in Cygwin shell may be the best way.

@Update
Hi, Tunaki. Thank your edit!
Reply



Forum Jump:


Users browsing this thread:
1 Guest(s)

©0Day  2016 - 2023 | All Rights Reserved.  Made with    for the community. Connected through