Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!watmath!clyde!cbosgd!gatech!ut-sally!std-unix From: std-u...@ut-sally.UUCP (Moderator, John Quarterman) Newsgroups: mod.std.unix Subject: localtime(), ctime() and timezones Message-ID: <4347@ut-sally.UUCP> Date: Sat, 1-Mar-86 18:31:29 EST Article-I.D.: ut-sally.4347 Posted: Sat Mar 1 18:31:29 1986 Date-Received: Sun, 2-Mar-86 02:49:22 EST Organization: IEEE/P1003 Portable Operating System Environment Committee Lines: 190 Approved: j...@sally.UUCP Date: 02 Mar 86 05:47:32 +1100 (Sun) From: Robert Elz <munnari!...@SEISMO.CSS.GOV> It seems to me that this discussion is getting a bit overblown, as far as P1003 is concerned, it doesn't really seem to be as difficult or complex as some people are making out. So, I'm going to propose something that could be inserted into P1003 (with the obvious extra definitions that I'm going to leave out on the assumption that everyone knows what they are, like the definition of a "struct tm"). In some words of other, it would go like this (with hopefully a lot of cleaning up of the typography to get rid of quotes and things like that where I would really prefer to use italics or bold): Implementations shall provide the following functions: struct tm *gmttime(t) time_t *t; struct tm *localtime(t) time_t *t; int settz(p) char *p; char *asctime(tp) struct tm *tp; char *ctime(t) time_t *t; gmttime: converts the time_t "*t" to a "struct tm" representing the same time (in Universal Co-ordinated Time). (waffle about the returned value being in a static area, etc, goes here). localtime: converts the time_t "*t" to a "struct tm" representing the given time adjusted to represent some local time difference. "local time" will be specified by a call to "settz", if no such call has preceded the call to localtime(), localtime() will call "settz(getenv("TZ"));". Implementors should note that for any defined past time (from midnight January 1, 1970 until the time the call is made) the local time returned should be accurate (taking into account the effects of daylight saving, if any). For future times, the local time returned should be as likely to be accurate as current projections of future timezone rules and daylight saving time changes allow. settz: enables users to specify the local time conversion to be used by localtime. The string is an implementation specific representation of the timezone offset desired, with 2 special cases.. The null pointer (t == (char *)0) will always select the appropriate local time offset for the host executing the call. A null string (t != (char *)0 && *t == '\0') will select no local time transformations (making localtime() equivalent to gmttime()). Implementations should provide, and document, some mechanism to allow users to select another timezone. This mechanism is beyond the scope of the standard. Implementors should, if possible, allow users to define their own timezones, and not restrict them to use one of some standard set. If settz is called with an unrecognisable argument, the effect is implementation defined. (Users might expect any of three "reasonable"? actions could be taken here -- use GMT, use local time, or use local time in the area where the implementation was performed). settz returns 0 if the timezone selected could be obtained, and -1 otherwise. settz can be called as many times as needed, each call affects future calls of localtime, until another call to settz. acstime: returns a 25 character string representing the time specified by "*tp". The format of the string is ... (you all know it). ctime: is defined to be "asctime(localtime(t))". ................... Notes: this is (about) the right level of detail for the standard. There is no need to specify what the form of the argument to settz() is. This enables things like the Sys V "EST5EDT" string, and Arthur Olson's (elsie!ado) "localtime" "Eastern" etc, to all be used with impunity - the implementor gets to choose whatever is appropriate to him - just provided that he can satisfy the needs of his customers (implementors who provide no means of getting daylight saving right in the Southern hemisphere can probably expect not to sell many copies there - but that's their choice). In particular - this discourages programmers from writing programs which "know" what the local time should be - there's no reason at all why a program should ever need to do more than select GMT, host local time, or a user specified time zone. (nb: while localtime uses the TZ environment variable in cases where the program has made no call to settz(), there's nothing to stop a program getting the argument to settz() from anywhere it pleases, including from several different environment variables if it chooses, and needs to operate in several timezones, or from an external configuration file, or wherever is appropriate). This works for existing programs (in general) - localtime() performs the required call to settz() the first time it is called (directly or via ctime()). There's no need to worry about who sets TZ, if its not set, getenv("TZ") will return (char *)0 and settz() will then use the appropriate local time for the host. How settz() gets that information is an implementation matter. The security problems (people faking local time for programs that expect it to be host local time, by setting TZ before running the program) can easily solved by causing those (comparatively few) programs to do "settz((char *)0)" before their first call to localtime(). What's missing: So far here there is no mention of the "timezone name". None of the standard mechanisms is really adequate here. The V7 (and 4.xbsd) "timezone" function is clearly inadequate (although 4.2 bsd allows users to set the environment variable TZNAME to anything they like) since there can clearly be several possible names for the same offset, and "timezone" has no way to discover which one is wanted. Requiring the name to resice in the environment somewhere (Sys V) is also inadequate (there are too many problems about making sure it is set in all the right places). Arthur Olson's scheme causes "localtime" to set a global variable "tz_abbr" to the correct string name for the timezone just used. I can't think of any cases where anything more than this is needed, but it is less flexible then "timezone()" and it would require programs that currently call timezone() to have to be altered. (He also has his version of "ctime" (but not "asctime") include the timezone in its output - I doubt if that is feasible for P1003, too many existing programs know what every byte in the returned string from ctime() contains.) I solicit suggestions for what to do here - one might be to retain "timezone" but not require that it be capable of returning anything except the zone name corresponding to the last call of localtime() - then with ado's implementation it could simply ignore its arguments and return tz_abbr - I suspect that would satisfy all existing uses (and the ones it doesn't are quite likely not to work in general anyway). Opinions? There's also no discussion of how this relates to processes and images. Not because there's anything doubtful here, but just because the necessary words take a lot of space. (informally, "the first call to localtime" is intended to be "the first after the program is exec'd, ignoring any fork()'s it may have since performed, as long as there has been no subsequent exec). Getting this kind of thing right is essential for a standatds document, its not essential here. ................... A justification for all this ... Today, just about 2 1/2 hours ago (it's early on a Sun morning as I write this) the daylight saving rules changed in at least 2 Australian states (no-one really seems very sure of what happened, or really why). The politicians gave us less than a month's warning that it was coming (and the month was February, which isn't a long month...). If there's anyone who doesn't believe that some form of dynamic timezone setting is required, they're welcome to come to Australia and suffer our local politicians (this isn't the first time: a couple of years ago New South Wales decided to extend daylight saving for a month to try and save on power bills - the amount of notice given was about the same - at that time, at least one local site decided to scrap running on GMT and run on localtime (ala VMS) instead. They're still doing that, I think, and suffering because of it). I'm extremely grateful that Arthur Olson decided to try an implementation, and donate it to the community - he made the task of converting things here much easier than it otherwise would have been. His implementation meets the above specs (in fact, it inspired them...), and will work for all the contorted exampes that people have been proposing (multiple shifts in a year, multi-hour saving, even daylight wasting). But note - there's no need for the standard to require this generality, market pressures will do that - all the standard needs to do is supply a suitable interface. Arthur Olson's implementation proves that the above reccomendation is implementable (munnari is running his code, in libc, right now) and effecient enough. [ Your last sentence gives the reason that I've encouraged discussions of implementations in the newsgroup: it's good to know that a proposed standard is implementable and handles actual cases. But you're right, of course, that the P1003 standard doesn't need implementation details. -mod ] Jack Jansen's (mcvax!jack) somewhat similar, but slightly different scheme would probably work just as well. Bob Devine's (hao!asgb!devine) "I don't think its needed" attitude can also fit the standard - if he's right then he's probably going to have a very fast localtime() which will serve him well. If he's wrong, then he's not going to get many customers. That's good - the more the better - that gives us users (or us system implementors perhaps) a wide choice of methods. Robert Elz kre%munnari...@seismo.css.gov seismo!munnari!kre Volume-Number: Volume 5, Number 65
Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Posting-Version: version B 2.10.3 4.3bsd-beta 6/6/85; site ut-sally.UUCP Path: utzoo!decvax!bellcore!ulysses!mhuxr!mhuxt!mhuxv!akgua!akguc!codas! peora!pesnta!pyramid!ut-sally!std-unix From: std-u...@ut-sally.UUCP (Moderator, John Quarterman) Newsgroups: mod.std.unix Subject: Re: localtime(), ctime() and timezones Message-ID: <4381@ut-sally.UUCP> Date: Fri, 7-Mar-86 11:30:16 EST Article-I.D.: ut-sally.4381 Posted: Fri Mar 7 11:30:16 1986 Date-Received: Sat, 8-Mar-86 12:55:20 EST References: <4347@ut-sally.UUCP> Organization: IEEE/P1003 Portable Operating System Environment Committee Lines: 34 Approved: j...@sally.UUCP Date: 6 Mar 86 23:09:30 EST (Thu) From: floyd!opus...@SEISMO.CSS.GOV (Kenneth Almquist) Organization: Bell Labs, Holmdel, NJ I basicly agree with Robert Elz. A few comments: 1) I suggest adding an entry for the timezone name to the tm structure. Something like char tm_zone[6]; I expect that time zone names will not exceed 5 characters, although the size of this array need not be specified in the standard. I don't suggest making tm_zone a character pointer because if that were done any implementation would be complicated by the need to ensure that tm_zone was still valid after settz was called with a different time zone. 2) The routine name is gmtime, not gmttime. 3) Removing the explicit mention of a time zone directory from the standard means that there is no longer a way to find the offset of time zone that a time zone name represents. How about providing a routine to do this: long tzoffset(tzname) char *tzname; which takes a time zone name and returns the offset of that time zone in seconds with respect to GMT? Kenneth Almquist ihnp4!houxm!hropus!ka (official name) ihnp4!opus!ka (shorter path) Volume-Number: Volume 5, Number 67