|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T g
Length: 13521 (0x34d1) Types: TextFile Names: »gdate.c«
└─⟦a0efdde77⟧ Bits:30001252 EUUGD11 Tape, 1987 Spring Conference Helsinki └─⟦this⟧ »EUUGD11/euug-87hel/sec1/nag/gdate.c«
/* * routines to turn a date from various formats to other formats * * Primary interesting routine is gdate() which eats a date * string of several common formats (see comment) and * fills in a standard UNIX tm structure. * * Barry Shein, Boston University * * if you compile it -DDEBUG (with DEBUG defined) it will * pull in a main() routine to run standalone for testing. * * NOTE: * * Barry's gdate was broken by a 1-off error; tm_mon is kept * in the range 0..11 instead of 1..12. Also, his totime was * broken, so I've deleted it and use the tm_to_time() function * from mod.sources. * * * Defines the functions: * * lcase() -- convert a char to lower case * dstring() -- get digit string from sp into bp (buffer) returning new sp * skipw() -- skip white space returning updated ptr * prefix() -- return how many chars of s1 prefix s2 * find() -- look up str in list for non-ambiguous (prefix) match * lookup() -- like find but demands exact match * extract() -- extract a token * fill() -- fill up an area with a value (eg. zeros) * * gdate() -- convert a date/time string to a tm structure. * gtime() -- convert time string to a tm structure. * * days() -- how many days were in a year. * jan1() -- return day of the week of jan 1 of given year * dowk() -- insert day of week given year and day of year into tm struct. * doyr() -- insert partial day of year given yr, mon and mday into tm struct. * * leap() -- Return 1 if `y' is a leap year, 0 otherwise. * ndays() -- number of days between UNIX epoch and time in a tm struct. * tm_to_time() -- Convert a tm struct to a time_t. */ #include <stdio.h> #include <ctype.h> #include <sys/types.h> #ifdef SYS5 # define time_t long /* SV is inconsistent, so go with lcd */ # include <time.h> # include <sys/times.h> # include <string.h> # else /* BSD */ # include <sys/time.h> # include <sys/timeb.h> # include <strings.h> #endif /*---------------------------------------------------------------- * * Manifest constants * */ #define MAXTOK 20 #define AMBIG -1 /* ambiguous month */ #define FALSE -2 /* bad syntax */ /*---------------------------------------------------------------- * * static and global Data * */ char *months[] = { "january", "february", "march", "april", "may", "june", "july", "august", "september", "october", "november", "december", 0 } ; char *dow[] = { "sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday", 0 } ; /* * known time-zone name list */ char *tz[] = { "adt", "ast", "edt", "est", "cdt", "cst", "mst", "mdt", "pdt", "pst", "gmt", 0 } ; char mdays[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } ; /*---------------------------------------------------------------- * * Utility functions * */ /* * lcase() -- convert a char to lower case */ lcase(c) register char c ; { return(isupper(c) ? tolower(c) : c) ; } /* * dstring() -- get digit string from sp into bp (buffer) returning new sp */ char * dstring(bp,sp) register char *sp, *bp ; { register int i = 0 ; while(isdigit(*sp)) if(i++ == MAXTOK) break ; else *bp++ = *sp++ ; *bp = '\0' ; return(sp) ; } /* * skipw() -- skip white space returning updated ptr */ char * skipw(sp) register char *sp ; { while(isspace(*sp) || *sp == '-') ++sp ; return(sp) ; } /* * prefix() -- return how many chars of s1 prefix s2 */ prefix(s1,s2) register char *s1, *s2 ; { register int i = 0 ; for(; *s1 == *s2 ; s1++,s2++,i++) if(*s2 == '\0') break ; return(*s1 == '\0' ? i : 0) ; } /* * find() -- look up str in list for non-ambiguous (prefix) match */ find(sp,lp) register char *sp, **lp ; { int i,j,ambig = 0 ; register int k ; int ret = FALSE ; for(i = 0,k = 0 ; *lp ; lp++,k++) if((j = prefix(sp,*lp)) > i) { ambig = 0 ; i = j ; ret = k + 1 ; } else if(j && (i == j)) ++ambig ; return(ambig ? AMBIG : ret) ; } /* * lookup() -- like find but demands exact match */ lookup(sp,lp) register char *sp, **lp ; { int i = 0 ; for(i=0 ; *lp ; lp++,i++) if(strcmp(sp,*lp) == 0) return(i+1) ; return(0) ; } /* * extract() -- extract a token */ char * extract(bp,sp) register char *bp, *sp ; { register int i = 0 ; sp = skipw(sp) ; for(; isalnum(*sp); sp++) if(i++ == MAXTOK) break ; else *bp++ = lcase(*sp) ; *bp = '\0' ; return(sp) ; } /* * fill() -- fill up an area with a value (eg. zeros) */ fill(cp,c,n) register char *cp, c ; register int n ; { while(n--) *cp++ = c ; } /*---------------------------------------------------------------- * * gdate, gtime related. * */ char *gdate() ; char *gtime() ; /* * gdate(date_str_ptr,time_buf_ptr) * (see CTIME(3) in UPM for second arg format) * takes many reasonable date strings and translates to * the time-buf structure (integers) * * formats (eg.): * oct 19, 1983 * OcT 19, 1983 12:43 * oCt 19, 1983 12:43:33 * oct 19 1983 ... * 19 oct 83 .... * 10/19/83 12:43:33 * 19-OCT-83 12:43:00 (DEC style) * Wed Oct 19 12:43 EST 83 (UNIX style) * oct. 19, 83 1:44 pm est * 831019124333 (see date(1)) * some variations on those themes also. * * BUGS: probably a few (maybe some in the eye of the beholder) * does not set dst flag (unless 'EDT' is in string) */ char * gdate(sp,tp) register char *sp ; register struct tm *tp ; { char buf[MAXTOK] ; fill(tp,'\0',sizeof *tp) ; sp = skipw(sp) ; if(isdigit(*sp)) /* either '7/12/83' or '12 jul 83' */ { if(isdigit(sp[1]) && isdigit(sp[2])) /* UNIX yymmddhhmmss */ { buf[2] = '\0' ; (void)strncpy(buf,sp,2) ; tp->tm_year = atoi(buf) ; (void)strncpy(buf,sp += 2,2) ; tp->tm_mon = atoi(buf) - 1 ; sp += 2 ; if(!isdigit(*sp)) goto badday ; (void)strncpy(buf,sp,2) ; tp->tm_mday = atoi(buf) ; sp += 2 ; if(!isdigit(*sp)) goto check ; (void)strncpy(buf,sp,2) ; /* ??? formerly null effect "tp->tm_hour ;" */ tp->tm_hour = atoi(buf) ; sp += 2 ; if(!isdigit(*sp)) goto check ; (void)strncpy(buf,sp,2) ; tp->tm_min = atoi(buf) ; sp += 2 ; if(!isdigit(*sp)) goto check ; (void)strncpy(buf,sp,2) ; tp->tm_min = atoi(buf) ; goto check ; } sp = dstring(buf,sp) ; sp = skipw(sp) ; if(*sp == '/') /* must be '7/12/83' */ { if((tp->tm_mon = atoi(buf) - 1) < 0 || (tp->tm_mon > 11)) { tp->tm_mon = FALSE ; goto badmon ; } sp = skipw(++sp) ; if(!isdigit(*sp)) goto badday ; sp = dstring(buf,sp) ; tp->tm_mday = atoi(buf) ; sp = skipw(sp) ; if(*sp != '/') goto badyr ; sp = skipw(++sp) ; if(!isdigit(*sp)) goto badyr ; sp = dstring(buf,sp) ; tp->tm_year = atoi(buf) ; sp = gtime(sp,tp) ; } else { /* * must be '12 jul 83' */ tp->tm_mday = atoi(buf) ; sp = extract(buf,sp) ; if((tp->tm_mon = find(buf,months)) < 0) goto badmon ; if(*sp == '.') ++sp ; sp = skipw(sp) ; if(!isdigit(*sp)) goto badyr ; sp = dstring(buf,sp) ; tp->tm_year = atoi(buf) ; sp = gtime(sp,tp) ; } } else { int flag = 0 ; /* used to indicate looking for UNIX style */ /* * either 'jul 12 83' or (UNIX) Wed jul 12 18:33 EST 1983 */ sp = extract(buf,sp) ; if(find(buf,dow) > 0) { sp = extract(buf,sp) ; ++flag ; } if((tp->tm_mon = find(buf,months)) < 0) goto badmon ; if(*sp == '.') ++sp ; sp = skipw(sp) ; if(!isdigit(*sp)) goto badday ; sp = dstring(buf,sp) ; tp->tm_mday = atoi(buf) ; sp = skipw(sp) ; if(*sp == ',') sp++ ; sp = skipw(sp) ; if(flag) sp = skipw(gtime(sp,tp)) ; if(!isdigit(*sp)) goto badyr ; sp = dstring(buf,sp) ; tp->tm_year = atoi(buf) ; if(!flag) sp = gtime(sp,tp) ; } check: /* * check for ridiculous numbers */ if(tp->tm_mday < 1) goto badday ; if(tp->tm_mday > mdays[tp->tm_mon]) if(!((tp->tm_mon == 1) && /* check for Feb 29 */ (tp->tm_mday == 29) && (days(tp->tm_year) == 365) )) goto badday ; if(tp->tm_year >= 1900) tp->tm_year -= 1900 ; if(tp->tm_hour > 23) { tp->tm_hour = FALSE ; return(sp) ; } if(tp->tm_min > 59) { tp->tm_hour = FALSE ; return(sp) ; } if(tp->tm_sec > 59) { tp->tm_sec = FALSE ; return(sp) ; } /* * fill in day of year, day of week (these calls must be * in this order as dowk() needs doyr() */ doyr(tp) ; dowk(tp) ; /* * all done ! */ return(NULL) ; badday : tp->tm_mday = FALSE ; return(sp) ; badmon : return(sp) ; badyr : tp->tm_year = FALSE ; return(sp) ; } /* * gtime() -- get hh:mm:ss or equivalent into a tm struct. */ char * gtime(sp,tp) register char *sp ; register struct tm *tp ; { char buf[MAXTOK],*cp ; sp = skipw(sp) ; if(isdigit(*sp)) { sp = dstring(buf,sp) ; tp->tm_hour = atoi(buf) ; sp = skipw(sp) ; if(*sp == ':') sp = skipw(++sp) ; else goto out ; if(isdigit(*sp)) { sp = dstring(buf,sp) ; tp->tm_min = atoi(buf) ; sp = skipw(sp) ; if(*sp == ':') sp = skipw(++sp) ; else goto out ; if(isdigit(*sp)) { sp = dstring(buf,sp) ; tp->tm_sec = atoi(buf) ; } } } out : sp = skipw(sp) ; if(isalpha(*sp)) /* PM:AM or time zone or both */ { cp = extract(buf,sp) ; if(strcmp(buf,"am") == 0 || strcmp(buf,"pm") == 0) { if(buf[0] == 'p' && tp->tm_hour < 12) tp->tm_hour += 12 ; sp = cp = skipw(cp) ; cp = extract(buf,cp) ; } if(lookup(buf,tz)) { if(buf[1] == 'd') tp->tm_isdst++ ; sp = skipw(cp) ; } } return (sp); } /* * days() -- how many days were in a year. * * Ok, you were all wondering so here it is folks... * THE LEAP YEAR CALCULATION * note: does not take into account 1752. */ days(y) register int y ; { if(y < 1970) y += 1900 ; if(((y % 4) == 0) && ( (y % 100) || ((y % 400)==0) )) y = 366 ; else y = 365 ; return(y) ; } /* * jan1() -- return day of the week of jan 1 of given year */ jan1(yr) { register y, d; /* * normal gregorian calendar * one extra day per four years */ y = yr; d = 4+y+(y+3)/4; /* * julian calendar * regular gregorian * less three days per 400 */ if(y > 1800) { d -= (y-1701)/100; d += (y-1601)/400; } /* * take care of weirdness at 1752. */ if(y > 1752) d += 3; return(d%7); } /* * dowk() -- insert day of week given year and day of year into tm struct. */ dowk(tp) register struct tm *tp ; { tp->tm_wday = (jan1(tp->tm_year+1900) + tp->tm_yday) % 7 ; } /* * doyr() -- insert partial day of year given yr and mon into tm struct. */ doyr(tp) register struct tm *tp ; { register int i,j ; j = ((tp->tm_mon > 1) && (days(tp->tm_year) == 366)) ? 1 : 0 ; for(i=1 ; i < tp->tm_mon ; i++) j += mdays[i-1] ; tp->tm_yday = j + tp->tm_mday - 1 ; } /*---------------------------------------------------------------- * * tm_to_time related * */ /* * leap() -- Return 1 if `y' is a leap year, 0 otherwise. */ static int leap (y) int y; { y += 1900; if (y % 400 == 0) return (1); if (y % 100 == 0) return (0); return (y % 4 == 0); } /* * ndays() -- number of days since UNIX epoch and time in a tm struct. */ static int ndays (p) struct tm *p; { register n = p->tm_mday; register m, y; register char *md = "\37\34\37\36\37\36\37\37\36\37\36\37"; for (y = 70; y < p->tm_year; ++y) { n += 365; if (leap (y)) ++n; } for (m = 0; m < p->tm_mon; ++m) n += md[m] + (m == 1 && leap (y)); return (n); } /* * tm_to_time() -- Convert a tm struct to a time_t. * * returns 0 if the time is before the UNIX epoch, 1/1/70 00:00:00 */ time_t tm_to_time (tp) struct tm *tp; { register int m1, m2; time_t t; struct tm otm; /* special case date before epoch */ if( tp->tm_year < 70) return(0); t = (ndays (tp) - 1) * 86400L + tp->tm_hour * 3600L + tp->tm_min * 60 + tp->tm_sec; /* * Now the hard part -- correct for the time zone: */ otm = *tp; tp = localtime (&t); m1 = tp->tm_hour * 60 + tp->tm_min; m2 = otm.tm_hour * 60 + otm.tm_min; t -= ((m1 - m2 + 720 + 1440) % 1440 - 720) * 60L; return (t); } /*---------------------------------------------------------------- * * Test program related * */ #if DEBUG /* * test driver * translates first arg from command line (argv[1]) * and dumps out structure built. */ usage(sp) char *sp ; { fprintf(stderr,"Usage: %s date\n",sp) ; exit(1) ; } /* * main() -- test the gdate and tm_to_time routines */ main(argc,argv) int argc ; char **argv ; { char *cp ; struct tm tm ; time_t t,t2 ; char *asctime(); char *ctime(); if(argc != 2) usage(*argv) ; if((cp = gdate(*++argv,&tm)) != NULL) printf("error: %s (%s)\n",*argv,cp) ; printf("year : %d month: %d day: %d\n", tm.tm_year,tm.tm_mon,tm.tm_mday); printf("day of month: %d hour: %d minute: %d second: %d\n", tm.tm_mday,tm.tm_hour,tm.tm_min,tm.tm_sec) ; printf("day of year: %d day of week: %d dst: %d\n", tm.tm_yday, tm.tm_wday, tm.tm_isdst) ; t = time(NULL) ; t2 = tm_to_time(&tm) ; printf("time_t of now %d, of arg %d\n",t, t2 ) ; printf("Now: %s", ctime(&t) ); printf("Arg: %s", ctime(&t2) ); exit(0) ; } #endif /* DEBUG */