X * The table is used to hold the list of known names.
X * This includes time zone names and days of the week, etc.
X *
X * CAVEAT
X * It is in English.
X * It is impossible to have a full list of time zones.
X */
X
Xtypedef struct table_t table_t;
Xstruct table_t
X{
X char *name;
X int type;
X int value;
X};
X
X#define HRMIN(a, b) ((a) * 60 + (b))
X
Xstatic table_t table[] =
X{
X { "a", ZONE, HRMIN(1, 0), },
X { "a.c.s.s.t.", DAYZONE, -HRMIN(9, 30), },
X { "a.c.s.t.", ZONE, -HRMIN(9, 30), },
X { "a.d.t.", DAYZONE, HRMIN(4, 0), },
X { "a.e.s.s.t.", DAYZONE, -HRMIN(10, 0), },
X { "a.e.s.t.", ZONE, -HRMIN(10, 0), },
X { "a.m.", MERIDIAN, AM, },
X { "a.s.t.", ZONE, HRMIN(4, 0), },
X { "a.w.s.t.", ZONE, -HRMIN(8, 0), }, /* (no daylight time there, I'm told */
X { "acsst", DAYZONE, -HRMIN(9, 30), }, /* Australian Central Summer */
X { "acst", ZONE, -HRMIN(9, 30), }, /* Australian Central Time */
X { "adt", DAYZONE, HRMIN(4, 0), },
X { "aesst", DAYZONE, -HRMIN(10, 0), }, /* Australian Eastern Summer Time */
X { "aest", ZONE, -HRMIN(10, 0), }, /* Australian Eastern Time */
X { "ago", AGO, 1, },
X { "am", MERIDIAN, AM, },
X { "apr", MONTH, 4, },
X { "apr.", MONTH, 4, },
X { "april", MONTH, 4, },
X { "ast", ZONE, HRMIN(4, 0), }, /* Atlantic */
X { "aug", MONTH, 8, },
X { "aug.", MONTH, 8, },
X { "august", MONTH, 8, },
X { "awst", ZONE, -HRMIN(8, 0), }, /* Australian Western Time */
X { "b", ZONE, HRMIN(2, 0), },
X { "b.s.t.", DAYZONE, HRMIN(0, 0), },
X { "bst", DAYZONE, HRMIN(0, 0), }, /* British Summer Time */
X { "c", ZONE, HRMIN(3, 0), },
X { "c.d.t.", DAYZONE, HRMIN(6, 0), },
X { "c.s.t.", ZONE, HRMIN(6, 0), },
X { "cdt", DAYZONE, HRMIN(6, 0), },
X { "cst", ZONE, HRMIN(6, 0), }, /* Central */
X { "d", ZONE, HRMIN(4, 0), },
X { "day", UNIT, 1 * 24 * 60, },
X { "days", UNIT, 1 * 24 * 60, },
X { "dec", MONTH, 12, },
X { "dec.", MONTH, 12, },
X { "december", MONTH, 12, },
X { "e", ZONE, HRMIN(5, 0), },
X { "e.d.t.", DAYZONE, HRMIN(5, 0), },
X { "e.e.s.t.", DAYZONE, HRMIN(0, 0), },
X { "e.e.t.", ZONE, HRMIN(0, 0), },
X { "e.s.t.", ZONE, HRMIN(5, 0), },
X { "edt", DAYZONE, HRMIN(5, 0), },
X { "eest", DAYZONE, HRMIN(0, 0), }, /* European Eastern Summer Time */
X { "eet", ZONE, HRMIN(0, 0), }, /* European Eastern Time */
X { "eigth", NUMBER, 8, },
X { "eleventh", NUMBER, 11, },
X { "est", ZONE, HRMIN(5, 0), }, /* Eastern */
X { "f", ZONE, HRMIN(6, 0), },
X { "feb", MONTH, 2, },
X { "feb.", MONTH, 2, },
X { "february", MONTH, 2, },
X { "fifth", NUMBER, 5, },
X { "first", NUMBER, 1, },
X { "fortnight", UNIT, 14 * 24 * 60, },
X { "fortnights", UNIT, 14 * 24 * 60, },
X { "fourth", NUMBER, 4, },
X { "fri", DAY, 5, },
X { "fri.", DAY, 5, },
X { "friday", DAY, 5, },
X { "g", ZONE, HRMIN(7, 0), },
X { "g.m.t.", ZONE, HRMIN(0, 0), },
X { "gmt", ZONE, HRMIN(0, 0), },
X { "h", ZONE, HRMIN(8, 0), },
X { "h.d.t.", DAYZONE, HRMIN(10, 0), },
X { "h.s.t.", ZONE, HRMIN(10, 0), },
X { "hdt", DAYZONE, HRMIN(10, 0), },
X { "hour", UNIT, 60, },
X { "hours", UNIT, 60, },
X { "hr", UNIT, 60, },
X { "hrs", UNIT, 60, },
X { "hst", ZONE, HRMIN(10, 0), }, /* Hawaii */
X { "i", ZONE, HRMIN(9, 0), },
X { "j.s.t.", ZONE, -HRMIN(9, 0), }, /* Japan Standard Time */
X { "jan", MONTH, 1, },
X { "jan.", MONTH, 1, },
X { "january", MONTH, 1, },
X { "jst", ZONE, -HRMIN(9, 0), }, /* Japan Standard Time */
X { "jul", MONTH, 7, },
X { "jul.", MONTH, 7, },
X { "july", MONTH, 7, },
X { "jun", MONTH, 6, },
X { "jun.", MONTH, 6, },
X { "june", MONTH, 6, },
X { "k", ZONE, HRMIN(10, 0), },
X { "l", ZONE, HRMIN(11, 0), },
X { "last", NUMBER, -1, },
X { "m", ZONE, HRMIN(12, 0), },
X { "m.d.t.", DAYZONE, HRMIN(7, 0), },
X { "m.e.s.t.", DAYZONE, -HRMIN(1, 0), },
X { "m.e.t.", ZONE, -HRMIN(1, 0), },
X { "m.s.t.", ZONE, HRMIN(7, 0), },
X { "mar", MONTH, 3, },
X { "mar.", MONTH, 3, },
X { "march", MONTH, 3, },
X { "may", MONTH, 5, },
X { "mdt", DAYZONE, HRMIN(7, 0), },
X { "mest", DAYZONE, -HRMIN(1, 0), }, /* Middle European Summer Time */
X { "met", ZONE, -HRMIN(1, 0), }, /* Middle European Time */
X { "min", UNIT, 1, },
X { "mins", UNIT, 1, },
X { "minute", UNIT, 1, },
X { "minutes", UNIT, 1, },
X { "mon", DAY, 1, },
X { "mon.", DAY, 1, },
X { "monday", DAY, 1, },
X { "month", MUNIT, 1, },
X { "months", MUNIT, 1, },
X { "mst", ZONE, HRMIN(7, 0), }, /* Mountain */
X { "n", ZONE, -HRMIN(1, 0), },
X { "n.s.t.", ZONE, HRMIN(3, 30), },
X { "next", NUMBER, 2, },
X { "ninth", NUMBER, 9, },
X { "nov", MONTH, 11, },
X { "nov.", MONTH, 11, },
X { "november", MONTH, 11, },
X { "now", UNIT, 0, },
X { "nst", ZONE, HRMIN(3, 30), }, /* Newfoundland */
X { "o", ZONE, -HRMIN(2, 0), },
X { "oct", MONTH, 10, },
X { "oct.", MONTH, 10, },
X { "october", MONTH, 10, },
X { "p", ZONE, -HRMIN(3, 0), },
X { "p.d.t.", DAYZONE, HRMIN(8, 0), },
X { "p.m.", MERIDIAN, PM, },
X { "p.s.t.", ZONE, HRMIN(8, 0), },
X { "pdt", DAYZONE, HRMIN(8, 0), },
X { "pm", MERIDIAN, PM, },
X { "pst", ZONE, HRMIN(8, 0), }, /* Pacific */
X { "q", ZONE, -HRMIN(4, 0), },
X { "r", ZONE, -HRMIN(5, 0), },
X { "s", ZONE, -HRMIN(6, 0), },
X { "sat", DAY, 6, },
X { "sat.", DAY, 6, },
X { "saturday", DAY, 6, },
X { "sec", SUNIT, 1, },
X { "second", SUNIT, 1, },
X { "seconds", SUNIT, 1, },
X { "secs", SUNIT, 1, },
X { "sep", MONTH, 9, },
X { "sep.", MONTH, 9, },
X { "sept", MONTH, 9, },
X { "sept.", MONTH, 9, },
X { "september", MONTH, 9, },
X { "seventh", NUMBER, 7, },
X { "sixth", NUMBER, 6, },
X { "sun", DAY, 0, },
X { "sun.", DAY, 0, },
X { "sunday", DAY, 0, },
X { "t", ZONE, -HRMIN(7, 0), },
X { "tenth", NUMBER, 10, },
X { "third", NUMBER, 3, },
X { "this", UNIT, 0, },
X { "thu", DAY, 4, },
X { "thu.", DAY, 4, },
X { "thur", DAY, 4, },
X { "thur.", DAY, 4, },
X { "thurs", DAY, 4, },
X { "thurs.", DAY, 4, },
X { "thursday", DAY, 4, },
X { "today", UNIT, 0, },
X { "tomorrow", UNIT, 1 * 24 * 60, },
X { "tue", DAY, 2, },
X { "tue.", DAY, 2, },
X { "tues", DAY, 2, },
X { "tues.", DAY, 2, },
X { "tuesday", DAY, 2, },
X { "twelfth", NUMBER, 12, },
X { "u", ZONE, -HRMIN(8, 0), },
X { "u.t.", ZONE, HRMIN(0, 0), },
X { "ut", ZONE, HRMIN(0, 0), },
X { "v", ZONE, -HRMIN(9, 0), },
X { "w", ZONE, -HRMIN(10, 0), },
X { "w.e.s.t.", DAYZONE, -HRMIN(2, 0), },
X { "w.e.t.", ZONE, -HRMIN(2, 0), },
X { "wed", DAY, 3, },
X { "wed.", DAY, 3, },
X { "wednes", DAY, 3, },
X { "wednes.", DAY, 3, },
X { "wednesday", DAY, 3, },
X { "week", UNIT, 7 * 24 * 60, },
X { "weeks", UNIT, 7 * 24 * 60, },
X { "west", DAYZONE, -HRMIN(2, 0), }, /* Western European Summer Time */
X { "wet", ZONE, -HRMIN(2, 0), }, /* Western European Time */
X { "x", ZONE, -HRMIN(11, 0), },
X { "y", ZONE, -HRMIN(12, 0), },
X { "y.d.t.", DAYZONE, HRMIN(9, 0), },
X { "y.s.t.", ZONE, HRMIN(9, 0), },
X { "ydt", DAYZONE, HRMIN(9, 0), },
X { "year", MUNIT, 12, },
X { "years", MUNIT, 12, },
X { "yesterday", UNIT, -1*24*60, },
X { "yst", ZONE, HRMIN(9, 0), }, /* Yukon */
X { "z", ZONE, HRMIN(0, 0), },
X};
X
X
X/*
X * NAME
X * timeconv - convert a time
X *
X * SYNOPSIS
X * time_t timeconv(int hh, int mm, int ss, int mer);
X *
X * DESCRIPTION
X * The timeconv function is used to convert a time
X * specified in hours minutes and seconds, into seconds past midnight.
X *
X * ARGUMENTS
X * hh hours, range depends on the meridian
X * mm minutes, 0..59
X * ss seconds, 0..59
X * mer meridian to use: AM, PM or 24
X *
X * RETURNS
X * time_t; seconds past midnight; -1 on any error.
X */
X
Xstatic time_t timeconv _((int hh, int mm, int ss, int mer));
X
Xstatic time_t
Xtimeconv(hh, mm, ss, mer)
X int hh;
X int mm;
X int ss;
X int mer;
X{
X time_t result;
X
X /*
X * perform sanity checks on input
X */
X trace(("timeconv(hh = %d, mm = %d, ss = %d, mer = %d)\n{\n"/*}*/, hh, mm, ss, mer));
X result = -1;
X if (mm < 0 || mm > 59 || ss < 0 || ss > 59)
X goto done;
X
X /*
X * perform range checks depending on the meridian
X */
X switch (mer)
X {
X case AM:
X if (hh < 1 || hh > 12)
X goto done;
X if (hh == 12)
X hh = 0;
X break;
X
X case PM:
X if (hh < 1 || hh > 12)
X goto done;
X if (hh == 12)
X hh = 0;
X hh += 12;
X break;
X
X case 24:
X if (hh < 0 || hh > 23)
X goto done;
X break;
X
X default:
X goto done;
X }
X result = ((hh * 60L + mm) * 60L + ss);
Xdone:
X trace(("return %ld;\n", (long)result));
X trace((/*{*/"}\n"));
X return result;
X}
X
X
X/*
X * NAME
X * dateconv - convert a date
X *
X * SYNOPSIS
X * time_t dateconv(int mm, int dd, int year, int h, int m, int s,
X * int mer, int zone, int dayflag);
X *
X * DESCRIPTION
X * The dateconv function may be used to convert a date after the
X * date string has been taken apart by yyparse.
X *
X * ARGUMENTS
X * mm month number, in the range 1..12
X * year year number, in several ranges:
X * 0..37 means 2000..2037
X * 70..99 means 1970..1999
X * 1970..2037 mean themselves.
X * dd day of month, in the range 1..max, where max varies for
X * each month, as per the catchy jingle (except February,
X * which is a monster).
X * h hours since midnight or meridian
X * m minutes past hour
X * s seconds past minute
X * mer meridian, AM or PM.
X * zone minutes correction for the time zone.
X * dayflag whether to use daylight savings: STANDARD, DAYLIGHT or MAYBE.
X *
X * RETURNS
X * time_t; the time in seconds past Jan 1 0:00:00 1970 GMT, this will
X * always be positive or zero; -1 is returned for any error.
X *
X * CAVEAT
X * The date functions only work between 1970 and 2037,
X * because 0 is Jan 1 00:00:00 1970 GMT
X * and (2^31-1) is Jan 19 03:14:07 2038 GMT
X * hence some if the weir magic number below.
X *
X * Because -1 is used to represent errors, times before noon Jan 1 1970
X * in places east of GMT can't always be represented.
X */
X
Xstatic time_t dateconv _((int mm, int dd, int year, int h, int m, int s,
X int mer, int zone, int dayflag));
X
Xstatic time_t
Xdateconv(mm, dd, year, h, m, s, mer, zone, dayflag)
X int mm;
X int dd;
X int year;
X int h;
X int m;
X int s;
X int mer;
X int zone;
X int dayflag;
X{
X time_t result;
X time_t tod;
X time_t jdate;
X int i;
X
X /*
X * make corrections for the year
X *
X * If it is 0..99, RFC822 says pick closest century.
X */
X trace(("dateconv(mm = %d, dd = %d, year = %d, h = %d, m = %d, s = %d, mer = %d, zone = %d, dayflag = %d)\n{\n"/*}*/, mm, dd, year, h, m, s, mer, zone, dayflag));