<<On Thu, 7 Jun 2001 12:09:33 -0400 (EDT), Jonathan Lennox <lennox@cs.columbia.edu> said:
Three functions manipulate a struct tz:
newtz -- create a time zone object
Poor choice of name. I believe that POSIX now requires any new interfaces to use namespace prefixes to avoid taking away more application namespace.
#include <time.h>
...probably a different header file should be used as well.
tzname is a pointer to a string representing the name of the allocated time zone.
Should allow a null pointer to represent whatever the default (as used in tzset()) would be.
It has one externally-visible element: tz_name,
A structure of this sort should be opaque. Define accessor functions, not the members of the structure. Unfortunately, POSIX is rather too fond of defining foo_t typedefs for things (like pointers to opaque structures) which should not be typedef'ed, so `struct tz' would probably get transmogrified by standards committees into `timezone_t' or some similar nonsense.
If tzname is NULL, the returned struct tz describes the local wall-clock time, as best as it is known by the local system.
Oops... Should reorder this description.
If tzname is the empty string "", the returned struct tz describes Coordinated Universal Time (UTC). (The POSIX rules also allow UTC to be represented with the string "GMT0".)
As I think about it, I think a better alternative would be parallel to how setlocale() works: If tzname is a null pointer, the return value shall represent Coordinated Universal Time (UTC). If tzname is a string of length zero, the return value shall represent the same timezone as is chosen by tzset().
This interface is designed so that newtz(getenv("TZ")) will return an object describing the default time zone object that non-thread-aware versions of the time functions will use by default, provided TZ (if set) is set to a valid time zone name.
I would suggest that requiring applications to check the ennvironment -- or even assuming that there is a meaningful environment, which there may not be in some profiles -- is probably a bad idea and potentially prone to error. (Consider: getenv("ZT") would be a common typo which would not be recognized by a compiler.)
#include <time.h> void freetz(struct tz* tzobj);
The same namespace comments apply here as well.
If the system defines the tm_zone field of struct tm, this function invalidates the strings pointed to by the tm_zone field of all struct tm values created by localtime_z called with this tzobj.
The result of accessing any freed memory is undefined, so such language is not necessary and would probably reduce standardizability.
#include <time.h> struct tz* duptz(const struct tz* tzobj);
I'm not sure how really useful this interface is. In many other places in C and POSIX we define opaque structures without any sort of ``duplicate'' mechanism, and leave the application to do reference counting if it so wishes. (Viz., the `FILE *' interfaces.)
struct tm * localtime_z(const time_t *clock, struct tm *result, const struct tz *tz);
Equivalent to localtime_r() or gmtime_r(), in the time zone represented by tz, except that tz->tz_name is not modified.
There doesn't seem to me to be any benefit in this restriction, and a program which is adopting this interface may well need to interact or be linked with libraries developed to the old interface. If you eliminate this restriction, then you no longer need to duplicate the strftime() interfacem, since the returned `struct tm' contains all the necessary information.
char * ctime_z(const time_t *clock, char *buf, const struct tz *tz);
char * asctime_z(const struct tm *tm, char *buf, const struct tz *tz);
As Joseph Myers pointed out, these interfaces are redundant with strftime() and an appropriate format specifier. Don't forget that for C99 you'll want to add an appropriate `restrict' qualifier or two.
Name tzuse -- use time zone object in current thread.
Synopsis #include <time.h> void tzuse(const struct tz *tz);
Rather than having a specific function, one might instead define a specific pre-instantiated key such that one can call `pthread_setspecific(PTHREAD_DEFAULT_TIMEZONE, tz)' with the consequences you describe. This makes it possible for the application to find out what the current timezone is, simply by calling `pthread_getspecific(PTHREAD_DEFAULT_TIMEZONE)'. You would need to specify what the thread-termination consequences are. -GAWollman