home *** CD-ROM | disk | FTP | other *** search
- UNIT Dates2; {Version 1.02 updated 14th November 1988}
-
-
- {***************************************************************************
- * *
- * Copyright 1988 Trevor J Carlsen *
- * Rovert Software Consulting Services *
- * PO Box 568 *
- * Port Hedland Western Australia 6721 *
- * *
- * *
- * *
- * All these routines are based on the global type Date which is *
- * globally declared as a longint. As all calculations are in seconds *
- * the valid range of date/time is restricted to 00:00:00 01-01-1981 *
- * until 23:59:59 31-12-2048. *
- * *
- * This unit is functionally identical to DATES.PAS but has a function *
- * Zstr added to replace the form function and thus make it independent *
- * of the Turbo Professional package. *
- * *
- ***************************************************************************}
-
- interface
-
- TYPE
- Date = longint;
- DaysOfWeek = array[0..6] of string[9];
- months = array[1..12] of string[9];
-
- CONST
- WeekDay : DaysOfWeek = ('Sunday','Monday','Tuesday','Wednesday',
- 'Thursday','Friday','Saturday');
- Amonth : months = ('January','February','March','April','May','June',
- 'July','August','September','October','November','December');
- {-----------------------------------------------------------------------------}
-
- FUNCTION Zstr(numb : byte): string;
- {-Adds a leading zero to a single digit number
-
- ------------------------------------------------------------------------------}
-
- FUNCTION DayOfTheWeek(pd : date): byte;
- { Returns the day of the week for any date Sunday = 0 .. Sat = 6
-
- ------------------------------------------------------------------------------}
-
- PROCEDURE PackDateAndTime(VAR pd : date; yr,mth,d,hr,m,s : word);
- { This procedure packs the Date and time into a 4 byte long integer using
- a different method to that used by DOS and the TP4 compiler. Each date
- and time are recorded as the number of elapsed seconds since 01-01-1981.
- The valid range is from 00:00:00 01-01-1988 until 23:59:59 31-12-2048.
- This method enables elapsed times and times between 2 times to be more
- easily calculated. It is also fully "sortable".
-
- ------------------------------------------------------------------------------}
-
- PROCEDURE UnPackDateAndTime(VAR yr,mth,d,hr,m,s : word; pd : date);
- { Unpacks a packed date from a long integer created by PackDateAndTime into
- its component parts.
-
- ------------------------------------------------------------------------------}
-
- PROCEDURE ParseDateTime(st : string; fmt : byte;
- VAR yr,mth,d,hr,m,s : word; VAR code : byte);
- { Breaks a string into its component parts for use by PackDateAndTime and
- ValidDate. I have included 4 formats and used a format flag.
- fmt = 0 dd-mm-yyyy hh:mm:ss
- fmt = 1 mm-dd-yyyy hh:mm:ss (must keep our American friends happy!)
- fmt = 2 ddmmyyyy hhmmss (no separators makes for easier data entry)
- fmt = 3 mmddyyyy hhmmss
- code is used to pass an error back to the calling routine. Any error which
- prevents the proper parsing of a string will set this variable to a non
- zero value.
-
- ------------------------------------------------------------------------------}
-
- FUNCTION ValidDate(yr,mth,d,hr,m,s : word; VAR errorcode : byte): boolean;
- { Validates the date and time data to ensure no out of range errors can
- occur and returns an error code to the calling procedure. A errorcode of
- zero is returned if no invalid parameter is detected. Errorcodes are as
- follows:
- Year out of range (<1981 or > 2048) bit 0 of errorcode is set.
- Month < 1 or > 12 bit 1 of errorcode is set.
- Day < 1 or > 31 bit 2 of errorcode is set.
- Day out of range for month bit 2 of errorcode is set.
- Hour < 0 or > 23 bit 3 of errorcode is set.
- Minute < 0 or > 59 bit 4 of errorcode is set.
- Second < 0 or > 59 bit 5 of errorcode is set.
- Error from ParseDateTime bit 7 of errorcode is set.
- Using the method indicated allows the calling routine to detect what
- type of error caused ValidDate to return false. It also means that a
- combination of errors can be detected.
-
- ------------------------------------------------------------------------------}
-
- FUNCTION UnPack2Str(pd : date; fmt : byte): string;
-
- { Unpacks a time and date from a long integer into a string of a selected
- format
- for the time of 11:59:59PM on the 31st December 1987
- fmt = 0 returns 23:59:59 31-12-1987
- 1 23:59:59 12-31-1987
- 2 11:59pm 31-12-1987
- 3 11:59pm 12-12-1987
- 4 23:59:59 December 31, 1987
- 5 11:59pm December 31, 1987
- 6 23:59, Saturday, December 31, 1987
- 7 11:59pm, Saturday, December 31, 1987
- 8 31121987 235959
- 10 11:59:59pm, Saturday, December 31, 1987
- 11 23:59:59
-
- ------------------------------------------------------------------------------}
-
- FUNCTION TimeStr(pd :date): string;
- { returns the current time as a string - equivalent to using UnPack2Str option
- 11.
-
- ------------------------------------------------------------------------------}
-
- FUNCTION NumbOfDaysInMth(y,m : word): byte;
- { returns the number of days in any month
-
- ------------------------------------------------------------------------------}
-
- PROCEDURE AddMonth(VAR pd : date; incr,day : byte);
- { Adds incr calendar months to a date.
- If the date being incremented has no exact equivalent in the target month
- then the last day of that month is substituted.
- ie. Incrementing the 31 Jan 1988 would result in 29 Feb 1988
- Conversely, if incrementing a short month and it is desired for a day other
- than the direct equivalent, set day to the desired day.
- ie. Incrementing 29 Feb 1988 and the last day of march is required set
- day to 31.
- Setting day to 31 will ALWAYS result in the incremented date being the last
- day of the month.
- Setting day to 30 will ALWAYS result in the incremented date being the 30th
- day of the month except in February when it will be either the 29th or 28th.
- As from version 1.02 this function will not permit pd to be outside the
- range permitted.
-
- ------------------------------------------------------------------------------}
-
- PROCEDURE DecMonth(VAR pd : date; decr,day : byte);
- { Decrements a date by decr calendar months
- The same comments and rules apply as for AddMonth
-
- ------------------------------------------------------------------------------}
-
- PROCEDURE AddYear(VAR pd : date; incr,day : byte);
- { Adds one year to a date
- The same comments and rules apply as for AddMonth where February is the
- month involved.
-
- ------------------------------------------------------------------------------}
-
-
-
-
-
- {=============================================================================}
-
- implementation
-
- CONST
- TDays : array[0..1,0..12] of word =
- ((0,31,59,90,120,151,181,212,243,273,304,334,365),
- (0,31,60,91,121,152,182,213,244,274,305,335,366));
-
- FUNCTION Zstr(numb : byte): string;
- {-simple function to add a leading zero to a single digit number}
- VAR temp : string[2];
- begin
- Str(numb, temp);
- if length(temp) = 1 then temp := '0'+ temp;
- Zstr := temp;
- end; {Zstr}
-
- FUNCTION DayOfTheWeek(pd : date): byte;
- begin
- DayOfTheWeek := (((pd div 86400) mod 7)+4) mod 7;
- end;
-
- PROCEDURE PackDateAndTime(VAR pd : date; yr,mth,d,hr,m,s : word);
- VAR
- total, temp : date;
- lyr : byte;
- begin
- lyr := ord(yr mod 4 = 0);
- dec(yr,1981);
- total := s + (m * 60) + (date(hr) * 3600);
- temp := date(yr * word(365) + (yr div 4));
- inc(temp,TDays[lyr][mth-1]);
- inc(temp,d-1);
- pd := total + (temp * 86400);
- end; {PackTimeAndDate}
-
- PROCEDURE UnPackDateAndTime(VAR yr,mth,d,hr,m,s : word; pd : date);
- VAR
- julian : word;
- temp : date;
- lyr : byte;
- begin
- d := word(pd div 86400 + 1);
- temp := pd mod 86400;
- hr := word(temp div 3600);
- temp := temp mod 3600;
- m := word(temp div 60);
- s := word(temp mod 60);
- yr := (date(d) * 4) div 1461;
- julian := d - (yr * 365 + (yr div 4));
- inc(julian,366 * ord(julian = 0)); { make sure that last day of a }
- inc(yr,1981 - ord(julian = 366)); { leap year is shown correctly }
- lyr := ord(yr mod 4 = 0);
- mth := 0;
- while julian > TDays[lyr][mth] do
- inc(mth);
- d := julian - TDays[lyr][mth-1];
- end;
-
- PROCEDURE ParseDateTime(st : string; fmt : byte;
- VAR yr,mth,d,hr,m,s : word;
- VAR code : byte);
- CONST
- offset : array[0..3,1..6] of byte = ((1,4,7,12,15,18),
- (4,1,7,12,15,18),
- (1,3,5,10,12,14),
- (3,1,5,10,12,14));
- VAR result : integer;
- begin
- code := 0;
- val(copy(st,offset[fmt][1],2),d,result);
- inc(code,result);
- val(copy(st,offset[fmt][2],2),mth,result);
- inc(code,result);
- val(copy(st,offset[fmt][3],4),yr,result);
- inc(code,result);
- val(copy(st,offset[fmt][4],2),hr,result);
- inc(code,result);
- val(copy(st,offset[fmt][5],2),m,result);
- inc(code,result);
- val(copy(st,offset[fmt][6],2),s,result);
- inc(code,result);
- end;
-
- FUNCTION ValidDate(yr,mth,d,hr,m,s : word; VAR errorcode : byte): boolean;
- VAR code : byte;
- begin
- code := errorcode;
- errorcode := ord(code <> 0) * 128; {set high bit if error returned from
- parsedatetime routine}
- if (yr < 1981) or (yr > 2048) then errorcode := (errorcode or 1);
- if (d < 1) or (d > 31) then errorcode := (errorcode or 2);
- if (mth < 1) or (mth > 12) then errorcode := (errorcode or 4);
- case mth of
- 4,6,9,11: if d > 30 then errorcode := (errorcode or 2);
- 2: if d > (28 + ord((yr mod 4) = 0)) then
- errorcode := (errorcode or 2);
- end; {case}
- if (hr < 0) or (hr > 23) then errorcode := (errorcode or 8);
- if (m < 0) or (m > 59) then errorcode := (errorcode or 16);
- if (s < 0) or (s > 59) then errorcode := (errorcode or 32);
- ValidDate := (errorcode = 0);
- end;
-
- FUNCTION UnPack2Str(pd : date; fmt : byte): string;
- VAR tempstr : string;
- ampm : string[10];
- y : string[4];
- hr,m,s,yr,mth,d: word;
- begin
- tempstr := '';
- str(yr:4,y);
- UnPackDateAndTime(yr,mth,d,hr,m,s,pd);
- case fmt of
- 2,3,5,7,10:begin
- if (hr = 0) and (m = 0) and (s = 0) then begin
- ampm := ' midnight';
- hr := 12;
- end
- else if hr < 12 then ampm := 'am'
- else if (hr = 12) and (m = 0) and (s = 0) then ampm := ' noon'
- else ampm := 'pm';
- if hr > 12 then dec(hr,12);
- end;
- end; {case}
- case fmt of
- 11: tempstr := Zstr(hr)+':'+Zstr(m)+':'+Zstr(s);
- 0,1: begin
- tempstr := Zstr(hr)+':'+Zstr(m)+':'+Zstr(s)+' ';
- if fmt = 0 then
- tempstr := tempstr +
- Zstr(d)+'-'+Zstr(mth)+'-'+ y
- else
- tempstr := tempstr +
- Zstr(mth)+'-'+Zstr(d)+'-'+ y
- end;
- 2..7,10: begin
- if fmt <> 4 then begin
- tempstr := ampm;
- if fmt > 5 then tempstr := tempstr + ', '+
- WeekDay[DayOfTheWeek(pd)]+', ';
- end;
- if fmt = 10 then
- tempstr := Zstr(hr)+':'+Zstr(m)+':'+Zstr(s) + tempstr
- else tempstr := Zstr(hr)+':'+Zstr(m) + tempstr;
- case fmt of
- 2: tempstr := tempstr + Zstr(d)+'-'+Zstr(mth)+'-'+ y;
- 3: tempstr := tempstr + Zstr(mth)+'-'+Zstr(d)+'-'+ y;
- 4: tempstr := tempstr + Zstr(s) + ' ';
- 4,5,6,7,10: tempstr := tempstr + Amonth[mth]+' '+ Zstr(d) + ', '+ y;
- end; {case}
- end;
- 8: tempstr := Zstr(d)+Zstr(mth)+y+' '+
- Zstr(hr)+Zstr(m)+Zstr(s);
- end; {case}
- UnPack2Str := tempstr;
- end; {UnPack2Str}
-
- FUNCTION TimeStr(pd :date): string;
- CONST mask = '@#';
- VAR hr,m,s,yr,mth,d: word;
- begin
- UnPackDateAndTime(yr,mth,d,hr,m,s,pd);
- TimeStr := Zstr(hr)+':'+Zstr(m)+':'+Zstr(s);
- end; {TimeStr}
-
-
- FUNCTION NumbOfDaysInMth(y,m : word): byte;
- begin
- case m of
- 1,3,5,7,8,10,12: NumbOfDaysInMth := 31;
- 4,6,9,11 : NumbOfDaysInMth := 30;
- 2 : NumbOfDaysInMth := 28 + ord((y mod 4) = 0);
- end;
- end;
-
-
- PROCEDURE AddMonth(VAR pd : date; incr,day : byte);
- VAR yr,mth,d,hr,m,s : word;
- pdate : date;
- begin
- pdate := pd;
- UnPackDateAndTime(yr,mth,d,hr,m,s,pdate);
- inc(yr,incr div 12);
- incr := incr mod 12;
- inc(mth,incr);
- if mth > 12 then begin
- inc(yr,1);
- dec(mth,12);
- end;
- if yr > 2048 then begin
- yr := 2048;
- mth := 12;
- end;
- if day <> 0 then d := day;
- if d > NumbOfDaysInMth(yr,mth) then
- d := NumbOfDaysInMth(yr,mth);
- PackDateAndTime(pdate,yr,mth,d,hr,m,s);
- pd := pdate;
- end;
-
- PROCEDURE DecMonth(VAR pd : date; decr,day : byte);
- VAR yr,mth,d,hr,m,s : word;
- pdate : date;
- temp : integer;
- begin
- pdate := pd;
- UnPackDateAndTime(yr,mth,d,hr,m,s,pdate);
- dec(yr,decr div 12);
- decr := decr mod 12;
- temp := integer(mth);
- dec(temp,decr);
- if temp < 1 then begin
- dec(yr,1);
- inc(temp,12);
- end;
- mth := word(temp);
- if yr < 1981 then begin
- yr := 1981;
- mth := 1;
- end;
- if day <> 0 then d := day;
- if d > NumbOfDaysInMth(yr,mth) then
- d := NumbOfDaysInMth(yr,mth);
- PackDateAndTime(pdate,yr,mth,d,hr,m,s);
- pd := pdate;
- end;
-
- PROCEDURE AddYear(VAR pd : date; incr,day : byte);
- VAR yr,mth,d,hr,m,s : word;
- begin
- UnPackDateAndTime(yr,mth,d,hr,m,s,pd);
- inc(yr,incr);
- if day <> 0 then d := day;
- if d > NumbOfDaysInMth(yr,mth) then
- d := NumbOfDaysInMth(yr,mth);
- if yr > 2048 then yr := 2048;
- PackDateAndTime(pd,yr,mth,d,hr,m,s);
- end;
-
-
- end.