🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Thread View: comp.unix.programmer
13 messages
13 total messages Started by Dan Kegel Mon, 17 Apr 2000 00:00
timezone macro for autoconf?
#3781
Author: Dan Kegel
Date: Mon, 17 Apr 2000 00:00
11 lines
1177 bytes
The Single Unix Standard, v2, defines timezone as
  extern int timezone;

So does Linux.  BSD, though, defines it as
  char *timezone(int zone, int dst);

Does anyone have a good autoconf macro for figuring out
how to get at the timezone offset (the extern int) portably?

Thanks,
Dan
Re: timezone macro for autoconf?
#3782
Author: Russ Allbery
Date: Mon, 17 Apr 2000 00:00
17 lines
1372 bytes
In gnu.utils.help, Dan Kegel <dank@alumni.caltech.edu> writes:

> The Single Unix Standard, v2, defines timezone as
>   extern int timezone;

> So does Linux.  BSD, though, defines it as
>   char *timezone(int zone, int dst);

> Does anyone have a good autoconf macro for figuring out
> how to get at the timezone offset (the extern int) portably?

No, but I need to write one for INN as well.  On a BSD system, you
generally want to get the timezone offset from the tm_gmtoff member of
struct tm; SysV doesn't have a tm_gmtoff member.

-- 
Russ Allbery (rra@stanford.edu)             <http://www.eyrie.org/~eagle/>
Re: timezone macro for autoconf?
#3783
Author: Paul Eggert
Date: Tue, 18 Apr 2000 00:00
35 lines
2403 bytes
Russ Allbery <rra@stanford.edu> writes:

>Dan Kegel <dank@alumni.caltech.edu> writes:

>> Does anyone have a good autoconf macro for figuring out
>> how to get at the timezone offset (the extern int) portably?

>No, but I need to write one for INN as well.

The most portable way to get the time zone offset is to invoke localtime
and gmtime on the same time_t value, and then compute the offset
yourself from the two broken-down times.  This works on any system that
conforms to either K&R C or to Standard C (either 1989 or 1999).  For a
code example, please see how glibc strftime.c implements %z in the case
where HAVE_TM_GMTOFF is zero, looking particularly at the tm_diff
function.

The 'timezone' variable is less accurate than the portable method, as
it assumes that the same standard time offset is in effect forever, so
it mishandles changes to the standard time zone offset (which
happened last month in Argentina, for example).

The portable method is a bit slow, unfortunately.  If you want extra
speed on systems that support a tm_gmtoff member of struct tm, then I
suggest looking at how, say, GNU fileutils defines HAVE_TM_GMTOFF.
However I should mention that the method for doing this will change in
the next autoconf release, where you'll be able to say something like this:

AC_CHECK_MEMBER(struct tm.tm_gmtoff,
  [AC_DEFINE(HAVE_TM_GMTOFF, 1,
     [Define if struct tm has the tm_gmtoff member.])],
     ,
     [#include <time.h>])

(I suspect that is more than you wanted to know about time zone offsets. :-)
Re: timezone macro for autoconf?
#3784
Author: Russ Allbery
Date: Tue, 18 Apr 2000 00:00
39 lines
2690 bytes
In gnu.utils.help, Paul Eggert <eggert@twinsun.com> writes:
> Russ Allbery <rra@stanford.edu> writes:
>> Dan Kegel <dank@alumni.caltech.edu> writes:

>>> Does anyone have a good autoconf macro for figuring out
>>> how to get at the timezone offset (the extern int) portably?

>> No, but I need to write one for INN as well.

> The most portable way to get the time zone offset is to invoke localtime
> and gmtime on the same time_t value, and then compute the offset
> yourself from the two broken-down times.  This works on any system that
> conforms to either K&R C or to Standard C (either 1989 or 1999).

Right.  This is what INN currently falls back to if struct tm doesn't have
the tm_gmtoff member.

> The 'timezone' variable is less accurate than the portable method, as it
> assumes that the same standard time offset is in effect forever, so it
> mishandles changes to the standard time zone offset (which happened last
> month in Argentina, for example).

Why does it assume that?  I must be missing something.  According to the
Solaris 2.6 man page for the time functions:

     The effects of tzset() are thus to change the values of the external
     variables timezone, altzone, daylight, and tzname.  The ctime(),
     localtime(), mktime(), and strftime() functions will also update
     these external variables as if they had called tzset() at the time
     specified by the time_t or struct tm value that they are converting.

so it seems to me that retrieving the value of timezone if tm_isdst is 0
or altzone if tm_isdst is 1 and daylight is positive, provided it is done
immediately after calling localtime(), would be as accurate as using
tm_gmtoff.  It's unfortunately not MT-Safe, but then localtime() isn't
MT-Safe in general anyway.

-- 
Russ Allbery (rra@stanford.edu)             <http://www.eyrie.org/~eagle/>
Re: timezone macro for autoconf?
#3785
Author: Dan Kegel
Date: Sun, 23 Apr 2000 00:00
118 lines
4545 bytes
Russ Allbery wrote:
> >>> Does anyone have a good autoconf macro for figuring out
> >>> how to get at the timezone offset (the extern int) portably?
> >> No, but I need to write one for INN as well.
> > The most portable way to get the time zone offset is to invoke localtime
> > and gmtime on the same time_t value, and then compute the offset
> > yourself from the two broken-down times.  This works on any system that
> > conforms to either K&R C or to Standard C (either 1989 or 1999).
> Right.  This is what INN currently falls back to if struct tm doesn't have
> the tm_gmtoff member.

PHP3 has a function gmmktime() which is the inverse of gmtime(),
i.e. it takes a struct tm * in GMT and returns a time_t.  
Boy, do I wish Unix had that function.

Here's the code PHP3 uses, by the way.  It relies on mktime()
setting the tm_gmtoff field in the structure the argument points to!
Note that that behavior doesn't seem to be specified in SUS, e.g.
http://www.opengroup.org/onlinepubs/007908799/xsh/mktime.html

I take it from the remarks above that INN does it this way
if tm_gmtoff is present?

- Dan

void _php3_mktime(INTERNAL_FUNCTION_PARAMETERS, int gm)
{
	pval *arguments[7];
	struct tm *ta;
	time_t t;
	int i, seconds, gmadjust=0, arg_count = ARG_COUNT(ht);

	if (arg_count > 7 || getParametersArray(ht, arg_count, arguments) == FAILURE) {
		WRONG_PARAM_COUNT;
	}
	/* convert supplied arguments to longs */
	for (i = 0; i < arg_count; i++) {
		convert_to_long(arguments[i]);
	}

	/* get the current time in seconds from epoch */
	t=time(NULL);
#if HAVE_TZSET
	tzset();
#endif
		ta = localtime(&t);

	/* Let the system decide later whether the time is
	   in daylight savings time or not. Unless the user
	   overrides this, of course. */
	ta->tm_isdst = -1;

	/* now we apply the specified parameters to the timestamp */
	switch(arg_count) {
	case 7:
		ta->tm_isdst = arguments[6]->value.lval;
		/* fall-through */
	case 6:
		ta->tm_year = arguments[5]->value.lval;
		if (ta->tm_year < 70)
			ta->tm_year += 100;
		else if (ta->tm_year > 1000)
			ta->tm_year -= 1900;
		/* fall-through */
	case 5:
		ta->tm_mday = arguments[4]->value.lval;
		/* fall-through */
	case 4:
		ta->tm_mon = arguments[3]->value.lval - 1;
		/* fall-through */
	case 3:
		ta->tm_sec = arguments[2]->value.lval;
		/* fall-through */
	case 2:
		ta->tm_min = arguments[1]->value.lval;
		/* fall-through */
	case 1:
		ta->tm_hour = arguments[0]->value.lval;
	case 0:
		break;
	}

	seconds =  mktime(ta);

	/* mktime(), which *does* modify the structure its argument points to,
	   very nicely just filled ta->tm_gmtoff with the right value for us to
	   use. So add it to seconds, if we want GMT. */
	if (gm) {
#if HAVE_TM_GMTOFF
		gmadjust = ta->tm_gmtoff;
#else
		gmadjust = timezone;
#endif
		seconds += gmadjust;
	}

	return_value->value.lval = seconds;
	return_value->type = IS_LONG;
}

/* {{{ proto int mktime(int hour, int min, int sec, int mon, int mday, int year)
   Get UNIX timestamp for a date */
void php3_mktime(INTERNAL_FUNCTION_PARAMETERS)
{
	_php3_mktime(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
}
/* }}} */

/* {{{ proto int gmmktime(int hour, int min, int sec, int mon, int mday, int year)
   Get UNIX timestamp for a GMT date */
void php3_gmmktime(INTERNAL_FUNCTION_PARAMETERS)
{
	_php3_mktime(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
}
/* }}} */

-- 
Entia non sunt multiplicanda praeter necessitatem.
Re: timezone macro for autoconf?
#3786
Author: Russ Allbery
Date: Sun, 23 Apr 2000 00:00
20 lines
1781 bytes
In gnu.utils.help, Dan Kegel <dank@alumni.caltech.edu> writes:

> Here's the code PHP3 uses, by the way.  It relies on mktime() setting
> the tm_gmtoff field in the structure the argument points to!  Note that
> that behavior doesn't seem to be specified in SUS, e.g.
> http://www.opengroup.org/onlinepubs/007908799/xsh/mktime.html

ISO C9x, which I was just reading earlier today, actually specifies a new
structure, struct tmx, which has additional standardized fields containing
the timezone information and a whole new set of functions for manipulating
it.

> I take it from the remarks above that INN does it this way if tm_gmtoff
> is present?

No, the code that you included uses timezone if tm_gmtoff isn't available.
INN falls back on calling localtime and gmtime and comparing them.

-- 
Russ Allbery (rra@stanford.edu)             <http://www.eyrie.org/~eagle/>
Re: timezone macro for autoconf?
#3787
Author: Dan Kegel
Date: Sun, 23 Apr 2000 00:00
21 lines
2013 bytes
Dan Kegel wrote:
> Russ Allbery wrote:
> > >>> Does anyone have a good autoconf macro for figuring out
> > >>> how to get at the timezone offset (the extern int) portably?
> > >> No, but I need to write one for INN as well.
> > > The most portable way to get the time zone offset is to invoke localtime
> > > and gmtime on the same time_t value, and then compute the offset
> > > yourself from the two broken-down times.  This works on any system that
> > > conforms to either K&R C or to Standard C (either 1989 or 1999).
> > Right.  This is what INN currently falls back to if struct tm doesn't have
> > the tm_gmtoff member.

Hey!  BSD has this neat timegm() function which is the inverse of gmtime().
glibc has it too, though it's undocumented.

Wish I'd noticed that sooner.  And why the heck isn't that in the Single Unix Spec (SUS)?
It sure would be handy.
- Dan

-- 
Entia non sunt multiplicanda praeter necessitatem.
Re: timezone macro for autoconf?
#3788
Author: Paul Eggert
Date: Mon, 24 Apr 2000 00:00
13 lines
1442 bytes
Dan Kegel <dank@alumni.caltech.edu> writes:

>PHP3 has a function gmmktime() which is the inverse of gmtime(),
>i.e. it takes a struct tm * in GMT and returns a time_t.  

Unfortunately, it's buggy.  It assumes that the sign of 'tm_gmtoff'
is the same as that of 'timezone', which is incorrect.  It may have
other bugs but that's the first one I found by inspection.

>Boy, do I wish Unix had that function.

It's an action item for the next C standard.
(Can you wait 10 years?  :-)
Re: timezone macro for autoconf?
#3789
Author: Paul Eggert
Date: Mon, 24 Apr 2000 00:00
21 lines
2021 bytes
Russ Allbery <rra@stanford.edu> writes:

>ISO C9x, which I was just reading earlier today, actually specifies a new
>structure, struct tmx,

struct tmx was in early drafts of ISO C9x, but the spec had a lot of
problems that were uncovered during review, and struct tmx was removed
before C99 became official.  struct tmx shouldn't be used in real code.

>the code that you included uses timezone if tm_gmtoff isn't available.
>INN falls back on calling localtime and gmtime and comparing them.

INN's method is more reliable.  The problem with the 'timezone' method
is that it assumes that standard time has a fixed UTC offset.  This
assumption is incorrect.  E.g. Argentina changed their standard-time
UTC offset last month.  Perhaps the PHP 'timezone' code with could be
fixed to work in most cases, but it's certainly not guaranteed to work
and I would suggest that it remove all references to 'timezone'.

I should point out that I helped to write and debug that part of the
INN code, so I'm not unbiased here.
Re: timezone macro for autoconf?
#3790
Author: Russ Allbery
Date: Mon, 24 Apr 2000 00:00
86 lines
5257 bytes
This is a bit of a digression, and parts of it have more to do with INN
than with the nominal subject of this thread.  In fact, I'll cc this
message to inn-workers@isc.org.  I think it's still on-topic for
comp.unix.programmer and comp.os.linux.development as part of a more
general discussion of programming style, and some of the specific
questions early on about timezones are still relevant to this thread.
Apologies for the rest of the digression.

In gnu.utils.help, Paul Eggert <eggert@twinsun.com> writes:
> Russ Allbery <rra@stanford.edu> writes:

>> ISO C9x, which I was just reading earlier today, actually specifies a
>> new structure, struct tmx,

> struct tmx was in early drafts of ISO C9x, but the spec had a lot of
> problems that were uncovered during review, and struct tmx was removed
> before C99 became official.  struct tmx shouldn't be used in real code.

*grumble*  I really wish they would make the C standard available for
free, or at least for a reasonable price.  I'd gladly purchase a paper
copy, but not for nearly $500.  If it were the price of a typical high-end
technical book, say $60-$80, I'd have a copy of the official standard by
now.

> INN's method is more reliable.  The problem with the 'timezone' method
> is that it assumes that standard time has a fixed UTC offset.  This
> assumption is incorrect.  E.g. Argentina changed their standard-time UTC
> offset last month.

Ah, I'm starting to understand.  So what you're saying is that code based
on timezone will fail if the definition (in terms of UTC offset) of the
local timezone has changed since the point at which the daemon was
started?

But if that's the case, wouldn't taking the difference between localtime
and gmtime also fail, given that the system timezone files likely haven't
been updated?  This also doesn't seem to me to be a common occurance, or
really worth the additional code complexity to work around.  Although I
suppose the code has to be there to handle systems without timezone
anyway.

I still feel like I'm missing something here, though.

> I should point out that I helped to write and debug that part of the INN
> code, so I'm not unbiased here.

I'm rather unsatisfied with how time is currently handled in INN primarily
because INN uses its own weird time structure internally rather than
either just time_t or a struct timeval.  It instead uses:

typedef struct _TIMEINFO {
    time_t      time;
    long        usec;
    long        tzone;
} TIMEINFO;

I have a bias when writing code to always, when possible, use the standard
structures and function names, and to put all the portability work into
supplying replacements for the standard ones if they aren't present, so
that the application code as much as possible can look like very standard
C and people don't have to keep hunting up structure definitions to
understand what's going on.

The tzone element of the above struct, which is filled out using the
algorithms we've been discussing on this thread, is currently used in
exactly three places in INN, once in inews to create the default Date
header (which should be done using strftime and some manipulation instead)
and in the parsing of the time argument to NEWGROUPS and NEWNEWS which is
presumed to be in local time unless the client says it's in GMT/UTC.

I'd rather see INN use time_t everywhere internally, or struct timeval if
more accuracy is needed, and use more specific parsing algorithms
specifically for the NEWGROUPS and NEWNEWS time arguments that turn them
into a time_t.  In that place, though, the time zone correction may still
be needed, which requires either tm_gmtoff (definitely the best solution)
or some other means of finding the delta between local time and UTC.

The *best* solution, of course, would be for all news clients to always
send NEWGROUPS and NEWNEWS times in UTC, since using the local time of the
*server* is inherently a flawed way of doing the correction anyway since
the client could be in a different time zone.  If that were done, then the
only place INN would have to worry about timezones at all would be in
parsedate.

-- 
Russ Allbery (rra@stanford.edu)             <http://www.eyrie.org/~eagle/>
Re: timezone macro for autoconf?
#3791
Author: Paul Eggert
Date: Tue, 25 Apr 2000 00:00
37 lines
2899 bytes
Russ Allbery <rra@stanford.edu> writes:

>So what you're saying is that code based
>on timezone will fail if the definition (in terms of UTC offset) of the
>local timezone has changed since the point at which the daemon was
>started?

No, that's another bug entirely (one that few daemons have fixed).

I was referring to the problem that different time stamps correspond to
different UTC offsets.  E.g. the value for 'timezone' for Portugal
today is 0, since Portugal's standard time is now the same as
Greenwich.  But from 1992 to 1996 Portugal had a standard time one hour
ahead of Greenwich.  So if 'timezone' contains the value zero (which is
correct for Portuguese time stamps today), time_t values between 1992
and 1996 won't be handled correctly in a Portuguese locale.

This problem doesn't occur when comparing the outputs of localtime and
gmtime, since their outputs can (and, in good implementations, do)
use standard-time UTC offsets that depend on the time stamp in question.

>I'm rather unsatisfied with how time is currently handled in INN primarily
>because INN uses its own weird time structure internally rather than
>either just time_t or a struct timeval.

No standard time structure will do.  Neither struct tm nor struct
timeval is guaranteed to contain a time zone.  And when the code was
written, struct timeval wasn't standardized (and it's still absent from
some hosts); time_t plus some other stuff was the only portable way to go.

These days the most "standard" way to write it would be to use struct
timespec, as it's standardized by POSIX.1 (struct timeval is not).
However, the standards are still mutating in this area -- the next C
standard after C99 might well have a new time type -- so personally I'd
just leave INN alone for now.

Your other points are well taken.
Re: timezone macro for autoconf?
#3792
Author: Russ Allbery
Date: Tue, 25 Apr 2000 00:00
40 lines
3039 bytes
In gnu.utils.help, Paul Eggert <eggert@twinsun.com> writes:

> I was referring to the problem that different time stamps correspond to
> different UTC offsets.  E.g. the value for 'timezone' for Portugal today
> is 0, since Portugal's standard time is now the same as Greenwich.  But
> from 1992 to 1996 Portugal had a standard time one hour ahead of
> Greenwich.  So if 'timezone' contains the value zero (which is correct
> for Portuguese time stamps today), time_t values between 1992 and 1996
> won't be handled correctly in a Portuguese locale.

Ah!  Thank you.  That makes sense.  I can see where that may well make a
difference.

> No standard time structure will do.  Neither struct tm nor struct
> timeval is guaranteed to contain a time zone.

True, but in checking into it, it turns out that INN very rarely actually
uses the timezone.  Getting that information in all of the places that INN
uses timestamps is therefore rather wasteful and pointless.

For a time that doesn't need an associated timezone, I think using time_t
or struct timeval is superior.  I'd really like to isolate the time zone
handling in INN to as few places as possible and just use UTC everywhere
else; I think it makes the code a lot easier to follow.

> And when the code was written, struct timeval wasn't standardized (and
> it's still absent from some hosts); time_t plus some other stuff was the
> only portable way to go.

> These days the most "standard" way to write it would be to use struct
> timespec, as it's standardized by POSIX.1 (struct timeval is not).

Hm.  Except that I can't figure out how to get a struct timespec on
Solaris or older Linux without just converting a struct timeval, and
gettimeofday() is available nearly everywhere these days and returns a
struct timeval.  Right now, struct timeval looks like the de facto
standard regardless of what the de jure standard says.

-- 
Russ Allbery (rra@stanford.edu)             <http://www.eyrie.org/~eagle/>
Re: timezone macro for autoconf?
#3793
Author: Paul Eggert
Date: Wed, 26 Apr 2000 00:00
25 lines
2188 bytes
Russ Allbery <rra@stanford.edu> writes:

>I'd really like to isolate the time zone
>handling in INN to as few places as possible and just use UTC everywhere
>else; I think it makes the code a lot easier to follow.

Sounds good to me.

>Right now, struct timeval looks like the de facto
>standard regardless of what the de jure standard says.

I disagree, because gettimeofday is a porting hassle in practice.
On some hosts, you must pass a second argument to gettimeofday,
which is either ignored or not (depending on the host).
On other hosts, you must pass only one argument to gettimeofday.
And some hosts don't have gettimeofday, or put it in some nonstandard place.
In Solaris, there are two versions of gettimeofday, one in libucb
and the other in libc, which can lead to linking hassles for those poor
misguided souls who still want to use libucb.

I don't bother with gettimeofday porting hassles any more.  If a host
has clock_gettime and if it succeeds then I use it; on older hosts I
fall back on 'time'.  This is easier to maintain, and yields more
precise results on modern hosts than gettimeofday would.  See the
source code to GNU make for an example of this approach.
Thread Navigation

This is a paginated view of messages in the thread with full content displayed inline.

Messages are displayed in chronological order, with the original post highlighted in green.

Use pagination controls to navigate through all messages in large threads.

Back to All Threads