Avatar of azami
azami
Flag for Japan asked on

Getting GMT time into a CTime

When our server passes time/date values to clients, it does so in a formatted string representing the time in GMT (UTC).  It's easy to get UTC from a CTime object with FormatGmt(), but there does not seem to be a way to put UTC back into another CTime object after we parse that string.  Any time that I give to CTime seems to be interpreted as local time.

A clumbsy workaround is to store the original values of _timezone and _daylight (global variables in C runtime), set them to 0, construct my CTime object, then restore the variables.  This works, but is ugly and obviously not threadsafe.

Can anyone offer a better alternative?

In short, I'm looking for a function like:

CTime GetCTimeFromGmt(int year, int month, int day, int hour, int minute, int second)
{
}

where the passed parameters are relative to GMT.  The function must be thread safe.

Thanks,
Matthew
System Programming

Avatar of undefined
Last Comment
azami

8/22/2022 - Mon
ASKER CERTIFIED SOLUTION
migel

THIS SOLUTION ONLY AVAILABLE TO MEMBERS.
View this solution by signing up for a free trial.
Members can start a 7-Day free trial and enjoy unlimited access to the platform.
See Pricing Options
Start Free Trial
GET A PERSONALIZED SOLUTION
Ask your own question & get feedback from real experts
Find out why thousands trust the EE community with their toughest problems.
azami

ASKER
The ripple effect when we cross a day boundary (need to see if the day is right, and the month, and the year...)  Seems a bit much.  But this seems to work:

CTime GetCTimeFromGmt(int year, int month, int day, int hour, int minute, int second)
{
     struct tm gmt_struct;
     gmt_struct.tm_sec = second;
     gmt_struct.tm_min = minute;
     gmt_struct.tm_hour = hour;
     ASSERT(day >= 1 && day <= 31);
     gmt_struct.tm_mday = day;
     ASSERT(month >= 1 && month <= 12);
     gmt_struct.tm_mon = month - 1;        // tm_mon is 0 based
     ASSERT(year >= 1900);
     gmt_struct.tm_year = year - 1900;     // tm_year is 1900 based
     gmt_struct.tm_isdst = -1; //DST is unknown
     
     time_t gmt_tt = mktime(&gmt_struct);
     
     // convert to gmt as though it was local time to get the offset
     struct tm *reversed_offset_struct = gmtime( &gmt_tt );
     time_t reversed_offset_tt = mktime(reversed_offset_struct);

     time_t offset = reversed_offset_tt - gmt_tt;

     time_t local_tt = gmt_tt - offset;

     return CTime(local_tt);
}

My only concern now is the thread safety of gmtime(), which uses a static buffer.  I think the MT CRT solves this, but I haven't been able to confirm one way or another.

I have to admit that I'm a bit surprised that neither CTime nor the C runtime offer a way to use GMT time as input!

Thanks for your help Migel.  I want to give this a few days to see whether anyone can comment on the thread safety before I accept your answer.

-Matthew
azami

ASKER
The ripple effect when we cross a day boundary (need to see if the day is right, and the month, and the year...)  Seems a bit much.  But this seems to work:

CTime GetCTimeFromGmt(int year, int month, int day, int hour, int minute, int second)
{
     struct tm gmt_struct;
     gmt_struct.tm_sec = second;
     gmt_struct.tm_min = minute;
     gmt_struct.tm_hour = hour;
     ASSERT(day >= 1 && day <= 31);
     gmt_struct.tm_mday = day;
     ASSERT(month >= 1 && month <= 12);
     gmt_struct.tm_mon = month - 1;        // tm_mon is 0 based
     ASSERT(year >= 1900);
     gmt_struct.tm_year = year - 1900;     // tm_year is 1900 based
     gmt_struct.tm_isdst = -1; //DST is unknown
     
     time_t gmt_tt = mktime(&gmt_struct);
     
     // convert to gmt as though it was local time to get the offset
     struct tm *reversed_offset_struct = gmtime( &gmt_tt );
     time_t reversed_offset_tt = mktime(reversed_offset_struct);

     time_t offset = reversed_offset_tt - gmt_tt;

     time_t local_tt = gmt_tt - offset;

     return CTime(local_tt);
}

My only concern now is the thread safety of gmtime(), which uses a static buffer.  I think the MT CRT solves this, but I haven't been able to confirm one way or another.

I have to admit that I'm a bit surprised that neither CTime nor the C runtime offer a way to use GMT time as input!

Thanks for your help Migel.  I want to give this a few days to see whether anyone can comment on the thread safety before I accept your answer.

-Matthew
migel

Hi!
IMHO all CRT routimes must be thread safe!
look at CRT source gmtime.c (...\Program Files\Microsoft Visual Studio\VC98\CRT\SRC\) and you founs that it isn`t exception from mainstream :-)
I started with Experts Exchange in 2004 and it's been a mainstay of my professional computing life since. It helped me launch a career as a programmer / Oracle data analyst
William Peck
azami

ASKER
I finally got around to installing the CRT source code to check.  I agree that the CRT _should_ be thread-safe, but unfortunately, not all of it is.  Fortunately, gmtime's buffer _is_ threadsafe, so the code (with my modifications) should work until the Y2.038K bug strikes.  BTW, _timezone and _daylight are among the globals that do not seem to have the thread-safety harness, so my original code that temporarily changed those (see question) was NOT threadsafe.