NAME time_parse - parse free-format date/time string SYNOPSIS #include int time_parse(char *str, struct tmx *tmx, char **endptr); struct tmx { struct tm tm; /* See ctime(3) for definition */ struct tmz tmz; /* See time_lzone(3X) for definition */ char *tmx_err; /* NULL or pointer to error message */ int tmx_flags; /* Flags for possible future uses */ }; #define TMX_NULL (-1) /* Unspecified items are given this value */ DESCRIPTION time_parse() accepts a null-terminated date/time string, "str", and parses it to fill out the specified TMX structure, "tmx". If "endptr" is not null, it is always set to point to the remainder (if any) of the string not consumed by time_parse(). The "time_make()" function can be used to derive a UNIX time word of type "time_t" from the resulting TMX structure. The integer return value is used to help indicate overall success or failure. A negative value means that the parse stopped due to conflicting specifications or ambiguous keywords, which usually means an error; otherwise, the value is the number of non-break tokens successfully scanned, which may be 0. Whenever the parse did not reach the end of the string for whatever reason, the char pointer "tmx_err" will be non-NULL and will point to a short constant message string describing the reason. INPUT "time_parse()" is intended to parse all reasonable date and/or time formats, specifically including everything that the TOPS-20/TENEX IDTNC JSYS will accept. The function is actually much more flexible than this since it will tolerate most cases of arbitrarily ordered, delimited, and duplicated items; it makes use of contextual clues to heuristically determine the meaning of numerical tokens. The string is parsed into tokens which are either numbers or keywords, separated by punctuation break characters. Keywords may be in any case and need only have enough of the word to uniquely identify it. Whitespace serves to delimit tokens but is otherwise ignored. The parse will stop when it encounters a keyword which cannot be identified (unknown or ambiguous), or encounters a character that is not one of the valid date/time punctuation chars: "()-,/:." plus space and tab. It will also stop if the only plausible interpretation of a token leads to a clash with already parsed values. For maximum flexibility, the parsing is deliberately as forgiving as possible, and will accept ANY construct as long as it can make some sense out of it, regardless of how bizarre the string looks to a human. It is guaranteed to correctly parse all strings which are "well formatted", but it cannot be used to enforce a specific syntax and its interpretation of some inherently ambiguous strings may not be what the user expects. The following are examples of acceptable formats (most taken from the TOPS-20/TENEX documentation). They are shown as dates and times; a string may have only one of these, or it may have both in either order, and sometimes their tokens can intermingle. Dates Times 6-Feb-76 12:34:56 or 1234:56 or 123456 Feb-6-76 12:34 or 1234 Feb 6 76 16:30 or 1630 or 4:30pm Feb 6, 1976 1:23 or 123 or 0123 6 Feb 76 1:56AM 6.2.1976 1:56-EST or 1:56 EST or 0156AM EST 2/6/76 NOON 1976-02-06 12:00AM or 12 AM or 12-am or MIDNIGHT Wedn Febru 6 1976 5-STD or 0500-STANDARD 1976 We Fe 6 12:30-DAYLIGHT Combined: Fri Nov 13 13:08:02 PDT 1981 (output of ctime()) Monday, May 24, 1987 3:22:23am-PST (03:22:23) (output of T20 daytime) Wed 2 Dec 87 09:18:44 PST (RFC822 format) 10-Nov-52 12:34-CDT 2:25 AM, December 25, 2025 Tues-PDT,(1988)8PM..AugUS 8 Tu (free-format example) Note that any USA timezone abbreviation is allowed, plus GMT, UT, and whatever else has been added to the keyword table. DIAGNOSTICS To summarize all possible return situations: Value tmx_err **endptr Meaning < 0 set start of bad token Parse stopped due to clashing specs or ambiguous keyword. >= 0 NULL '\0' String was completely parsed. >= 0 set start of invalid token String was not completely parsed. (if isalpha(**endptr) is true, this is an unknown keyword) Return-value: The exact quantity expressed by a positive return value is not useful for most purposes; it represents the number of valid numerical or alpha (keyword) tokens that the scan parsed. This often but not always corresponds to the number of entries in "tmx" that were set. A zero return value always indicates that the scan halted before finding any such valid tokens, and nothing in the "tmx" structure was set. tmx_err: The "tmx_err" member of "tmx" will be NULL if the parse scanned the entire string, otherwise it will be set. Note that the setting of this variable, as well as the sign of the return value, does not necessarily reflect either success or failure; it is up to the application program to interpret the results. endptr: The "endptr" return value provides another way to see what terminated the scan, since it points to the first character of whatever token stopped it. This will be '\0' at the end of the string, and if **endptr is an alpha character then the token was an unidentified or ambiguous keyword. tmx: NOTE!! Although a "tm" structure is included in the "tmx" structure, the values it contains are not completely consistent with the way "tm" structures are used by the C library functions. There are two differences: (1) If a structure member was not specified by the date/time string, it is given the value TMX_NULL, defined in , which matches no valid value for any member. In particular the "tm.tm_yday" member will always be set to TMX_NULL since there is no standard convention for specifying it in a text string. (2) The "tm.tm_year" member is set to whatever year value the string specifies. This may be 87, or 1987, or any other number. This conflicts with the C library interpretation where 0 is the year 1900. In fact, time_parse() can be used to merely initialize a "tmx" structure, by invoking it like this: time_parse((char *)0, &tmx, (char *)0); The time_make() function can be used to completely canonicalize the structure so that the "tm" substructure is then acceptable to the standard C library functions. It is important to remember that time_parse() does not, in general, attempt to verify the correctness of the resulting "tmx" structure. Cross-checking is limited primarily to ensuring that duplicate specifications are identical, e.g. if the weekday is seen twice, it must have the same value or the parse fails. time_make() will perform the necessary content checking to derive a valid "time_t" time. SEE ALSO time_make(3X), time_lzone(3X), ctime(3), time(2) AUTHOR Ken Harrenstien, SRI International 415/859-6552 NAME time_make - derive a "time_t" time value from a parsed time SYNOPSIS #include time_t time_make(struct tmx *tmx); DESCRIPTION "time_make" can be considered the inverse of "localtime"; it takes a broken-down time description and returns a UNIX-format time value of type "time_t". Note that it works only on "tmx" structures, not "tm" structures. It is possible to have unspecified (TMX_NULL) values in the structure, which time_make() will attempt to default reasonably: Member Default value if unspecified tm.tm_year Current year. tm.tm_mon 0 (Jan) if year specified, else current month. tm.tm_mday 1 if month specified, else current mday. tm.tm_hour 0 tm.tm_min 0 tm.tm_sec 0 tmz.tm_secwest tmz.tm_minwest * 60 tmz.tm_minwest local timezone tm.tm_isdst 0 if timezone not local. If local, applies local DST algorithm. For example, "July 10" will default the year to its current value (e.g. 1987), and the time to 00:00:00. Just giving "1980" will produce "Jan 1, 1980 00:00:00". The timezone, which is specified by tmz.tm_secwest, defaults to tmz.tm_minwest*60 which in turn defaults to the local timezone. A value of 1 for either variable is interpreted as an explicit request to use the local timezone. If tm.tm_isdst is set to 0, daylight savings time (DST) is never applied. If set to 1 (to represent USA DST) then DST is always applied (by subtracting one hour). If not specified, no DST is applied unless the timezone is that of the local timezone, in which case DST is applied if appropriate (determined by consulting localtime()). The "tm.tm_yday" (day of year) entry is not used to compute the time unless neither the month nor day are specified. The "tm.tm_wday" (day of week) entry is never used. However, specifying either of these values will cause them to be checked, and time_make() will fail if the values conflict with the other date specifications. DIAGNOSTICS -1 is returned on failure, which is usually due to a parameter being out of range. A failure return will always set "tmx_err" in the tmx structure to point to a short constant error message. This variable is cleared to NULL for a successful return. SEE ALSO time_parse(3X), time_lzone(3X), ctime(3), time(2) AUTHOR Ken Harrenstien, SRI International 415/859-6552 NAME time_lzone - get local timezone information time_tzset - set local timezone information from system SYNOPSIS #include int time_lzone(struct tmz *tmz); int time_tzset(void); struct tmz { long tmz_secwest; /* Secs west of GMT (-12/+12 hrs) */ int tmz_minwest; /* Same, in mins. (tmz_secwest/60) */ int tmz_dsttype; /* DST type if any (0 = none, 1 = USA) */ char *tmz_name; /* Standard timezone name */ char *tmz_dname; /* DST timezone name (if any) */ }; DESCRIPTION "time_lzone()" fills out the structure pointed to. It does this by copying the contents of the static area indicated by time_tzset(), which it calls if necessary. "time_tzset()" attempts to get the local timezone information from the system or environment (this is system dependent) and uses this to set (or re-initialize) its static TMZ structure. If successful, a pointer to this structure is returned; if it could not be initialized, NULL is returned. It is not necessary to invoke this function explicitly unless the program has some reason to believe that the timezone may have changed during execution. SEE ALSO time_make(3X), time_parse(3X), ctime(3), time(2) BUGS Time zones are a big mess, especially on Unix where there are several incompatible (and unportable) methods of tracking them. These functions attempt to standardize the information more sensibly. AUTHOR Ken Harrenstien, SRI International 415/859-6552