home *** CD-ROM | disk | FTP | other *** search
- /*
- MRDates - AmigaDOS date support routines.
- 07/03/88
-
- This package is a hybrid of code from Thad Floryan, Doug Merrit and
- myself. I wanted a reliable set of AmigaDOS date conversion routines
- and this combination seems to work pretty well. The star of the show
- here is Thad's algorithm for converting the "days elapsed" field of
- an AmigaDOS DateStamp, using an intermediate Julian date format. I
- lifted/embellished some of the data structures from Doug's ShowDate
- package and wrote the DateToDS function.
-
- History: (most recent change first)
-
- 12/31/88 -MRR-
- StrToDS was not handling the null string properly.
-
- 11/01/88 -MRR- Added Unix-style documentation.
-
- 07/03/88 - Changed some names:
- Str2DS => StrToDS
- DS2Str => DSToStr
- */
-
- #define MRDATES
- #include "MRDates.h"
- #include <exec/types.h>
- #include <ctype.h>
-
-
- char *index();
-
- #define DATE_SEPARATORS "/:-."
- #define MINS_PER_HOUR 60
- #define SECS_PER_MIN 60
- #define SECS_PER_HOUR (SECS_PER_MIN * MINS_PER_HOUR)
- #define TICS_PER_SEC 50
-
- #define YEARS_PER_CENTURY 100
-
-
- /*
- definitions to calculate current date
- */
- #define FEB 1 /* index of feb. in table (for leap years) */
- #define DAYS_PER_WEEK 7
- #define DAYS_PER_YEAR 365
- #define YEARS_PER_LEAP 4
- #define START_YEAR 1978
- #define FIRST_LEAP_YEAR 1980
- #define LEAP_ADJUST (FIRST_LEAP_YEAR - START_YEAR)
- #define LEAP_FEB_DAYS 29
- #define NORM_FEB_DAYS 28
- #define IsLeap(N) (((N) % YEARS_PER_LEAP) ? 0 : 1)
-
-
- /* FUNCTION
- DSToDate - convert a DateStamp to a DATE.
-
- SYNOPSIS
- int DSToDate(dateStamp, date)
- struct DateStamp *dateStamp;
- DATE *date;
-
- DESCRIPTION
- Extracts the date components from an AmigaDOS datestamp.
- The calculations herein use the following assertions:
-
- 146097 = number of days in 400 years per 400 * 365.2425 = 146097.00
- 36524 = number of days in 100 years per 100 * 365.2425 = 36524.25
- 1461 = number of days in 4 years per 4 * 365.2425 = 1460.97
-
- AUTHOR
- Thad Floryan, 12-NOV-85
- Mods by Mark Rinfret, 04-JUL-88
-
- SEE ALSO
- Include file MRDates.h.
-
- */
-
- #define DDELTA 722449 /* days from Jan.1,0000 to Jan.1,1978 */
-
- static int mthvec[] =
- {-1, -1, 30, 58, 89, 119, 150, 180, 211, 242, 272, 303, 333, 364};
-
- int
- DSToDate(ds, date)
- long *ds; DATE *date;
-
- {
-
- long jdate, day0, day1, day2, day3;
- long year, month, day, temp;
-
- jdate = ds[0] + DDELTA; /* adjust internal date to Julian */
-
- year = (jdate / 146097) * 400;
- day0 = day1 = jdate %= 146097;
- year += (jdate / 36524) * 100;
- day2 = day1 %= 36524;
- year += (day2 / 1461) * 4;
- day3 = day1 %= 1461;
- year += day3 / 365;
- month = 1 + (day1 %= 365);
- day = month % 30;
- month /= 30;
-
- if ( ( day3 >= 59 && day0 < 59 ) ||
- ( day3 < 59 && (day2 >= 59 || day0 < 59) ) )
- ++day1;
-
- if (day1 > mthvec[1 + month]) ++month;
- day = day1 - mthvec[month];
- date->Dyear = year;
- date->Dmonth = month;
- date->Dday = day;
- date->Dweekday = ds[0] % DAYS_PER_WEEK;
-
- temp = ds[1]; /* get ds_Minute value */
- date->Dhour = temp / MINS_PER_HOUR;
- date->Dminute = temp % MINS_PER_HOUR;
- date->Dsecond = ds[2] / TICS_PER_SEC;
- return 0;
- }
-
- /* FUNCTION
- DateToDS(date, dateStamp)
-
- SYNOPSIS
- void DateToDS(date, dateStamp)
- DATE *date;
- struct DateStamp *dateStamp;
-
- DESCRIPTION
- DateToDS converts the special DATE format to a DateStamp.
- */
-
- DateToDS(date, ds)
- DATE *date; long *ds;
- {
- long daysElapsed, yearsElapsed, leapYears, thisMonth, thisDay, thisYear;
- int month;
-
- /* Note the special handling for year < START_YEAR. In this case,
- * the other fields are not even checked - the user just gets the
- * "start of time".
- */
- if ((thisYear = date->Dyear) < START_YEAR) {
- ds[0] = ds[1] = ds[2] = 0;
- return;
- }
- if (IsLeap(thisYear))
- calendar[FEB].Mdays = LEAP_FEB_DAYS;
-
- thisDay = date->Dday - 1;
- thisMonth = date->Dmonth -1;
- yearsElapsed = thisYear - START_YEAR;
- leapYears = (yearsElapsed + LEAP_ADJUST -1) / YEARS_PER_LEAP;
- daysElapsed = (yearsElapsed * DAYS_PER_YEAR) + leapYears;
- for (month = 0; month < thisMonth; ++month)
- daysElapsed += calendar[month].Mdays;
- daysElapsed += thisDay;
- calendar[FEB].Mdays = NORM_FEB_DAYS;
- ds[0] = daysElapsed;
- ds[1] = date->Dhour * MINS_PER_HOUR + date->Dminute;
- ds[2] = date->Dsecond * TICS_PER_SEC;
- }
- /* FUNCTION
- CompareDS - compare two DateStamp values.
-
- SYNOPSIS
- int CompareDS(date1, date2)
- struct DateStamp *date1, *date2;
-
- DESCRIPTION
- CompareDS performs an ordered comparison between two DateStamp
- values, returning the following result codes:
-
- -1 => date1 < date2
- 0 => date1 == date2
- 1 => date1 > date2
-
- 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 */
- }
-
- /* FUNCTION
- DSToStr - convert a DateStamp to a formatted string.
-
- SYNOPSIS
- void DSToStr(str,fmt,d)
- char *str, *fmt;
- struct DateStamp *d;
-
- DESCRIPTION
- DSToStr works a little like sprintf. It converts a DateStamp
- to an ascii formatted string. The formatting style is dependent
- upon the contents of the format string, fmt, passed to this
- function.
-
- The content 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
-
- */
- void
- DSToStr(str,fmt,d)
- char *str, *fmt; long *d;
- {
- DATE date;
- char fc,*fs,*out;
- USHORT ivalue;
- char new_fmt[256]; /* make it big to be "safe" */
- USHORT new_fmt_lng;
- char *svalue;
-
- DSToDate(d, &date); /* convert DateStamp to DATE 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.Dyear % 100;
- 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.Dyear;
- goto write_int;
-
- case 'm': /* month */
- ivalue = date.Dmonth;
- goto write_int;
-
- case 'M': /* month name */
- svalue = calendar[date.Dmonth - 1].Mname;
- 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.Dday;
- goto write_int;
-
- case 'D': /* day name */
- svalue = dayNames[d[0] % DAYS_PER_WEEK];
- goto write_str;
-
- case 'h': /* hour */
- ivalue = date.Dhour;
- goto write_int;
-
- case 'H': /* hour in 12 hour notation */
- ivalue = date.Dhour;
- if (ivalue >= 12) ivalue -= 12;
- goto write_int;
-
- case 'i': /* AM/PM indicator */
- case 'I':
- if (date.Dhour >= 12)
- svalue = "PM";
- else
- svalue = "AM";
- goto write_str;
-
- case 'n': /* minutes */
- case 'N':
- ivalue = date.Dminute;
- goto write_int;
-
- case 's': /* seconds */
- case 'S':
- ivalue = date.Dsecond;
- 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 */
- }
-
- /* FUNCTION
- StrToDS - convert a string to a DateStamp.
-
- SYNOPSIS
- int StrToDS(string, date)
- char *string;
- struct DateStamp *date;
-
- DESCRIPTION
- StrToDS expects its string argument to contain a date in
- MM/DD/YY HH:MM:SS format. The time portion is optional.
- StrToDS will attempt to convert the string to a DateStamp
- representation. If successful, it will return 0. On
- failure, a 1 is returned.
-
- */
-
- int
- StrToDS(str, d)
- char *str; long *d;
- {
- register char c;
- int count;
- int i, item;
- DATE date; /* 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;
- }
- else if (! index(DATE_SEPARATORS, c) )
- goto bad_value; /* Illegal character - quit. */
- } /* end while */
- if (item) { /* Getting time? */
- date.Dhour = values[0];
- date.Dminute = values[1];
- date.Dsecond = 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;
- date.Dmonth = values[0];
- date.Dday = values[1];
- date.Dyear = values[2];
- if (date.Dyear == 0) {
- date.Dyear = START_YEAR;
- date.Dday = 1;
- }
- else {
- if (date.Dyear < (START_YEAR - 1900) )
- date.Dyear += 100;
- date.Dyear += 1900;
- }
- }
- } /* end for */
- DateToDS(&date, d);
- return 0;
- } /* StrToDS */
-
-
- #ifdef DEBUG
- #include "stdio.h"
- main(ac, av)
- int ac;
- char **av;
- {
- long datestamp[3]; /* A little dangerous with Aztec */
- long datestamp2[3];
- DATE date, oldDate;
- long day, lastDay;
- int errors = 0;
-
- /*
- * display results from DateStamp() (hours:minutes:seconds)
- */
- DateStamp(datestamp);
-
- /*
- * display results from DSToDate() (e.g. "03-May-88")
- */
- DSToDate(datestamp, &date);
- printf("Current date: %02d-%s-%02d\n",
- date.Dday, calendar[ date.Dmonth - 1].Mname,
- (date.Dyear % YEARS_PER_CENTURY));
-
- printf("Current time: %02d:%02d:%02d\n",
- date.Dhour, date.Dminute, date.Dsecond);
-
- printf("\nDoing sanity check through year 2000...\n\t");
- lastDay = (2000L - START_YEAR) * 365L;
- lastDay += (2000L - START_YEAR) / YEARS_PER_LEAP;
- for (day = 0; day <= lastDay; ++day) {
- if (day % 1000 == 0) {
- printf(" %ld", day);
- fflush(stdout);
- }
- datestamp[0] = day;
- datestamp[1] = MINS_PER_HOUR - 1;
- datestamp[2] = TICS_PER_SEC * (SECS_PER_MIN - 1);
- DSToDate(datestamp, &date);
- if (day && date == oldDate) {
- printf("Got same date for days %d, %d: %02d-%s-%02d\n",
- day - 1, day,
- date.Dday,
- calendar[ date.Dmonth - 1 ].Mname,
- (date.Dyear % YEARS_PER_CENTURY));
-
- if (++errors == 10)
- exit(1);
- }
- DateToDS(&date, datestamp2);
- if (day != datestamp2[0]) {
- printf("\nConversion mismatch at day %ld!\n", day);
- printf("\tBad value = %ld", datestamp2[0]);
- printf("\tDate: %02d-%s-%02d\n",
- date.Dday,
- calendar[ date.Dmonth -1 ].Mname,
- (date.Dyear % YEARS_PER_CENTURY));
- if (++errors == 10)
- exit(1);
- }
- oldDate = date;
- }
- printf("\nSanity check passed.\n");
- } /* main() */
- #endif
-
-