/* General routines to provide date support for the DateStamp * date format. * * Author: Mark R. Rinfret (mark@unisec.usi.com) * Date: 07/18/87 * * This source is released to the public domain by the author, without * restrictions. However, it is requested that you give credit where * credit is due and share any bug fixes or enhancements with him. * * History: (most recent change first) * * 08/20/87 -MRR- Gack! I wrote this? In the interests of orthogonality, * I have replaced SetDateStamp with PackDS, the inverse * of UnpackDS. I have also renamed the package MRDates * to provide a unique name, hopefully relieving conflicts * with other packages providing date/time functions. The * UnpackedDS type is now defined in MRDates.h and can * be included by modules which require PackDS and UnpackDS. */ /* The following #define MUST be set to inhibit certain declarations in * the include file MRDates.h: */ #define MRDATES #include #include #include #include #include "MRDates.h" /* #define DEBUG */ char *daynames[] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" }; USHORT monthdays[12] = {0,31,59,90,120,151,181,212,243,273,304,334}; char *monthnames[12] = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }; /* Compare two DateStamp values. * Called with: * d1,d2: pointers to DateStamp structs * * Returns: * < 0 => d1 < d2 * 0 => d1 == d2 * > 0 => d1 > d2 * * Note: * This routine makes an assumption about the DateStamp structure, * specifically that it can be viewed as an array of 3 long integers * in days, minutes and ticks order. */ int CompareDS(d1, d2) long *d1, *d2; { USHORT i; long compare; for (i = 0; i < 3; ++i) { if (compare = (d1[i] - d2[i])) { if (compare < 0) return -1; return 1; } } return 0; /* dates match */ } /* Convert a DateStamp to a formatted string. * Called with: * fmt: format string * The format of the format string is very similar to that * for printf, with the exception that the following letters * have special significance: * y => year minus 1900 * Y => full year value * m => month value as integer * M => month name * d => day of month (1..31) * D => day name ("Monday".."Sunday") * h => hour in twenty-four hour notation * H => hour in twelve hour notation * i => 12 hour indicator for H notation (AM or PM) * I => same as i * n => minutes (sorry...conflict with m = months) * N => same as n * s => seconds * S => same as s * * All other characters are passed through as part of the normal * formatting process. The following are some examples with * Saturday, July 18, 1987, 13:53 as an input date: * * "%y/%m/%d" => 87/7/18 * "%02m/%02d/%2y" => 07/18/87 * "%D, %M %d, %Y" => Saturday, July 18, 1987 * "%02H:%02m i" => 01:53 PM * "Time now: %h%m" => Time now: 13:53 * * str: string to write date on * d: pointer to DateStamp structure * */ void DS2Str(str,fmt,d) char *str, *fmt; struct DateStamp *d; { UnpackedDS date; char fc,*fs,*out; USHORT ivalue; char new_fmt[256]; /* make it big to be "safe" */ USHORT new_fmt_lng; char *svalue; UnpackDS(d, &date); /* convert DateStamp to unpacked format */ *str = '\0'; /* insure output is empty */ out = str; fs = fmt; /* make copy of format string pointer */ while (fc = *fs++) { /* get format characters */ if (fc == '%') { /* formatting meta-character? */ new_fmt_lng = 0; new_fmt[new_fmt_lng++] = fc; /* copy width information */ while (isdigit(fc = *fs++) || fc == '-') new_fmt[new_fmt_lng++] = fc; switch (fc) { /* what are we trying to do? */ case 'y': /* year - 1980 */ ivalue = date.year - 1900; write_int: new_fmt[new_fmt_lng++] = 'd'; new_fmt[new_fmt_lng] = '\0'; sprintf(out,new_fmt,ivalue); out = str + strlen(str); break; case 'Y': /* full year value */ ivalue = date.year; goto write_int; case 'm': /* month */ ivalue = date.month; goto write_int; case 'M': /* month name */ svalue = monthnames[date.month - 1]; write_str: new_fmt[new_fmt_lng++] = 's'; new_fmt[new_fmt_lng] = '\0'; sprintf(out,new_fmt,svalue); out = str + strlen(str); break; case 'd': /* day */ ivalue = date.day; goto write_int; case 'D': /* day name */ svalue = daynames[d->ds_Days % 7]; goto write_str; case 'h': /* hour */ ivalue = date.hour; goto write_int; case 'H': /* hour in 12 hour notation */ ivalue = date.hour; if (ivalue >= 12) ivalue -= 12; goto write_int; case 'i': /* AM/PM indicator */ case 'I': if (date.hour >= 12) svalue = "PM"; else svalue = "AM"; goto write_str; case 'n': /* minutes */ case 'N': ivalue = date.minute; goto write_int; case 's': /* seconds */ case 'S': ivalue = date.second; goto write_int; default: /* We are in deep caca - don't know what to do with this * format character. Copy the raw format string to the * output as debugging information. */ new_fmt[new_fmt_lng++] = fc; new_fmt[new_fmt_lng] = '\0'; strcat(out, new_fmt); out = out + strlen(out); /* advance string pointer */ break; } } else *out++ = fc; /* copy literal character */ } *out = '\0'; /* terminating null */ } /* Convert a string to a DateStamp. * Called with: * str: string containing date in MM/DD/YY format * d: pointer to DateStamp structure * Returns: * status code (0 => success, 1 => failure) */ int Str2DS(str, d) char *str; struct DateStamp *d; { register char c; int count; int i, item; UnpackedDS upd; /* unpacked DateStamp */ char *s; int values[3]; int value; s = str; for (item = 0; item < 2; ++item) { /* item = date, then time */ for (i = 0; i < 3; ++i) values[i] = 0; count = 0; while (c = *s++) { /* get date value */ if (c <= ' ') break; if (isdigit(c)) { value = 0; do { value = value*10 + c - '0'; c = *s++; } while (isdigit(c)); if (count == 3) { bad_value: #ifdef DEBUG puts("Error in date-time format.\n"); printf("at %s: values(%d) = %d, %d, %d\n", s, count, values[0], values[1], values[2]); #endif return 1; } values[count++] = value; if (c <= ' ') break; } } /* end while */ if (item) { /* getting time? */ upd.hour = values[0]; upd.minute = values[1]; upd.second = values[2]; } else { /* getting date? */ /* It's OK to have a null date string, but it's not OK to specify only * 1 or 2 of the date components. */ if (count && count != 3) goto bad_value; upd.month = values[0]; upd.day = values[1]; upd.year = values[2]; } } /* end for */ PackDS(d,&upd); return 0; } /* Set a DateStamp structure, given the date/time components. * Called with: * d: pointer to DateStamp * upd: pointer to UnpackedDS */ PackDS(d,upd) struct DateStamp *d; UnpackedDS *upd; { USHORT leapyear; short year,month,day,hour,minute,second; year = upd->year; /* copy date components to locals */ month = upd->month; day = upd->day; hour = upd->hour; minute = upd->minute; second = upd->second; if (year > 1900) year = year - 1900; leapyear = (year % 4 ? 0 : 1); year = year - 78; if (month < 1 || month > 12) /* somebody goofed? */ month = 1; day = day - 1 + monthdays[month-1]; if (leapyear && (month > 2)) ++day; d->ds_Days = year * 365 + (year + 1) / 4 + day; d->ds_Minute = hour * 60 + minute; d->ds_Tick = second * TICKS_PER_SECOND; } /* Unpack a DateStamp structure into an UnpackedDS structure. * Called with: * ds: pointer to DateStamp structure * du: pointer to UnpackedDS structure */ UnpackDS(ds, du) struct DateStamp *ds; UnpackedDS *du; { USHORT i, leap_years, leap, temp, test_value; du->year = ds->ds_Days / 365 + 1978; /* is current year a leapyear? */ leap = ( (du->year % 4) == 0); /* how many leap years since "beginning of time"? */ leap_years = (du->year - 1976 - 1) / 4; /* get days remaining in year */ temp = ds->ds_Days % 365 - leap_years; /* find month */ du->month = 0; du->day = 0; for (i = 11; i >= 0; --i) { test_value = monthdays[i]; if (i > 2) test_value += leap; if (temp >= test_value) { du->month = i + 1; du->day = temp - test_value + 1; break; } } du->hour = ds->ds_Minute / 60; du->minute = ds->ds_Minute % 60; du->second = ds->ds_Tick / TICKS_PER_SECOND; } #ifdef DEBUG main() { int compflag; char datestr[81], instr[81]; struct DateStamp *ds, *now; UnpackedDS du; now = (struct DateStamp *) AllocMem((long) sizeof(struct DateStamp), MEMF_PUBLIC); ds = (struct DateStamp *) AllocMem((long) sizeof(struct DateStamp), MEMF_PUBLIC); puts("Enter a date string and I will convert it. To quit, hit RETURN"); while (1) { DateStamp(now); UnpackDS(now, &du); printf("\nCurrent date and time: %02d/%02d/%02d %02d:%02d:%02d\n", du.month,du.day,du.year,du.hour,du.minute,du.second); puts("\nEnter the date [and time]:"); gets(instr); if (*instr == '\0') break; if (Str2DS(instr,ds)) puts("Error encountered in input string"); else { DS2Str(datestr, "%02m/%02d/%02y %02h:%02n:%02s", ds); puts(datestr); DS2Str(datestr, "%D, %M %d, %Y", ds); puts(datestr); DS2Str(datestr, "The time entered is %02H:%02N %i", ds); puts(datestr); compflag = CompareDS(ds,now); printf("The date input is "); if (compflag < 0) printf("earlier than"); else if (compflag == 0) printf("the same as"); else printf("later than"); puts(" the current date."); } } FreeMem(ds, (long) sizeof(struct DateStamp)); FreeMem(now, (long) sizeof(struct DateStamp)); } #endif