The two TimeZones in one process. How to?

What is the easiest way of obtaining the UTC time and date in a process
running in the environment where the TZ is not UTC0?

I need both - having the TZ=MST-3MDT-4,M3.5.0/2,M10.5.0/3 in the
environment (the process must know the local time) and be able to get the
MJD (Modified Julian Date) in the same process.

All I could think of is spawning a sub-process with TZ=UTC0 in it’s
environment every time I need the current MJD (and the sub-process should
report it back somehow)…

Please advise.

Tony.

On Mon, 23 May 2005 02:26:54 +0400, Tony wrote:

What is the easiest way of obtaining the UTC time and date in a process
running in the environment where the TZ is not UTC0?

I need both - having the TZ=MST-3MDT-4,M3.5.0/2,M10.5.0/3 in the
environment (the process must know the local time) and be able to get the
MJD (Modified Julian Date) in the same process.

gmtime() gives you the time in UTC
localtime() gives you the time according to the TZ variable

If you need anything more fancy than that, then you can always change the
value of the TZ variable using setenv() before you call any of the time
library functions (of course that is a bit more tricky if you have a
multi-threaded application).

Rob Rutherford
Ruzz Technology

BE VERY CAREFUL when using setenv()/putenv(), there is a known memory
leak in the WATCOM Library. If you repeatedly set TZ (or any
envirenment var) in a process via setenv() you will eventually blow up
the heap and/or run out of memory on the machine.

What we have done is write our own fmt_local_time() function that does
local substitution of the TZ string in the (global) environ[] array, and
set our own time zone name if/when necessary. Modify as you see fit.
Note, dst is a flag meaning daylight savings time is supported for this
time zone (not that dst is in effect at “this” time). Also, we use an
internal format for time zone…

/*

  • ushort_t timezone Local timezone in ZZ[MM]D format.
  •                  ZZ = standard "westerly" offset from UTC (00-23).
    
  •                  MM = Deviation from "on-the-hour" UTC in minutes.
    
  •                  D  = 0/1 flag for dst is supported in this TZ
    

*/

char *fmt_local_time( ushort_t timezone, char *fmt, time_t *utc )
{
static char buf[80];

char *tz = NULL;
int i;
short dst,
zone,
mm;
char zn;
char tzn[2][8];
char *tznsav[2];
struct tm *tm;

/*
** Set new TZ environment variable, get local time, reset TZ
** Because there seems to be a bug in putenv() we’ll be doing a little
** fake out using ‘environ’
*/

dst = (timezone % 10) != 0;
zone = timezone / 10;

if ( zone > 99 ) {
mm = zone % 100;
zone = zone / 100;
} else {
mm = 0;
}

if ( zone > 23 || zone < 0 ) {
zone = 0;
} else
if ( zone > 11 ) {
zone = zone - 24;
}

switch( zone ) {
case 5: zn = ‘e’; break;
case 6: zn = ‘c’; break;
case 7: zn = ‘m’; break;
case 8: zn = ‘p’; break;
case 9: zn = ‘a’; break;
case 10: zn = ‘h’; break;
default: zn = ‘z’;
sprintf( tzn[0], “Z%+.2d%.2d”, -zone, mm );
sprintf( tzn[1], “Z%+.2d%.2d”, -(zone - 1), mm );
break;
}

if ( dst )
sprintf( buf, “TZ=%cst%d:%.2d%cdt%d:%.2d,M4.1.0/2,M10.5.0/2”
, zn, zone, mm, zn, zone-1, mm
);
else
sprintf( buf, “TZ=%cst%d:%.2d”, zn, zone, mm );

for ( i = 0; environ != NULL; i++ )
if ( memcmp( environ, “TZ=”, 3 ) == 0 ) {
tz = environ;
break;
}

if ( tz )
environ = buf;
else
putenv( buf );

tzset( );

tm = localtime( utc );

if ( zn == ‘z’ ) {
tznsav[0] = tzname[0];
tznsav[1] = tzname[1];
tzname[0] = tzn[0];
tzname[1] = tzn[1];
}

strftime( buf, 80, fmt, tm );

if ( tz )
environ = tz;

if ( zn == ‘z’ ) {
tzname[0] = tznsav[0];
tzname[1] = tznsav[1];
}

tzset( );

return( buf );
}
------------

-Rob


Robert Rutherford wrote:

On Mon, 23 May 2005 02:26:54 +0400, Tony wrote:


What is the easiest way of obtaining the UTC time and date in a process
running in the environment where the TZ is not UTC0?

I need both - having the TZ=MST-3MDT-4,M3.5.0/2,M10.5.0/3 in the
environment (the process must know the local time) and be able to get the
MJD (Modified Julian Date) in the same process.



gmtime() gives you the time in UTC
localtime() gives you the time according to the TZ variable

If you need anything more fancy than that, then you can always change the
value of the TZ variable using setenv() before you call any of the time
library functions (of course that is a bit more tricky if you have a
multi-threaded application).

Rob Rutherford
Ruzz Technology

On Mon, 23 May 2005 19:04:56 +0400, Rob Hem <rob@spamyourself.com> wrote:

BE VERY CAREFUL when using setenv()/putenv(), there is a known memory
leak in the WATCOM Library.
Thank you!

What the version of Watcom C this flaw is known against?
I’m on Watcom C v10.6B+SecPatch, is it affected as well?

This is how I calculate the MJD (Modfied Julian Date):

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

void
main()
{
time_t t0,t1,t2;
struct tm *tm;
struct tm MJD_ref; / 31 Jan 1982 is MJD 45000 */

tzset();

MJD_ref->tm_sec = 0; /* seconds after the minute – [0,61] /
MJD_ref->tm_min = 0; /
minutes after the hour – [0,59] /
MJD_ref->tm_hour = 0; /
hours after midnight – [0,23] /
MJD_ref->tm_mday = 31; /
day of the month – [1,31] /
MJD_ref->tm_mon = 0; /
months since January – [0,11] /
MJD_ref->tm_year = 82; /
years since 1900 /
MJD_ref->tm_wday = 0; /
days since Sunday – [0,6] /
MJD_ref->tm_yday = 0; /
days since January 1 – [0,365]/
MJD_ref->tm_isdst = -1; /
Daylight Savings Time flag */
t0 = mktime(MJD_ref);
printf( “Reference point is: %s\n”, asctime(MJD_ref) );

(void)time(&t1); /* store current UTC calendar time into t1 /
tm = gmtime(&t1); /
convert it into structure as UTC still */

tm->tm_isdst = -1; /* let OS determine if it is DST in action /
t2 = mktime™; /
convert the structure into LOCAL timezone as t2 */

printf( “Current UTC: %s”, asctime™);
printf( “LOCAL-UTC: %u seconds\n”, (int)difftime(t1, t2) );

printf( “Current MJD: %u\n”, (int)difftime(t1, t0)/(606024) + 45000 );
}


I hope this code copes with the leap-years properly…

Tony.

t0 = mktime(MJD_ref);
printf( “Reference point is: %s\n”, asctime(MJD_ref) );
Oops!

Not exactly what I wanted.
I need to obtain t0 as UTC time, and mktime() stores it through my TZ.
How to pack an arbitrary structure as if it were UTC no matter what was my
TZ?
A sort of “mkgmtime()”…

Tony.

On Mon, 23 May 2005 10:04:56 -0500, Rob Hem wrote:

BE VERY CAREFUL when using setenv()/putenv(), there is a known memory
leak in the WATCOM Library. If you repeatedly set TZ (or any
envirenment var) in a process via setenv() you will eventually blow up
the heap and/or run out of memory on the machine.

True, I should have remembered that. As an alternative to Rob’s code, here
is our code to do push and pop and the TZ variable. Similar concept,
slightly different approach.

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

  • TZ save/restore utilities

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

  • There is a bug in setenv where if the string length increases then
  • new space is malloc’ed but the old is never freed. This is a terrible
  • memory leak.
  • Workaround is to directly hack the env var table.
    */
    static char **default_tz_ptr = NULL;
    static char *default_tz_val = NULL;

void push_tz( const char *new_tz ) {

int i;

// Loop through environment table until we find a TZ
for ( i = 0; environ != NULL; i++ ) {
if ( memcmp( environ, “TZ=”, 3) == 0 ) {
default_tz_ptr = &(environ);
default_tz_val = environ;
environ = (char *)new_tz;
return;
}
}

// None found, create one set to the default
putenv( “TZ=EST5EDT” );

// Recurse to set to UTC value
push_tz( new_tz );
}
void pop_tz( void ) {

if ( default_tz_ptr ) {
*default_tz_ptr = default_tz_val;
}
}

Another workaround that I have found is to always putenv() with the same
size string as previous.

Not sure how to do this with the TZ variable, but perhaps simply padding
with spaces?? or the like will result in not re-allocating memory.

I found this many years ago, and the fix (for me) was to always use the same
size string.

HTH

Jeff.


“Robert Rutherford” <mail@NoSpamPlease.ruzz.com> wrote in message
news:1kvorfv12w5f6$.1i25t2oz91pbb.dlg@40tude.net

On Mon, 23 May 2005 10:04:56 -0500, Rob Hem wrote:

BE VERY CAREFUL when using setenv()/putenv(), there is a known memory
leak in the WATCOM Library. If you repeatedly set TZ (or any
envirenment var) in a process via setenv() you will eventually blow up
the heap and/or run out of memory on the machine.


True, I should have remembered that. As an alternative to Rob’s code, here
is our code to do push and pop and the TZ variable. Similar concept,
slightly different approach.

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

  • TZ save/restore utilities

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

  • There is a bug in setenv where if the string length increases then
  • new space is malloc’ed but the old is never freed. This is a terrible
  • memory leak.
  • Workaround is to directly hack the env var table.
    */
    static char **default_tz_ptr = NULL;
    static char *default_tz_val = NULL;

void push_tz( const char *new_tz ) {

int i;

// Loop through environment table until we find a TZ
for ( i = 0; environ > != NULL; i++ ) {
if ( memcmp( environ> , “TZ=”, 3) == 0 ) {
default_tz_ptr = &(environ> );
default_tz_val = environ> ;
environ > = (char *)new_tz;
return;
}
}

// None found, create one set to the default
putenv( “TZ=EST5EDT” );

// Recurse to set to UTC value
push_tz( new_tz );
}
void pop_tz( void ) {

if ( default_tz_ptr ) {
*default_tz_ptr = default_tz_val;
}
}