xref: /plan9/sys/src/cmd/seconds.c (revision 6084a089d07240b0be60cd120ef40fa169c93cdf)
181bcec06SDavid du Colombier /*
281bcec06SDavid du Colombier  * seconds absolute_date ... - convert absolute_date to seconds since epoch
381bcec06SDavid du Colombier  */
481bcec06SDavid du Colombier 
581bcec06SDavid du Colombier #include <u.h>
681bcec06SDavid du Colombier #include <libc.h>
781bcec06SDavid du Colombier #include <ctype.h>
881bcec06SDavid du Colombier 
981bcec06SDavid du Colombier typedef ulong Time;
1081bcec06SDavid du Colombier 
1181bcec06SDavid du Colombier enum {
1281bcec06SDavid du Colombier 	AM, PM, HR24,
1381bcec06SDavid du Colombier 
1481bcec06SDavid du Colombier 	/* token types */
1581bcec06SDavid du Colombier 	Month = 1,
1681bcec06SDavid du Colombier 	Year,
1781bcec06SDavid du Colombier 	Day,
1881bcec06SDavid du Colombier 	Timetok,
1981bcec06SDavid du Colombier 	Tz,
2081bcec06SDavid du Colombier 	Dtz,
2181bcec06SDavid du Colombier 	Ignore,
2281bcec06SDavid du Colombier 	Ampm,
2381bcec06SDavid du Colombier 
2481bcec06SDavid du Colombier 	Maxtok		= 6, /* only this many chars are stored in datetktbl */
2581bcec06SDavid du Colombier 	Maxdateflds	= 25,
2681bcec06SDavid du Colombier };
2781bcec06SDavid du Colombier 
2881bcec06SDavid du Colombier /*
2981bcec06SDavid du Colombier  * macros for squeezing values into low 7 bits of "value".
3081bcec06SDavid du Colombier  * all timezones we care about are divisible by 10, and the largest value
3181bcec06SDavid du Colombier  * (780) when divided is 78.
3281bcec06SDavid du Colombier  */
3381bcec06SDavid du Colombier #define TOVAL(tp, v)	((tp)->value = (v) / 10)
3481bcec06SDavid du Colombier #define FROMVAL(tp)	((tp)->value * 10)	/* uncompress */
3581bcec06SDavid du Colombier 
3681bcec06SDavid du Colombier /* keep this struct small since we have an array of them */
3781bcec06SDavid du Colombier typedef struct {
3881bcec06SDavid du Colombier 	char	token[Maxtok];
3981bcec06SDavid du Colombier 	char	type;
4081bcec06SDavid du Colombier 	schar	value;
4181bcec06SDavid du Colombier } Datetok;
4281bcec06SDavid du Colombier 
4381bcec06SDavid du Colombier int dtok_numparsed;
4481bcec06SDavid du Colombier 
4581bcec06SDavid du Colombier /* forwards */
4681bcec06SDavid du Colombier Datetok	*datetoktype(char *s, int *bigvalp);
4781bcec06SDavid du Colombier 
4881bcec06SDavid du Colombier static Datetok datetktbl[];
4981bcec06SDavid du Colombier static unsigned szdatetktbl;
5081bcec06SDavid du Colombier 
5181bcec06SDavid du Colombier /* parse 1- or 2-digit number, advance *cpp past it */
5281bcec06SDavid du Colombier static int
eatnum(char ** cpp)5381bcec06SDavid du Colombier eatnum(char **cpp)
5481bcec06SDavid du Colombier {
5581bcec06SDavid du Colombier 	int c, x;
5681bcec06SDavid du Colombier 	char *cp;
5781bcec06SDavid du Colombier 
5881bcec06SDavid du Colombier 	cp = *cpp;
5981bcec06SDavid du Colombier 	c = *cp;
6081bcec06SDavid du Colombier 	if (!isascii(c) || !isdigit(c))
6181bcec06SDavid du Colombier 		return -1;
6281bcec06SDavid du Colombier 	x = c - '0';
6381bcec06SDavid du Colombier 
6481bcec06SDavid du Colombier 	c = *++cp;
6581bcec06SDavid du Colombier 	if (isascii(c) && isdigit(c)) {
6681bcec06SDavid du Colombier 		x = 10*x + c - '0';
6781bcec06SDavid du Colombier 		cp++;
6881bcec06SDavid du Colombier 	}
6981bcec06SDavid du Colombier 	*cpp = cp;
7081bcec06SDavid du Colombier 	return x;
7181bcec06SDavid du Colombier }
7281bcec06SDavid du Colombier 
7381bcec06SDavid du Colombier /* return -1 on failure */
7481bcec06SDavid du Colombier int
parsetime(char * time,Tm * tm)7581bcec06SDavid du Colombier parsetime(char *time, Tm *tm)
7681bcec06SDavid du Colombier {
7781bcec06SDavid du Colombier 	tm->hour = eatnum(&time);
7881bcec06SDavid du Colombier 	if (tm->hour == -1 || *time++ != ':')
7981bcec06SDavid du Colombier 		return -1;			/* only hour; too short */
8081bcec06SDavid du Colombier 
8181bcec06SDavid du Colombier 	tm->min = eatnum(&time);
8281bcec06SDavid du Colombier 	if (tm->min == -1)
8381bcec06SDavid du Colombier 		return -1;
8481bcec06SDavid du Colombier 	if (*time++ != ':') {
8581bcec06SDavid du Colombier 		tm->sec = 0;
8681bcec06SDavid du Colombier 		return 0;			/* no seconds; okay */
8781bcec06SDavid du Colombier 	}
8881bcec06SDavid du Colombier 
8981bcec06SDavid du Colombier 	tm->sec = eatnum(&time);
9081bcec06SDavid du Colombier 	if (tm->sec == -1)
9181bcec06SDavid du Colombier 		return -1;
9281bcec06SDavid du Colombier 
9381bcec06SDavid du Colombier 	/* this may be considered too strict.  garbage at end of time? */
9481bcec06SDavid du Colombier 	return *time == '\0' || isascii(*time) && isspace(*time)? 0: -1;
9581bcec06SDavid du Colombier }
9681bcec06SDavid du Colombier 
9781bcec06SDavid du Colombier /*
9881bcec06SDavid du Colombier  * try to parse pre-split timestr in fields as an absolute date
9981bcec06SDavid du Colombier  */
10081bcec06SDavid du Colombier int
tryabsdate(char ** fields,int nf,Tm * now,Tm * tm)10181bcec06SDavid du Colombier tryabsdate(char **fields, int nf, Tm *now, Tm *tm)
10281bcec06SDavid du Colombier {
10381bcec06SDavid du Colombier 	int i, mer = HR24, bigval = -1;
10481bcec06SDavid du Colombier 	long flg = 0, ty;
10581bcec06SDavid du Colombier 	char *p;
10681bcec06SDavid du Colombier 	Datetok *tp;
10781bcec06SDavid du Colombier 
10881bcec06SDavid du Colombier 	now = localtime(time(0));	/* default to local time (zone) */
10981bcec06SDavid du Colombier 	tm->tzoff = now->tzoff;
110*6084a089SDavid du Colombier 	strncpy(tm->zone, now->zone, sizeof tm->zone - 1);
111*6084a089SDavid du Colombier 	tm->zone[sizeof tm->zone - 1] = '\0';
11281bcec06SDavid du Colombier 
11381bcec06SDavid du Colombier 	tm->mday = tm->mon = tm->year = -1;	/* mandatory */
11481bcec06SDavid du Colombier 	tm->hour = tm->min = tm->sec = 0;
11581bcec06SDavid du Colombier 	dtok_numparsed = 0;
11681bcec06SDavid du Colombier 
11781bcec06SDavid du Colombier 	for (i = 0; i < nf; i++) {
11881bcec06SDavid du Colombier 		if (fields[i][0] == '\0')
11981bcec06SDavid du Colombier 			continue;
12081bcec06SDavid du Colombier 		tp = datetoktype(fields[i], &bigval);
12181bcec06SDavid du Colombier 		ty = (1L << tp->type) & ~(1L << Ignore);
12281bcec06SDavid du Colombier 		if (flg & ty)
12381bcec06SDavid du Colombier 			return -1;		/* repeated type */
12481bcec06SDavid du Colombier 		flg |= ty;
12581bcec06SDavid du Colombier 		switch (tp->type) {
12681bcec06SDavid du Colombier 		case Year:
12781bcec06SDavid du Colombier 			tm->year = bigval;
12881bcec06SDavid du Colombier 			if (tm->year < 1970 || tm->year > 2106)
12981bcec06SDavid du Colombier 				return -1;	/* can't represent in ulong */
13081bcec06SDavid du Colombier 			/* convert 4-digit year to 1900 origin */
13181bcec06SDavid du Colombier 			if (tm->year >= 1900)
13281bcec06SDavid du Colombier 				tm->year -= 1900;
13381bcec06SDavid du Colombier 			break;
13481bcec06SDavid du Colombier 		case Day:
13581bcec06SDavid du Colombier 			tm->mday = bigval;
13681bcec06SDavid du Colombier 			break;
13781bcec06SDavid du Colombier 		case Month:
13881bcec06SDavid du Colombier 			tm->mon = tp->value - 1; /* convert to zero-origin */
13981bcec06SDavid du Colombier 			break;
14081bcec06SDavid du Colombier 		case Timetok:
14181bcec06SDavid du Colombier 			if (parsetime(fields[i], tm) < 0)
14281bcec06SDavid du Colombier 				return -1;
14381bcec06SDavid du Colombier 			break;
14481bcec06SDavid du Colombier 		case Dtz:
14581bcec06SDavid du Colombier 		case Tz:
14681bcec06SDavid du Colombier 			tm->tzoff = FROMVAL(tp);
14781bcec06SDavid du Colombier 			/* tm2sec needs the name in upper case */
148*6084a089SDavid du Colombier 			strncpy(tm->zone, fields[i], sizeof tm->zone - 1);
149*6084a089SDavid du Colombier 			tm->zone[sizeof tm->zone - 1] = '\0';
150*6084a089SDavid du Colombier 			for (p = tm->zone; *p; p++)
15181bcec06SDavid du Colombier 				if (isascii(*p) && islower(*p))
15281bcec06SDavid du Colombier 					*p = toupper(*p);
15381bcec06SDavid du Colombier 			break;
15481bcec06SDavid du Colombier 		case Ignore:
15581bcec06SDavid du Colombier 			break;
15681bcec06SDavid du Colombier 		case Ampm:
15781bcec06SDavid du Colombier 			mer = tp->value;
15881bcec06SDavid du Colombier 			break;
15981bcec06SDavid du Colombier 		default:
16081bcec06SDavid du Colombier 			return -1;	/* bad token type: CANTHAPPEN */
16181bcec06SDavid du Colombier 		}
16281bcec06SDavid du Colombier 	}
16381bcec06SDavid du Colombier 	if (tm->year == -1 || tm->mon == -1 || tm->mday == -1)
16481bcec06SDavid du Colombier 		return -1;		/* missing component */
16581bcec06SDavid du Colombier 	if (mer == PM)
16681bcec06SDavid du Colombier 		tm->hour += 12;
16781bcec06SDavid du Colombier 	return 0;
16881bcec06SDavid du Colombier }
16981bcec06SDavid du Colombier 
17081bcec06SDavid du Colombier int
prsabsdate(char * timestr,Tm * now,Tm * tm)17181bcec06SDavid du Colombier prsabsdate(char *timestr, Tm *now, Tm *tm)
17281bcec06SDavid du Colombier {
17381bcec06SDavid du Colombier 	int nf;
17481bcec06SDavid du Colombier 	char *fields[Maxdateflds];
17581bcec06SDavid du Colombier 	static char delims[] = "- \t\n/,";
17681bcec06SDavid du Colombier 
17781bcec06SDavid du Colombier 	nf = gettokens(timestr, fields, nelem(fields), delims+1);
17881bcec06SDavid du Colombier 	if (nf > nelem(fields))
17981bcec06SDavid du Colombier 		return -1;
18081bcec06SDavid du Colombier 	if (tryabsdate(fields, nf, now, tm) < 0) {
18181bcec06SDavid du Colombier 		char *p = timestr;
18281bcec06SDavid du Colombier 
18381bcec06SDavid du Colombier 		/*
18481bcec06SDavid du Colombier 		 * could be a DEC-date; glue it all back together, split it
18581bcec06SDavid du Colombier 		 * with dash as a delimiter and try again.  Yes, this is a
18681bcec06SDavid du Colombier 		 * hack, but so are DEC-dates.
18781bcec06SDavid du Colombier 		 */
18881bcec06SDavid du Colombier 		while (--nf > 0) {
18981bcec06SDavid du Colombier 			while (*p++ != '\0')
19081bcec06SDavid du Colombier 				;
19181bcec06SDavid du Colombier 			p[-1] = ' ';
19281bcec06SDavid du Colombier 		}
19381bcec06SDavid du Colombier 		nf = gettokens(timestr, fields, nelem(fields), delims);
19481bcec06SDavid du Colombier 		if (nf > nelem(fields) || tryabsdate(fields, nf, now, tm) < 0)
19581bcec06SDavid du Colombier 			return -1;
19681bcec06SDavid du Colombier 	}
19781bcec06SDavid du Colombier 	return 0;
19881bcec06SDavid du Colombier }
19981bcec06SDavid du Colombier 
20081bcec06SDavid du Colombier int
validtm(Tm * tm)20181bcec06SDavid du Colombier validtm(Tm *tm)
20281bcec06SDavid du Colombier {
20381bcec06SDavid du Colombier 	if (tm->year < 0 || tm->mon < 0 || tm->mon > 11 ||
20481bcec06SDavid du Colombier 	    tm->mday < 1 || tm->hour < 0 || tm->hour >= 24 ||
20581bcec06SDavid du Colombier 	    tm->min < 0 || tm->min > 59 ||
20681bcec06SDavid du Colombier 	    tm->sec < 0 || tm->sec > 61)	/* allow 2 leap seconds */
20781bcec06SDavid du Colombier 		return 0;
20881bcec06SDavid du Colombier 	return 1;
20981bcec06SDavid du Colombier }
21081bcec06SDavid du Colombier 
21181bcec06SDavid du Colombier Time
seconds(char * timestr)21281bcec06SDavid du Colombier seconds(char *timestr)
21381bcec06SDavid du Colombier {
21481bcec06SDavid du Colombier 	Tm date;
21581bcec06SDavid du Colombier 
21681bcec06SDavid du Colombier 	memset(&date, 0, sizeof date);
21781bcec06SDavid du Colombier 	if (prsabsdate(timestr, localtime(time(0)), &date) < 0)
21881bcec06SDavid du Colombier 		return -1;
21981bcec06SDavid du Colombier 	return validtm(&date)? tm2sec(&date): -1;
22081bcec06SDavid du Colombier }
22181bcec06SDavid du Colombier 
22281bcec06SDavid du Colombier int
convert(char * timestr)22381bcec06SDavid du Colombier convert(char *timestr)
22481bcec06SDavid du Colombier {
22581bcec06SDavid du Colombier 	char *copy;
22681bcec06SDavid du Colombier 	Time tstime;
22781bcec06SDavid du Colombier 
22881bcec06SDavid du Colombier 	copy = strdup(timestr);
22981bcec06SDavid du Colombier 	if (copy == nil)
23081bcec06SDavid du Colombier 		sysfatal("out of memory");
23181bcec06SDavid du Colombier 	tstime = seconds(copy);
23281bcec06SDavid du Colombier 	free(copy);
23381bcec06SDavid du Colombier 	if (tstime == -1) {
23481bcec06SDavid du Colombier 		fprint(2, "%s: `%s' not a valid date\n", argv0, timestr);
23581bcec06SDavid du Colombier 		return 1;
23681bcec06SDavid du Colombier 	}
23781bcec06SDavid du Colombier 	print("%lud\n", tstime);
23881bcec06SDavid du Colombier 	return 0;
23981bcec06SDavid du Colombier }
24081bcec06SDavid du Colombier 
24181bcec06SDavid du Colombier static void
usage(void)24281bcec06SDavid du Colombier usage(void)
24381bcec06SDavid du Colombier {
24481bcec06SDavid du Colombier 	fprint(2, "usage: %s date-time ...\n", argv0);
24581bcec06SDavid du Colombier 	exits("usage");
24681bcec06SDavid du Colombier }
24781bcec06SDavid du Colombier 
24881bcec06SDavid du Colombier void
main(int argc,char ** argv)24981bcec06SDavid du Colombier main(int argc, char **argv)
25081bcec06SDavid du Colombier {
25181bcec06SDavid du Colombier 	int i, sts;
25281bcec06SDavid du Colombier 
25381bcec06SDavid du Colombier 	sts = 0;
25481bcec06SDavid du Colombier 	ARGBEGIN{
25581bcec06SDavid du Colombier 	default:
25681bcec06SDavid du Colombier 		usage();
25781bcec06SDavid du Colombier 	}ARGEND
25881bcec06SDavid du Colombier 	if (argc == 0)
25981bcec06SDavid du Colombier 		usage();
26081bcec06SDavid du Colombier 	for (i = 0; i < argc; i++)
26181bcec06SDavid du Colombier 		sts |= convert(argv[i]);
26281bcec06SDavid du Colombier 	exits(sts != 0? "bad": 0);
26381bcec06SDavid du Colombier }
26481bcec06SDavid du Colombier 
26581bcec06SDavid du Colombier /*
26681bcec06SDavid du Colombier  * Binary search -- from Knuth (6.2.1) Algorithm B.  Special case like this
26781bcec06SDavid du Colombier  * is WAY faster than the generic bsearch().
26881bcec06SDavid du Colombier  */
26981bcec06SDavid du Colombier Datetok *
datebsearch(char * key,Datetok * base,unsigned nel)27081bcec06SDavid du Colombier datebsearch(char *key, Datetok *base, unsigned nel)
27181bcec06SDavid du Colombier {
27281bcec06SDavid du Colombier 	int cmp;
27381bcec06SDavid du Colombier 	Datetok *last = base + nel - 1, *pos;
27481bcec06SDavid du Colombier 
27581bcec06SDavid du Colombier 	while (last >= base) {
27681bcec06SDavid du Colombier 		pos = base + ((last - base) >> 1);
27781bcec06SDavid du Colombier 		cmp = key[0] - pos->token[0];
27881bcec06SDavid du Colombier 		if (cmp == 0) {
27981bcec06SDavid du Colombier 			cmp = strncmp(key, pos->token, Maxtok);
28081bcec06SDavid du Colombier 			if (cmp == 0)
28181bcec06SDavid du Colombier 				return pos;
28281bcec06SDavid du Colombier 		}
28381bcec06SDavid du Colombier 		if (cmp < 0)
28481bcec06SDavid du Colombier 			last = pos - 1;
28581bcec06SDavid du Colombier 		else
28681bcec06SDavid du Colombier 			base = pos + 1;
28781bcec06SDavid du Colombier 	}
28881bcec06SDavid du Colombier 	return 0;
28981bcec06SDavid du Colombier }
29081bcec06SDavid du Colombier 
29181bcec06SDavid du Colombier Datetok *
datetoktype(char * s,int * bigvalp)29281bcec06SDavid du Colombier datetoktype(char *s, int *bigvalp)
29381bcec06SDavid du Colombier {
29481bcec06SDavid du Colombier 	char *cp = s;
29581bcec06SDavid du Colombier 	char c = *cp;
29681bcec06SDavid du Colombier 	static Datetok t;
29781bcec06SDavid du Colombier 	Datetok *tp = &t;
29881bcec06SDavid du Colombier 
29981bcec06SDavid du Colombier 	if (isascii(c) && isdigit(c)) {
30081bcec06SDavid du Colombier 		int len = strlen(cp);
30181bcec06SDavid du Colombier 
30281bcec06SDavid du Colombier 		if (len > 3 && (cp[1] == ':' || cp[2] == ':'))
30381bcec06SDavid du Colombier 			tp->type = Timetok;
30481bcec06SDavid du Colombier 		else {
30581bcec06SDavid du Colombier 			if (bigvalp != nil)
30681bcec06SDavid du Colombier 				*bigvalp = atoi(cp); /* won't fit in tp->value */
30781bcec06SDavid du Colombier 			if (len == 4)
30881bcec06SDavid du Colombier 				tp->type = Year;
30981bcec06SDavid du Colombier 			else if (++dtok_numparsed == 1)
31081bcec06SDavid du Colombier 				tp->type = Day;
31181bcec06SDavid du Colombier 			else
31281bcec06SDavid du Colombier 				tp->type = Year;
31381bcec06SDavid du Colombier 		}
31481bcec06SDavid du Colombier 	} else if (c == '-' || c == '+') {
31581bcec06SDavid du Colombier 		int val = atoi(cp + 1);
31681bcec06SDavid du Colombier 		int hr =  val / 100;
31781bcec06SDavid du Colombier 		int min = val % 100;
31881bcec06SDavid du Colombier 
31981bcec06SDavid du Colombier 		val = hr*60 + min;
32081bcec06SDavid du Colombier 		TOVAL(tp, c == '-'? -val: val);
32181bcec06SDavid du Colombier 		tp->type = Tz;
32281bcec06SDavid du Colombier 	} else {
32381bcec06SDavid du Colombier 		char lowtoken[Maxtok+1];
32481bcec06SDavid du Colombier 		char *ltp = lowtoken, *endltp = lowtoken+Maxtok;
32581bcec06SDavid du Colombier 
32681bcec06SDavid du Colombier 		/* copy to lowtoken to avoid modifying s */
32781bcec06SDavid du Colombier 		while ((c = *cp++) != '\0' && ltp < endltp)
32881bcec06SDavid du Colombier 			*ltp++ = (isascii(c) && isupper(c)? tolower(c): c);
32981bcec06SDavid du Colombier 		*ltp = '\0';
33081bcec06SDavid du Colombier 		tp = datebsearch(lowtoken, datetktbl, szdatetktbl);
33181bcec06SDavid du Colombier 		if (tp == nil) {
33281bcec06SDavid du Colombier 			tp = &t;
33381bcec06SDavid du Colombier 			tp->type = Ignore;
33481bcec06SDavid du Colombier 		}
33581bcec06SDavid du Colombier 	}
33681bcec06SDavid du Colombier 	return tp;
33781bcec06SDavid du Colombier }
33881bcec06SDavid du Colombier 
33981bcec06SDavid du Colombier 
34081bcec06SDavid du Colombier /*
34181bcec06SDavid du Colombier  * to keep this table reasonably small, we divide the lexval for Tz and Dtz
34281bcec06SDavid du Colombier  * entries by 10 and truncate the text field at MAXTOKLEN characters.
34381bcec06SDavid du Colombier  * the text field is not guaranteed to be NUL-terminated.
34481bcec06SDavid du Colombier  */
34581bcec06SDavid du Colombier static Datetok datetktbl[] = {
34681bcec06SDavid du Colombier /*	text		token	lexval */
34781bcec06SDavid du Colombier 	"acsst",	Dtz,	63,	/* Cent. Australia */
34881bcec06SDavid du Colombier 	"acst",		Tz,	57,	/* Cent. Australia */
34981bcec06SDavid du Colombier 	"adt",		Dtz,	-18,	/* Atlantic Daylight Time */
35081bcec06SDavid du Colombier 	"aesst",	Dtz,	66,	/* E. Australia */
35181bcec06SDavid du Colombier 	"aest",		Tz,	60,	/* Australia Eastern Std Time */
35281bcec06SDavid du Colombier 	"ahst",		Tz,	60,	/* Alaska-Hawaii Std Time */
35381bcec06SDavid du Colombier 	"am",		Ampm,	AM,
35481bcec06SDavid du Colombier 	"apr",		Month,	4,
35581bcec06SDavid du Colombier 	"april",	Month,	4,
35681bcec06SDavid du Colombier 	"ast",		Tz,	-24,	/* Atlantic Std Time (Canada) */
35781bcec06SDavid du Colombier 	"at",		Ignore,	0,	/* "at" (throwaway) */
35881bcec06SDavid du Colombier 	"aug",		Month,	8,
35981bcec06SDavid du Colombier 	"august",	Month,	8,
36081bcec06SDavid du Colombier 	"awsst",	Dtz,	54,	/* W. Australia */
36181bcec06SDavid du Colombier 	"awst",		Tz,	48,	/* W. Australia */
36281bcec06SDavid du Colombier 	"bst",		Tz,	6,	/* British Summer Time */
36381bcec06SDavid du Colombier 	"bt",		Tz,	18,	/* Baghdad Time */
36481bcec06SDavid du Colombier 	"cadt",		Dtz,	63,	/* Central Australian DST */
36581bcec06SDavid du Colombier 	"cast",		Tz,	57,	/* Central Australian ST */
36681bcec06SDavid du Colombier 	"cat",		Tz,	-60,	/* Central Alaska Time */
36781bcec06SDavid du Colombier 	"cct",		Tz,	48,	/* China Coast */
36881bcec06SDavid du Colombier 	"cdt",		Dtz,	-30,	/* Central Daylight Time */
36981bcec06SDavid du Colombier 	"cet",		Tz,	6,	/* Central European Time */
37081bcec06SDavid du Colombier 	"cetdst",	Dtz,	12,	/* Central European Dayl.Time */
37181bcec06SDavid du Colombier 	"cst",		Tz,	-36,	/* Central Standard Time */
37281bcec06SDavid du Colombier 	"dec",		Month,	12,
37381bcec06SDavid du Colombier 	"decemb",	Month,	12,
37481bcec06SDavid du Colombier 	"dnt",		Tz,	6,	/* Dansk Normal Tid */
37581bcec06SDavid du Colombier 	"dst",		Ignore,	0,
37681bcec06SDavid du Colombier 	"east",		Tz,	-60,	/* East Australian Std Time */
37781bcec06SDavid du Colombier 	"edt",		Dtz,	-24,	/* Eastern Daylight Time */
37881bcec06SDavid du Colombier 	"eet",		Tz,	12,	/* East. Europe, USSR Zone 1 */
37981bcec06SDavid du Colombier 	"eetdst",	Dtz,	18,	/* Eastern Europe */
38081bcec06SDavid du Colombier 	"est",		Tz,	-30,	/* Eastern Standard Time */
38181bcec06SDavid du Colombier 	"feb",		Month,	2,
38281bcec06SDavid du Colombier 	"februa",	Month,	2,
38381bcec06SDavid du Colombier 	"fri",		Ignore,	5,
38481bcec06SDavid du Colombier 	"friday",	Ignore,	5,
38581bcec06SDavid du Colombier 	"fst",		Tz,	6,	/* French Summer Time */
38681bcec06SDavid du Colombier 	"fwt",		Dtz,	12,	/* French Winter Time  */
38781bcec06SDavid du Colombier 	"gmt",		Tz,	0,	/* Greenwish Mean Time */
38881bcec06SDavid du Colombier 	"gst",		Tz,	60,	/* Guam Std Time, USSR Zone 9 */
38981bcec06SDavid du Colombier 	"hdt",		Dtz,	-54,	/* Hawaii/Alaska */
39081bcec06SDavid du Colombier 	"hmt",		Dtz,	18,	/* Hellas ? ? */
39181bcec06SDavid du Colombier 	"hst",		Tz,	-60,	/* Hawaii Std Time */
39281bcec06SDavid du Colombier 	"idle",		Tz,	72,	/* Intl. Date Line, East */
39381bcec06SDavid du Colombier 	"idlw",		Tz,	-72,	/* Intl. Date Line, West */
39481bcec06SDavid du Colombier 	"ist",		Tz,	12,	/* Israel */
39581bcec06SDavid du Colombier 	"it",		Tz,	22,	/* Iran Time */
39681bcec06SDavid du Colombier 	"jan",		Month,	1,
39781bcec06SDavid du Colombier 	"januar",	Month,	1,
39881bcec06SDavid du Colombier 	"jst",		Tz,	54,	/* Japan Std Time,USSR Zone 8 */
39981bcec06SDavid du Colombier 	"jt",		Tz,	45,	/* Java Time */
40081bcec06SDavid du Colombier 	"jul",		Month,	7,
40181bcec06SDavid du Colombier 	"july",		Month,	7,
40281bcec06SDavid du Colombier 	"jun",		Month,	6,
40381bcec06SDavid du Colombier 	"june",		Month,	6,
40481bcec06SDavid du Colombier 	"kst",		Tz,	54,	/* Korea Standard Time */
40581bcec06SDavid du Colombier 	"ligt",		Tz,	60,	/* From Melbourne, Australia */
40681bcec06SDavid du Colombier 	"mar",		Month,	3,
40781bcec06SDavid du Colombier 	"march",	Month,	3,
40881bcec06SDavid du Colombier 	"may",		Month,	5,
40981bcec06SDavid du Colombier 	"mdt",		Dtz,	-36,	/* Mountain Daylight Time */
41081bcec06SDavid du Colombier 	"mest",		Dtz,	12,	/* Middle Europe Summer Time */
41181bcec06SDavid du Colombier 	"met",		Tz,	6,	/* Middle Europe Time */
41281bcec06SDavid du Colombier 	"metdst",	Dtz,	12,	/* Middle Europe Daylight Time*/
41381bcec06SDavid du Colombier 	"mewt",		Tz,	6,	/* Middle Europe Winter Time */
41481bcec06SDavid du Colombier 	"mez",		Tz,	6,	/* Middle Europe Zone */
41581bcec06SDavid du Colombier 	"mon",		Ignore,	1,
41681bcec06SDavid du Colombier 	"monday",	Ignore,	1,
41781bcec06SDavid du Colombier 	"mst",		Tz,	-42,	/* Mountain Standard Time */
41881bcec06SDavid du Colombier 	"mt",		Tz,	51,	/* Moluccas Time */
41981bcec06SDavid du Colombier 	"ndt",		Dtz,	-15,	/* Nfld. Daylight Time */
42081bcec06SDavid du Colombier 	"nft",		Tz,	-21,	/* Newfoundland Standard Time */
42181bcec06SDavid du Colombier 	"nor",		Tz,	6,	/* Norway Standard Time */
42281bcec06SDavid du Colombier 	"nov",		Month,	11,
42381bcec06SDavid du Colombier 	"novemb",	Month,	11,
42481bcec06SDavid du Colombier 	"nst",		Tz,	-21,	/* Nfld. Standard Time */
42581bcec06SDavid du Colombier 	"nt",		Tz,	-66,	/* Nome Time */
42681bcec06SDavid du Colombier 	"nzdt",		Dtz,	78,	/* New Zealand Daylight Time */
42781bcec06SDavid du Colombier 	"nzst",		Tz,	72,	/* New Zealand Standard Time */
42881bcec06SDavid du Colombier 	"nzt",		Tz,	72,	/* New Zealand Time */
42981bcec06SDavid du Colombier 	"oct",		Month,	10,
43081bcec06SDavid du Colombier 	"octobe",	Month,	10,
43181bcec06SDavid du Colombier 	"on",		Ignore,	0,	/* "on" (throwaway) */
43281bcec06SDavid du Colombier 	"pdt",		Dtz,	-42,	/* Pacific Daylight Time */
43381bcec06SDavid du Colombier 	"pm",		Ampm,	PM,
43481bcec06SDavid du Colombier 	"pst",		Tz,	-48,	/* Pacific Standard Time */
43581bcec06SDavid du Colombier 	"sadt",		Dtz,	63,	/* S. Australian Dayl. Time */
43681bcec06SDavid du Colombier 	"sast",		Tz,	57,	/* South Australian Std Time */
43781bcec06SDavid du Colombier 	"sat",		Ignore,	6,
43881bcec06SDavid du Colombier 	"saturd",	Ignore,	6,
43981bcec06SDavid du Colombier 	"sep",		Month,	9,
44081bcec06SDavid du Colombier 	"sept",		Month,	9,
44181bcec06SDavid du Colombier 	"septem",	Month,	9,
44281bcec06SDavid du Colombier 	"set",		Tz,	-6,	/* Seychelles Time ?? */
44381bcec06SDavid du Colombier 	"sst",		Dtz,	12,	/* Swedish Summer Time */
44481bcec06SDavid du Colombier 	"sun",		Ignore,	0,
44581bcec06SDavid du Colombier 	"sunday",	Ignore,	0,
44681bcec06SDavid du Colombier 	"swt",		Tz,	6,	/* Swedish Winter Time  */
44781bcec06SDavid du Colombier 	"thu",		Ignore,	4,
44881bcec06SDavid du Colombier 	"thur",		Ignore,	4,
44981bcec06SDavid du Colombier 	"thurs",	Ignore,	4,
45081bcec06SDavid du Colombier 	"thursd",	Ignore,	4,
45181bcec06SDavid du Colombier 	"tue",		Ignore,	2,
45281bcec06SDavid du Colombier 	"tues",		Ignore,	2,
45381bcec06SDavid du Colombier 	"tuesda",	Ignore,	2,
45481bcec06SDavid du Colombier 	"ut",		Tz,	0,
45581bcec06SDavid du Colombier 	"utc",		Tz,	0,
45681bcec06SDavid du Colombier 	"wadt",		Dtz,	48,	/* West Australian DST */
45781bcec06SDavid du Colombier 	"wast",		Tz,	42,	/* West Australian Std Time */
45881bcec06SDavid du Colombier 	"wat",		Tz,	-6,	/* West Africa Time */
45981bcec06SDavid du Colombier 	"wdt",		Dtz,	54,	/* West Australian DST */
46081bcec06SDavid du Colombier 	"wed",		Ignore,	3,
46181bcec06SDavid du Colombier 	"wednes",	Ignore,	3,
46281bcec06SDavid du Colombier 	"weds",		Ignore,	3,
46381bcec06SDavid du Colombier 	"wet",		Tz,	0,	/* Western Europe */
46481bcec06SDavid du Colombier 	"wetdst",	Dtz,	6,	/* Western Europe */
46581bcec06SDavid du Colombier 	"wst",		Tz,	48,	/* West Australian Std Time */
46681bcec06SDavid du Colombier 	"ydt",		Dtz,	-48,	/* Yukon Daylight Time */
46781bcec06SDavid du Colombier 	"yst",		Tz,	-54,	/* Yukon Standard Time */
46881bcec06SDavid du Colombier 	"zp4",		Tz,	-24,	/* GMT +4  hours. */
46981bcec06SDavid du Colombier 	"zp5",		Tz,	-30,	/* GMT +5  hours. */
47081bcec06SDavid du Colombier 	"zp6",		Tz,	-36,	/* GMT +6  hours. */
47181bcec06SDavid du Colombier };
47281bcec06SDavid du Colombier static unsigned szdatetktbl = nelem(datetktbl);
473