/* -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 */ /******************************************************************************* * c0xtimezone.c * Proposed ISO/IEC C (C0X) timezone types and functions. * * This source file implements several proposed timezone functions as a * proof of concept; most of the algorithms used are for illustration only * and are not meant for production-quality systems. * * Functions that are implemented: * _gettimezone() * * References * See . * * See also * c0xcalendar.c * c0xcalendar.h * *------------------------------------------------------------------------------- * History * 1.0, 2001-12-27, David R Tribble. * First attempt. * * 1.1, 2001-12-29, David R Tribble. * Minor changes. * * 1.2, 2002-01-17, David R Tribble. * Minor changes. * * 1.3, 2002-01-31, David R Tribble. * Changed member '_timezone.tz_sec_west' to '.tz_min_west'. * * 1.4, 2002-02-12, David R Tribble. * Renamed argument 'name' to 'tzname'. * Added "UTC" timezone. * * 1.5, 2002-02-13, David R Tribble. * Removed the '_gettimezonelist()' function. * * 1.6, 2002-02-17, David R Tribble. * Added an improved '_gettimezonelist()' function. * Removed 'xxx_vers' struct members and 'XXX_VERS' constants. * * 1.7, 2002-02-23, David R Tribble. * Added '_XXX_VS' version macros. * Added predefined "+hh00" timezone names. * Added '_mktimezonename()' function. *******************************************************************************/ /* Identification */ static const char rev[] = "@(#)$Header: c0xtimezone.c 1.7 2002-02-23 $"; /* Standard includes */ #include #include #include #include /* Local includes */ #include "c0xcalendar.h" /******************************************************************************* * Shared constants *******************************************************************************/ const struct _timezone _cal_zones[] = { #if _TIMEZONE_VS > 20020223 #error struct _timezone has changed #endif /* [0], UTC */ { "Coordinated Universal Time", /* tz_name */ "UTC", /* tz_abbr */ 0L, /* tz_min_west */ 0, /* tz_dst */ }, /* [1], GMT */ { "Greenwich Mean Time", /* tz_name */ "GMT", /* tz_abbr */ 0L, /* tz_min_west */ 0, /* tz_dst */ }, /* [2], AST */ { "US Atlantic Standard Time", /* tz_name */ "AST", /* tz_abbr */ (+4)*60, /* tz_min_west */ 0, /* tz_dst */ }, /* [3], ADT */ { "US Atlantic Daylight Time", /* tz_name */ "ADT", /* tz_abbr */ (+4-1)*60, /* tz_min_west */ 0, /* tz_dst */ }, /* [4], EST */ { "US Eastern Standard Time", /* tz_name */ "EST", /* tz_abbr */ (+5)*60, /* tz_min_west */ 0, /* tz_dst */ }, /* [5], EDT */ { "US Eastern Daylight Time", /* tz_name */ "EDT", /* tz_abbr */ (+5-1)*60, /* tz_min_west */ 1, /* tz_dst */ }, /* [6], CST */ { "US Central Standard Time", /* tz_name */ "CST", /* tz_abbr */ (+6)*60, /* tz_min_west */ 0, /* tz_dst */ }, /* [7], CDT */ { "US Central Daylight Time", /* tz_name */ "CDT", /* tz_abbr */ (+6-1)*60, /* tz_min_west */ 1, /* tz_dst */ }, /* [8], MST */ { "US Mountain Standard Time", /* tz_name */ "MST", /* tz_abbr */ (+7)*60, /* tz_min_west */ 0, /* tz_dst */ }, /* [9], MDT */ { "US Mountain Daylight Time", /* tz_name */ "MDT", /* tz_abbr */ (+7-1)*60, /* tz_min_west */ 1, /* tz_dst */ }, /* [10], PST */ { "US Pacific Standard Time", /* tz_name */ "PST", /* tz_abbr */ (+8)*60, /* tz_min_west */ 0, /* tz_dst */ }, /* [11], PDT */ { "US Pacific Daylight Time", /* tz_name */ "PDT", /* tz_abbr */ (+8-1)*60, /* tz_min_west */ 1, /* tz_dst */ }, }; /******************************************************************************* * Private types *******************************************************************************/ /*------------------------------------------------------------------------------ * struct TzLookup * Used to implement a lookup table for timezone names. */ struct TzLookup { const char * name; /* Timezone name */ const struct _timezone * tz0; /* TZ info without DST */ const struct _timezone * tz1; /* TZ info with DST */ }; /******************************************************************************* * Private constants *******************************************************************************/ static const char *const TZ_ENV = "TZ"; static const size_t nZones = sizeof(_cal_zones)/sizeof(_cal_zones[0]); /*------------------------------------------------------------------------------ * tz_lookup[] * Lookup table matching timezone names to their timezone info structs. */ static const struct TzLookup tz_lookup[] = { { "UTC", &_cal_zones[0], &_cal_zones[0] }, { "+0000", &_cal_zones[0], &_cal_zones[0] }, { "+0400", &_cal_zones[2], &_cal_zones[2] }, { "+0500", &_cal_zones[4], &_cal_zones[4] }, { "+0600", &_cal_zones[6], &_cal_zones[6] }, { "+0700", &_cal_zones[8], &_cal_zones[8] }, { "+0800", &_cal_zones[10], &_cal_zones[10] }, { "GMT", &_cal_zones[1], &_cal_zones[1] }, { "AST", &_cal_zones[2], &_cal_zones[2] }, { "AST4", &_cal_zones[2], &_cal_zones[2] }, { "AST4ADT", &_cal_zones[2], &_cal_zones[3] }, { "EST", &_cal_zones[4], &_cal_zones[4] }, { "EST5", &_cal_zones[4], &_cal_zones[4] }, { "EST5EDT", &_cal_zones[4], &_cal_zones[5] }, { "CST", &_cal_zones[6], &_cal_zones[6] }, { "CST6", &_cal_zones[6], &_cal_zones[6] }, { "CST6CDT", &_cal_zones[6], &_cal_zones[7] }, { "MST", &_cal_zones[8], &_cal_zones[8] }, { "MST7", &_cal_zones[8], &_cal_zones[8] }, { "MST7MDT", &_cal_zones[8], &_cal_zones[9] }, { "PST", &_cal_zones[10], &_cal_zones[10] }, { "PST8", &_cal_zones[10], &_cal_zones[10] }, { "PST8PDT", &_cal_zones[10], &_cal_zones[11] }, { NULL, NULL, NULL }, }; /******************************************************************************* * Public functions *******************************************************************************/ /*------------------------------------------------------------------------------ * _gettimezone() * Find a supported timezone with a name matching a given string. * * Parameter tz * A two-element array that is modified to point to the matching timezone * information; 'tz[0]' is modified to point to the matching timezone with * no DST in effect, and 'tz[1]' is modified to point to the matching * timezone with DST in effect. * * Parameter tzname * The name or abbreviated name of a timezone to find. If this is empty * ("") or null, the local timezone is used (as determined by the value of * the "TZ" environment variable). * * Returns * Zero on success, otherwise a nonzero value on error. */ int _gettimezone(const struct _timezone *tz[2], const char *tzname) { #if _TIMEZONE_VS > 20020223 #error struct _timezone has changed #endif int i; #if DEBUG printf("$ _gettimezone(tz=%08p, tzname=%08p=\"%.200s\")\n", tz, tzname, (tzname != NULL ? tzname : "")); #endif /* Check for local timezone request */ if (tzname == NULL or tzname[0] == '\0') { /* Use the local timezone */ tzname = getenv(TZ_ENV); if (tzname == NULL or tzname[0] == '\0') return (-1); } /* Search for a matching supported timezone name */ for (i = 0; tz_lookup[i].name != NULL; i++) { if (strcmp(tzname, tz_lookup[i].name) == 0) { /* Found a matching timezone */ tz[0] = tz_lookup[i].tz0; tz[1] = tz_lookup[i].tz1; return (0); } } /* No matching timezone name was found */ return (-1); } /*------------------------------------------------------------------------------ * _gettimezonelist() * Retrieve a list of supported timezones. * * Parameter tz * Pointer to an array of timezone pointers, which will be modified to * point to timezone objects specifying the supported timezones. This can * be null (see below). * * Parameter max * Specifies the maximum number of elements of array 'tz' to modify. * * Returns * If 'tz' is not null, up to 'max' elements of array 'tz' are modified and * the actual number of members is returned. If 'tz' is null, the number * of supported timezones is returned. */ size_t _gettimezonelist(const struct _timezone *tz[], size_t max) { #if _TIMEZONE_VS > 20020223 #error struct _timezone has changed #endif size_t i; #if DEBUG printf("$ _gettimezonelist(tz=%08p, max=%lu)\n", tz, (unsigned long)max); #endif /* Check args */ if (tz == NULL) return (nZones); /* Fill 'tz[]' with pointers to supported timezones */ for (i = 0; i < max and i < nZones; i++) tz[i] = &_cal_zones[i]; return (i); } /*------------------------------------------------------------------------------ * _mktimezonename() * Construct a timezone name given a pair of timezone objects. * * Parameter tz * A two-element array that specifies a pair of (DST and non-DST) timezone * objects. This array pointer and the two pointer elements of this array * cannot be null. * * Parameter buf * Points to a character array that will be filled with at most 'max' * characters, representing the constructed timezone name. This pointer * cannot be null. * * Parameter max * Specifies the maximum number of characters that will be placed into the * array pointed to by 'buf'. * * Returns * The number of characters written into the array pointed to by 'buf' on * success (which will not be greater than 'max'), or -1 if an error * occurs. */ int _mktimezonename(char *buf, size_t max, const struct _timezone *tz[2]) { #if _TIMEZONE_VS > 20020223 #error struct _timezone has changed #endif int i; int tzoff; char name[80]; #if DEBUG printf("$ _mktimezonename(buf=%08p, max=%lu, tz=%08p\n", buf, (unsigned long)max, tz); #endif /* Check args */ if (buf == NULL) return (-1); if (tz == NULL or tz[0] == NULL or tz[1] == NULL) return (-1); if (max == 0) return (0); /* Construct a name for the timezone pair */ tzoff = tz[0]->tz_min_west; i = 0; strcpy(name+i, tz[0]->tz_abbr); i = 3; if (tz[0] == tz[1] and tzoff%60 == 0) goto done; if (tzoff < 0) { name[i++] = '-'; tzoff = -tzoff; } if (tzoff/60 >= 10) name[i++] = tzoff/60 / 10 + '0'; name[i++] = tzoff/60 % 10 + '0'; tzoff %= 60; if (tzoff > 0) { name[i++] = tzoff/10 + '0'; name[i++] = tzoff%10 + '0'; } strcpy(name+i, tz[1]->tz_abbr); i += 3; name[i] = '\0'; done: /* Copy the constructed name into 'buf' */ strncpy(buf, name, max); buf[max-1] = '\0'; return (strlen(buf)); } /* End c0xtimezone.c */ /* -----BEGIN PGP SIGNATURE----- Version: PGPfreeware 7.0.3 for non-commercial use iQA/AwUBPHgXbnS9RCOKzj55EQL1xACfUtF2X1SSeJCrnnQwAq9BE3UFIgIAniem J1B35eBLvCDN06S7lMucBrpB =dZri -----END PGP SIGNATURE----- */