home *** CD-ROM | disk | FTP | other *** search
- /* @(#)dates.c 3.0 (c) copyright 3/01/90 (Dan Heller, Bart Schaefer) */
-
- #include "mush.h"
-
- /*
- * %ld%3c%s gmt_in_secs weekday orig_timezone
- * The standard "date format" stored in the msg data structure.
- */
- char *day_names[] = {
- "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
- };
- char *month_names[] = { /* imported in pick.c */
- "Jan", "Feb", "Mar", "Apr", "May", "Jun",
- "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
- };
-
- static int mtbl[] = { 0,31,59,90,120,151,181,212,243,273,304,334 };
-
- /* Time Zone Stuff */
- struct zoneoff {
- char *zname;
- int hr_off;
- int mn_off;
- } time_zones[] = {
- /* Universal Time */
- { "UT", 0, 0 }, { "GMT", 0, 0 },
- /* European Time */
- { "BST", 1, 0 }, /* Brit. Summer */
- { "EET", 0, 0 }, { "EEST", 1, 0 }, /* Eastern */
- { "MET", -1, 0 }, { "MEST", 0, 0 }, /* Middle */
- { "WET", -2, 0 }, { "WEST", -1, 0 }, /* Western */
- /* North American Time */
- { "NST", -3,-30 }, /* Newfoundland */
- { "AST", -4, 0 }, { "ADT", -3, 0 }, /* Atlantic */
- { "EST", -5, 0 }, { "EDT", -4, 0 }, /* Eastern */
- { "CST", -6, 0 }, { "CDT", -5, 0 }, /* Central */
- { "MST", -7, 0 }, { "MDT", -6, 0 }, /* Mountain */
- { "PST", -8, 0 }, { "PDT", -7, 0 }, /* Pacific */
- { "YST", -9, 0 }, { "YDT", -8, 0 }, /* Yukon */
- { "HST", -10, 0 }, { "HDT", -9, 0 }, /* Hawaii */
- /* Japan and Australia Time */
- {"JST", 9, 0 }, /* Japan */
- {"AEST", 10, 0 }, {"AESST", 11, 0 }, /* Eastern */
- {"ACST", 9, 30 }, {"ACSST", 10, 30 }, /* Central */
- {"AWST", 8, 0 }, /* Western */
- /* Military Time */
- { "A", 1, 0 }, { "N", -1, 0 },
- { "B", 2, 0 }, { "O", -2, 0 },
- { "C", 3, 0 }, { "P", -3, 0 },
- { "D", 4, 0 }, { "Q", -4, 0 },
- { "E", 5, 0 }, { "R", -5, 0 },
- { "F", 6, 0 }, { "S", -6, 0 },
- { "G", 7, 0 }, { "T", -7, 0 },
- { "H", 8, 0 }, { "U", -8, 0 },
- { "I", 9, 0 }, { "V", -9, 0 },
- { "K", 10, 0 }, { "W", -10, 0 },
- { "L", 11, 0 }, { "X", -11, 0 },
- { "M", 12, 0 }, { "Y", -12, 0 },
- { "Z", 0, 0 },
- /* Also legal is +/- followed by hhmm offset from UT */
- { 0, 0, 0 }
- };
-
- long
- getzoff(zone)
- char *zone;
- {
- struct zoneoff *z;
- int hours, mins;
- char sign[2];
-
- if (!zone || !*zone)
- return 0;
- if (sscanf(zone, "%1[-+]%2d%2d", sign, &hours, &mins) == 3)
- return (hours * 3600 + mins * 60) * (*sign == '-' ? -1 : 1);
- for (z = time_zones; z->zname; z++)
- if (lcase_strncmp(zone, z->zname, -1) == 0)
- return z->hr_off * 3600 + z->mn_off * 60;
- return 0;
- }
-
- /*
- * Kind of the reverse of localtime() and gmtime() -- converts a struct tm
- * to time in seconds since 1970. Valid until 2038.
- * If the "zone" argument is present, it modifies the return value.
- * The zone should be a string, either +/-hhmm or symbolic (above).
- * The "how" argument should be -1 to convert FROM gmt, 1 to convert TO gmt,
- * and (as a "side-effect") 0 if the Zone parameter is to be ignored.
- *
- * Thanks to ktl@wag240.caltech.edu (Kian-Tat Lim) for similar algorithm
- * written in perl from which this was derived.
- */
- long
- time2gmt(tym, zone, how)
- struct tm *tym;
- char *zone;
- int how;
- {
- long year, julian;
-
- if (tym->tm_year < 100)
- year = tym->tm_year + 1900;
- if (year < 69)
- year += 100;
-
- julian = 365 * (year - 1970) + (int)((year - 1970 + 1) / 4) +
- mtbl[tym->tm_mon] + tym->tm_mday - 1;
- /* tym->tm_yday might not be valid */
- if (tym->tm_mon > 1 && year%4 == 0 && (year%100 != 0 || year%400 == 0))
- julian++;
- julian *= 86400; /* convert to seconds */
- julian += (tym->tm_hour * 60 + tym->tm_min) * 60 + tym->tm_sec;
- return julian - getzoff(zone) * how;
- }
-
- struct tm *
- time_n_zone(zone)
- char *zone;
- {
- struct tm *T;
- char *tz;
- #if defined(SYSV) || defined(TIMEZONE)
- long x;
-
- (void) time(&x);
- T = localtime(&x);
- #ifndef TIMEZONE
- {
- extern char *tzname[];
- tz = tzname[T->tm_isdst];
- }
- #endif /* TIMEZONE */
- #else /* SYSV || TIMEZONE */
- extern char *timezone();
- struct timeval mytime;
- struct timezone myzone;
-
- (void) gettimeofday(&mytime, &myzone);
- T = localtime(&mytime.tv_sec);
- tz = timezone(myzone.tz_minuteswest, (T->tm_isdst && myzone.tz_dsttime));
- #endif /* !SYSV */
-
- #ifdef TIMEZONE
- #ifdef DAYLITETZ
- if (T->tm_isdst)
- tz = DAYLITETZ;
- else
- #endif /* DAYLITETZ */
- tz = TIMEZONE;
- #endif /* TIMEZONE */
-
- (void) strncpy(zone, tz, 7), zone[7] = 0;
- return T;
- }
-
- /* Time() returns a string according to criteria:
- * if "now" is 0, then the current time is gotten and used.
- * else, use the time described by now
- * opts points to a string of args which is parsed until an unknown
- * arg is found and opts will point to that upon return.
- * valid args are T (time of day), D (day of week), M (month), Y (year),
- * N (number of day in month -- couldn't think of a better letter).
- */
- char *
- Time(opts, now)
- register char *opts;
- long now;
- {
- static char time_buf[30];
- struct tm *T;
- register char *p = time_buf;
- long x;
-
- if (!opts)
- return NULL;
- if (now)
- x = now;
- else
- (void) time(&x);
- T = localtime(&x);
- for (;; opts++) {
- switch(*opts) {
- case 'T':
- if (ison(glob_flags, MIL_TIME))
- (void) sprintf(p, "%2d:%02d", T->tm_hour, T->tm_min);
- else
- (void) sprintf(p, "%d:%02d", (T->tm_hour) ?
- ((T->tm_hour <= 12) ? T->tm_hour : T->tm_hour - 12) :
- 12, T->tm_min);
- when 'D': case 'W': (void) strcpy(p, day_names[T->tm_wday]);
- when 'M': (void) strcpy(p, month_names[T->tm_mon]);
- when 'y': (void) sprintf(p, "%d", T->tm_year);
- when 'Y': (void) sprintf(p, "%d", T->tm_year + 1900);
- when 'N': (void) sprintf(p, "%d", T->tm_mday);
- otherwise: *--p = 0; return time_buf;
- }
- p += strlen(p);
- *p++ = ' ';
- }
- }
-
- /* parse date and return a string that looks like
- * %ld%3c%s gmt_in_secs weekday orig_timezone
- * This function is a bunch of scanfs on known date formats. Don't
- * trust the "weekday" name fields because they may not be spelled
- * right, or have the correct punctuation. Figure it out once the
- * year and month and date have been determined.
- */
- char *
- parse_date(p)
- register char *p;
- {
- /* When scanf-ing if month isn't a month, it could be a _long_ string.
- * this is also the static buffer whose address we return.
- */
- static char month[64];
- char Wkday[4], Zone[8];
- char a_or_p;
- int Month = 0, Day = 0, Year = 0;
- int Uhour = 0, Umin = 0, Hours = -1, Mins = -1;
- struct tm T;
-
- Zone[0] = 0;
- skipspaces(0);
-
- /* programmer's note -- there are too many scanfs here for some compilers
- * to put them all into one if statement. Use goto's :-( Also reset
- * Zone[0] after any sscanf() that could corrupt it on a partial match.
- */
-
- /* RFC822 formats and minor variations -- order important */
-
- /* day_number month_name year_number time timezone */
- if (sscanf(p, "%d %s %d %d:%d:%*d %7s",
- &Day, month, &Year, &Hours, &Mins, Zone) >= 5 && Day)
- goto gotit;
- Zone[0] = 0;
- if (sscanf(p, "%d %s %d %d:%d %7s",
- &Day, month, &Year, &Hours, &Mins, Zone) >= 5 && Day)
- goto gotit;
- Zone[0] = 0;
- /* day_name day_number month_name year_number time timezone */
- if (sscanf(p, "%*s %d %s %d %d:%d:%*d %7s",
- &Day, month, &Year, &Hours, &Mins, Zone) >= 5 && Day)
- goto gotit;
- Zone[0] = 0;
- if (sscanf(p, "%*s %d %s %d %d:%d %7s",
- &Day, month, &Year, &Hours, &Mins, Zone) >= 5 && Day)
- goto gotit;
- Zone[0] = 0;
-
- /* Ctime format (From_ lines) -- timezone almost never found */
-
- /* day_name month_name day_number time year_number */
- if (sscanf(p, "%*s %s %d %d:%d:%*d %d %7s",
- month, &Day, &Hours, &Mins, &Year, Zone) >= 5)
- goto gotit;
- Zone[0] = 0;
-
- /* Other common variants */
-
- /* day_number month_name year_number time-timezone (day) */
- /* ^no colon separator */
- if (sscanf(p, "%d %s %d %2d%2d-%6[0123456789]",
- &Day, month, &Year, &Hours, &Mins, &Zone[1]) == 6) {
- Zone[0] = '-';
- goto gotit;
- }
- if (sscanf(p, "%d %s %d %2d%2d-%7s",
- &Day, month, &Year, &Hours, &Mins, Zone) == 6)
- goto gotit;
- Zone[0] = 0;
-
- /* day_number month_name year_number time timezone */
- /* ^no colon separator */
- /* (This is the odd one in the RFC822 examples section; */
- /* also catches the slop from partial hits above.) */
- if (sscanf(p, "%d %s %d %2d%2d %7s",
- &Day, month, &Year, &Hours, &Mins, Zone) >= 5 && Day)
- goto gotit;
- Zone[0] = 0;
-
- Zone[1] = 0; /* Yes, Zone[1] -- tested below */
-
- /* day_number month_name year_number, time "-" ?? */
- if (sscanf(p,"%d %s %d, %d:%d:%*d -%6[0123456789]",
- &Day, month, &Year, &Hours, &Mins, &Zone[1]) >= 5 && Day) {
- if (Zone[1])
- Zone[0] = '-';
- goto gotit;
- }
-
- /* day_number month_name year_number 12_hour_time a_or_p */
- if (sscanf(p, "%d %s %d %d:%d:%*d %cm %7s",
- &Day, month, &Year, &Hours, &Mins, &a_or_p, Zone) >= 6) {
- if (a_or_p == 'p')
- Hours += 12;
- goto gotit;
- }
-
- /* day_name month_name day_number year_number time */
- if (sscanf(p, "%*s %s %d %d %d:%d:%*d %7s",
- month, &Day, &Year, &Hours, &Mins, Zone) >= 5)
- goto gotit;
- Zone[0] = 0;
- if (sscanf(p, "%*s %s %d %d %d:%d %7s",
- month, &Day, &Year, &Hours, &Mins, Zone) >= 5)
- goto gotit;
- Zone[0] = 0;
-
- /* day_name month_name day_number time timezone year_number */
- if (sscanf(p, "%*s %s %d %d:%d:%*d %7s %d",
- month, &Day, &Hours, &Mins, Zone, &Year) == 6)
- goto gotit;
- Zone[0] = 0;
- if (sscanf(p, "%*s %s %d %d:%d %7s %d",
- month, &Day, &Hours, &Mins, Zone, &Year) == 6)
- goto gotit;
- Zone[0] = 0;
-
- /* day_number-month_name-year time */
- if (sscanf(p,"%d-%[^-]-%d %d:%d", &Day, month, &Year, &Hours, &Mins) == 5)
- goto gotit;
-
- /* day_name, day_number-month_name-year time */
- if (sscanf(p,"%*s %d-%[^-]-%d %d:%d",
- &Day, month, &Year, &Hours, &Mins) == 5)
- goto gotit;
-
- /* year_number-month_number-day_number time */
- if (sscanf(p, "%d-%d-%d %d:%d", &Year, &Month, &Day, &Hours, &Mins) == 5)
- goto gotit;
-
- /* month_name day_number time year Zone */
- /* (ctime, but without the day name) */
- if (sscanf(p, "%s %d %d:%d:%*d %d %7s",
- month, &Day, &Hours, &Mins, &Year, Zone) >= 5)
- goto gotit;
- Zone[0] = 0;
-
- goto didnt_getit;
-
- gotit:
- if (Year > 1900)
- Year -= 1900;
- if (!Month && (Month = month_to_n(month)) == -1) {
- print("bad month: %s\n", p);
- return NULL;
- }
- if (Zone[0] == 0) {
- /* Use local time zone if none found -- important for date_recv */
- (void) time_n_zone(Zone);
- }
- {
- /* Lots of foolishness with casts for Xenix-286 16-bit ints */
-
- long days_ctr; /* 16-bit ints overflowed Sept 12, 1989 */
-
- days_ctr = ((long)Year * 365L) + ((Year + 3) / 4);
- days_ctr += mtbl[Month-1] + Day + 6;
- if (Month > 2 && (Year % 4 == 0))
- days_ctr++;
- (void) (sprintf(Wkday, "%.3s", day_names[(int)(days_ctr % 7L)]));
- }
- T.tm_sec = 0; /* not recorded, so ignore it */
- T.tm_min = Mins;
- T.tm_hour = Hours;
- T.tm_mday = Day;
- T.tm_mon = Month - 1;
- T.tm_year = Year;
- T.tm_wday = T.tm_yday = 0; /* not used in time2gmt() */
- T.tm_isdst = 0; /* determined from Zone */
- return sprintf(month, "%ld%s%s", time2gmt(&T, Zone, 1), Wkday, Zone);
- didnt_getit:
- if (ison(glob_flags, WARNING))
- print("Unknown date format: %s\n", p);
- return NULL;
- }
-
- /* pass a string in the standard date format, put into string.
- * return values in buffers provided they are not null.
- */
- char *
- date_to_string(Date, Yr, Mon, Day, Wkday, Tm, Zone, ret_buf)
- char *Date, *Yr, *Mon, *Day, *Wkday, *Tm, *Zone, *ret_buf;
- {
- long gmt;
- struct tm *T;
- char a_or_p, *p = ret_buf;
-
- Zone[0] = 0;
- (void) sscanf(Date, "%ld%3c%s", &gmt, Wkday, Zone);
- Wkday[3] = 0;
- gmt += getzoff(Zone);
- T = gmtime(&gmt);
- a_or_p = (T->tm_hour < 12)? 'a': 'p';
-
- (void) sprintf(Yr, "%d", T->tm_year + 1900);
- (void) sprintf(Day, "%d", T->tm_mday);
- (void) strcpy(Mon, month_names[T->tm_mon]);
- p += strlen(sprintf(p, "%s %2.d, ", Mon, T->tm_mday));
-
- if (ison(glob_flags, MIL_TIME))
- (void) sprintf(p, "%2d:%02d",T->tm_hour,T->tm_min);
- else
- (void) sprintf(p, "%2.d:%02d%cm",
- (T->tm_hour)? (T->tm_hour <= 12)? T->tm_hour: T->tm_hour-12: 12,
- T->tm_min, a_or_p);
- (void) strcpy(Tm, p);
-
- return ret_buf;
- }
-
- /* pass a string in the internal mush date format.
- * return pointer to static buffer holding ctime-format date.
- */
- char *
- date_to_ctime(Date)
- char *Date;
- {
- static char ret_buf[32];
- long gmt;
-
- ret_buf[0] = 0;
- (void) sscanf(Date, "%ld", &gmt);
- (void) strcpy(ret_buf, ctime(&gmt));
-
- return ret_buf;
- }
-
- /*
- * Build a date string according to the specification in the RFC for Date:
- */
- char *
- rfc_date(buf)
- char buf[];
- {
- struct tm *T;
- char zone[8];
-
- T = time_n_zone(zone);
- return sprintf(buf, "%s, %d %s %d %02d:%02d:%02d %s",
- day_names[T->tm_wday], /* day name */
- T->tm_mday, /* day of the month */
- month_names[T->tm_mon], /* month name */
- T->tm_year + 1900, /* year number */
- T->tm_hour, /* hours (24hr) */
- T->tm_min, T->tm_sec, /* mins/secs */
- zone); /* timezone */
- }
-
- #define JAN 1
- #define FEB 2
- #define MAR 3
- #define APR 4
- #define MAY 5
- #define JUN 6
- #define JUL 7
- #define AUG 8
- #define SEP 9
- #define OCT 10
- #define NOV 11
- #define DEC 12
-
- /* stolen direct from ELM */
- month_to_n(name)
- register char *name;
- {
- /** return the month number given the month name... **/
-
- register char ch;
-
- switch (lower(*name)) {
- case 'a' : if ((ch = lower(name[1])) == 'p')
- return(APR);
- else if (ch == 'u')
- return(AUG);
- else return(-1); /* error! */
- case 'd' : return(DEC);
- case 'f' : return(FEB);
- case 'j' : if ((ch = lower(name[1])) == 'a')
- return(JAN);
- else if (ch == 'u') {
- if ((ch = lower(name[2])) == 'n')
- return(JUN);
- else if (ch == 'l')
- return(JUL);
- else return(-1); /* error! */
- }
- else return(-1); /* error */
- case 'm' : if ((ch = lower(name[2])) == 'r')
- return(MAR);
- else if (ch == 'y')
- return(MAY);
- else return(-1); /* error! */
- case 'n' : return(NOV);
- case 'o' : return(OCT);
- case 's' : return(SEP);
- default : return(-1);
- }
- }
-