home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / pascal / library / dos / t_power / calendar.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1988-02-08  |  17.2 KB  |  629 lines

  1. (***********************************************************************)
  2. (*                                                                     *)
  3. (*                     TURBO CALENDAR FUNCTIONS                        *)
  4. (*                                                                     *)
  5. (*                                                                     *)
  6. (*                       Module version 1.01A                          *)
  7. (*                                                                     *)
  8. (*                         by Rick Amerson                             *)
  9. (*                                                                     *)
  10. (*                                                                     *)
  11. (*                                                                     *)
  12. (*                                                                     *)
  13. (*                                                                     *)
  14. (***********************************************************************)
  15. unit Calendar;
  16.  
  17. interface
  18.  
  19. uses Dos,
  20.      Crt,
  21.      TpString;
  22.  
  23. const
  24.     BaseYear         =  1901;    {Must start year after leap year}
  25.     MaxHoliday       =  400;     {Maximum number of entries in holiday file }
  26.     InvalidDate      =  $FFFF;   {Invalid Date}
  27.  
  28. type
  29.     DayOfWeek        =  (Sunday, Monday, Tuesday, Wednesday,
  30.                          Thursday, Friday, Saturday);
  31.     DateNum          =  word;   {Date Number-- compressed two byte date}
  32.     DateArray        =  array[1..MaxHoliday] of DateNum;
  33.     CalendarPtr      =  ^CalendarRec;
  34.     CalendarRec      =  record
  35.                           CalName:  string[8];
  36.                           LastH,      {Last holiday entry}
  37.                           LastE:  integer;    {Last entry in extra array}
  38.                           Workdays: set of DayOfWeek;
  39.                           WorkdaysPerWeek: 0..7;
  40.                           HDate: DateArray;
  41.                           EDate: DateArray;
  42.                           end;
  43.  
  44. const
  45.     MonthName: array[1..12] of string[9]=
  46.            ('January', 'February', 'March', 'April', 'May', 'June',
  47.             'July', 'August', 'September', 'October', 'November', 'December');
  48.     DayName: array[DayOfWeek] of string[9]=
  49.              ('Sunday', 'Monday', 'Tuesday', 'Wednesday',
  50.               'Thursday', 'Friday', 'Saturday');
  51.  
  52.  
  53. function ToDateNum(D: DateTime): DateNum;
  54. {This function returns the integer equivalent of a date passed to it}
  55.  
  56. procedure FromDateNum(D_In: DateNum;
  57.                   var D:    DateTime);
  58.  
  59. {This function converts from a DateNum format date to DateTime}
  60.  
  61. function Today: DateNum;    {returns today's date as a DateNum}
  62.  
  63. function LotusDate(D: DateNum): string;
  64. {Returns a string formatted as  12-Jul-88.  If date = 0, returns blank string}
  65.  
  66. function FromLotusDate(S: string): DateNum;
  67. {Reads a date from any of the following formats:
  68.  
  69.       1: DD-MMM-YY
  70.       2: DD-MMM         --Assumes current year
  71.       3: MMM-YY         --Assumes first of month
  72.       4: MM/DD/YY
  73.       5: MM/DD          --Assumes current year
  74.       6: MMM DD, YYYY
  75. }
  76.  
  77. function ExtDate(D: DateNum): string;
  78. { returns date of format:   Fri, Aug 28, 1987 }
  79.  
  80. function ExtTime( T: word ): string;
  81. {returns time of format:  12:46 PM}
  82.  
  83. function TimeStr( T: DateNum ): string;
  84. {returns a string with the time T in 12-hour format "10:43 PM"}
  85.  
  86. function ToMMDDYY(D: DateNum): string;
  87. {Returns string of format:  030288   (MonthDayYear)}
  88.  
  89. function FromMMDDYY(S: string): DateNum;
  90. {Decodes string of format:   030288   (MonthDayYear)}
  91.  
  92. function ToDDMMYY(D: DateNum): string;
  93. {Returns string of format:  020388  (DayMonthYear)}
  94.  
  95. function FromDDMMYY(S: string): DateNum;
  96. {Decodes string of format:   030288   (DayMonthYear)}
  97.  
  98. function HolidaysBetween( D1,
  99.                           D2: DateNum;
  100.                           var Calendar: CalendarPtr ): integer;
  101. {Return Number of Holidays between D1 and D2}
  102.  
  103. function WorkDaysBetween( D1, D2: DateNum;
  104.                           var Calendar: CalendarPtr ): integer;
  105. {Return Number of WorkDays between D1 and D2}
  106.  
  107. procedure SetDate(NewDate: DateNum);    {sets today's date as an integer}
  108.  
  109. function TimeNow: word; {returns current time as integer minutes since 0:00}
  110.  
  111. procedure GetTime( var Minutes,
  112.                        Seconds: word); {gets current time as mins since 0:00}
  113.  
  114. procedure SetTime( Minutes,
  115.                    Seconds: word); {sets current time as minutes since 0:00}
  116.  
  117. function ValidDate( D: DateTime ): boolean; {Returns true if date is valid}
  118.  
  119. {===========================================================================}
  120. {.pa}
  121. implementation
  122.  
  123. const
  124.   Digits: set of char   = ['0'..'9'];
  125.   DayOffset        =  1;       {Constant to add for day of week}
  126.   DaysInYear       =  365.25;
  127.   MonthsInYear     =  12;
  128.   DaysIn: array[1..12] of byte        =  (31, 29, 31, 30, 31, 30,
  129.                                           31, 31, 30, 31, 30, 31);
  130.   DaysBefore: array[1..12] of integer =   (0, 31, 60, 91,121,152,
  131.                                          182,213,244,274,305,335);
  132.  
  133. type
  134.   str2 = string[2];
  135.  
  136. function Str2Lead0( B: byte ): str2;
  137.  
  138. begin
  139.  
  140.   Str2Lead0[0] := #2;   {two byte result}
  141.   Str2Lead0[1] := chr((B div 10) + ord('0'));
  142.   Str2Lead0[2] := chr((B mod 10) + ord('0'));
  143.  
  144.   end;
  145.  
  146. function Str2LeadBlank( B: byte ): str2;
  147.  
  148. begin
  149.  
  150.   Str2LeadBlank[0] := #2;   {two byte result}
  151.   if (B div 10) = 0 then Str2LeadBlank[1] := ' '
  152.   else Str2LeadBlank[1] := chr((B div 10) + ord('0'));
  153.   Str2LeadBlank[2] := chr((B mod 10) + ord('0'));
  154.  
  155.   end;
  156.  
  157. function ValidDate( D: DateTime ): boolean; {Returns true if date is valid}
  158.  
  159. begin
  160.  
  161.   with D do begin
  162.     ValidDate := false;
  163.     case Year of
  164.       1901..2079: case Day of
  165.         1..31: case Month of
  166.           1, 3..12: if Day <= DaysIn[Month] then ValidDate := true;
  167.           2:        if Day <= 28 + ord(Year mod 4 = 0) then ValidDate := true;
  168.           end;  {case Month}
  169.         end;  {case Day}
  170.       end;  {case Year}
  171.     end;  {with D}
  172.  
  173.   end;  {ValidDate}
  174.  
  175. function ToDateNum(D: DateTime): DateNum;
  176. {This function returns the integer equivalent of a date passed to it}
  177.  
  178. var T: integer;
  179.  
  180. begin
  181.  
  182.   T := DaysBefore[D.Month] + D.Day +                  {Days in this year}
  183.     trunc( DaysInYear * (D.Year - BaseYear));         {Days in prior years}
  184.   if ( ( D.Year and $3 ) <> 0 ) and ( D.Month > 2 ) then Dec(T);
  185.                                     { Subtract Leap Day for non-leap years}
  186.   ToDateNum := T;
  187.   end;
  188. {.pa}
  189. procedure FromDateNum(D_In: DateNum;
  190.                   var D:    DateTime);
  191.  
  192. {This function converts from a DateNum format date to DateTime}
  193.  
  194. var T: integer;
  195.  
  196. begin
  197.  
  198.   with D do begin
  199.     T := trunc( D_In / DaysInYear );     {Number of prior years}
  200.     D_In := D_In - trunc( T * DaysInYear ); {Day in year-- 1..366}
  201.     Year := T + BaseYear;
  202.     if (( Year and $3 ) <> 0 ) and ( D_In >= DaysBefore[3] ) then Inc( D_In);
  203.                                       {Add in Feb 29 for non-leap years}
  204.     Month := ( D_In - 1 ) div 31 + 1;  {Approximate month}
  205.     if ( D_In > DaysBefore[Month] + DaysIn[Month] ) then Inc(Month);
  206.     Day := D_In - DaysBefore[Month];
  207.     end; {with D do}
  208.  
  209.   end; {CalDate}
  210. {.pa}
  211. function Today: DateNum;    {returns today's date as a DateNum}
  212.  
  213. var Reg: Registers;
  214.     TDate: DateTime;
  215.  
  216. begin
  217.  
  218.   with Reg, TDate do begin
  219.     AH := $2A;
  220.     MSDos( Reg );
  221.     Month := DH;
  222.     Day := ( DL );
  223.     Year := ( CX );
  224.     Today := ToDateNum( TDate );
  225.     end;  {with Reg, TDate do}
  226.  
  227.   end; {Today}
  228.  
  229. function LotusDate(D: DateNum): string;
  230. {Returns a string formatted as  12-Jul-88.  If date = 0, returns blank string}
  231.  
  232. var
  233.   TDate: DateTime;
  234.  
  235. begin {LotusDate}
  236.   if D = InvalidDate then
  237.     LotusDate := '*Invalid*'
  238.       else begin
  239.     FromDateNum(D,TDate);
  240.     with TDate do begin
  241.       LotusDate := Str2Lead0( Day ) + '-' + copy(MonthName[Month],1,3) + '-' +
  242.         Str2Lead0( Year mod 100 );
  243.       end; {with TDate}
  244.     end; {else D = 0}
  245.   end; {LotusDate}
  246. {.pa}
  247. function FromLotusDate(S: string): DateNum;
  248. {Reads a date from any of the following formats:
  249.  
  250.       1: DD-MMM-YY
  251.       2: DD-MMM         --Assumes current year
  252.       3: MMM-YY         --Assumes first of month
  253.       4: MM/DD/YY
  254.       5: MM/DD          --Assumes current year
  255.       6: MMM DD, YYYY
  256. }
  257.  
  258. type
  259.   DateFormat = set of 1..6;
  260.  
  261. const
  262.   Separators: set of char = ['-', '/', ' ', ','];  {Valid separator characters}
  263.  
  264. var
  265.   Format:    DateFormat;
  266.   TDate:     DateTime;
  267.   Junk:      word;
  268.  
  269. function FindMonth(var Name: string): word;
  270.  
  271. var
  272.   Month:     byte;
  273.   TName:     string[3];
  274.  
  275. begin
  276.  
  277.   Month := 12;
  278.   TName := StLocase( copy(Name,1,3) );
  279.   TName[1] := Upcase( Name[1] );
  280.   while (copy(MonthName[Month], 1, 3) <> TName) and (Month > 0) do dec(Month);
  281.   FindMonth := Month;
  282.   if Month <> 0 then begin
  283.     Name := copy( Name, 4, 255 );
  284.     while (length(Name) > 0) and (Name[1] in Separators) do
  285.       Name := copy(Name, 2, 255);                {Throw away separator char}
  286.     end;
  287.  
  288.   end; {FindMonth}
  289.  
  290. function ReadDigits( var S: string ): word;
  291. {Reads a number up to 4 digits}
  292.  
  293. var
  294.   V:  word;
  295.  
  296. begin
  297.  
  298.   V := 0;
  299.   while (length(S) > 0 ) and (S[1] in Digits) and (V <= 999) do begin
  300.     V := V * 10 + ord(S[1]) - ord('0');
  301.     S := copy( S, 2, 255 );
  302.     end;
  303.   ReadDigits := V;
  304.   while (length(S) > 0) and (S[1] in Separators) do
  305.     S := copy(S, 2, 255);                {Throw away separator char}
  306.  
  307.   end;
  308. {.pa}
  309. begin {FromLotus}
  310.  
  311.   Format := [1..6];                {could be any format}
  312.   with TDate do begin
  313.     Hour := 0;
  314.     Min := 0;
  315.     Sec := 0;
  316.     Day := ReadDigits( S );
  317.     if Day <> 0 then Format := Format - [3,6]
  318.     else Format := Format - [1,2,4,5];    {format 3 or 6}
  319.     Month := FindMonth(S);
  320.     if Month = 0 then begin
  321.       Format := Format - [1,2,3,6];    {not a valid format}
  322.       Month := Day;
  323.       Day := ReadDigits( S );
  324.       if Day = 0 then Format := Format - [4,5];    {Not a 4 or 5}
  325.       end;
  326.     if length(S) > 0 then begin                 {Look for a year}
  327.       Format := Format - [2,5];
  328.       Year := ReadDigits( S );
  329.       if length(S) > 0 then begin    {must be format 6; this is the day}
  330.         Day := Year;
  331.         Year := ReadDigits( S );
  332.         Format := Format - [1,2,3,4,5];
  333.         end
  334.       else Format := Format - [6];
  335.       if Year < 100 then begin
  336.         Year := Year + 1900;
  337.         if Year < 1901 then Year := Year + 100;
  338.         end;
  339.       end
  340.     else begin
  341.       Format := Format - [1,3,4,6];
  342.       GetDate( Year, Junk, Junk, Junk );   {Use current year}
  343.       end;
  344.     if Format = [3] then Day := 1;  {Default day}
  345.     if (Format <> []) and ValidDate(TDate) then begin
  346.       FromLotusDate := ToDateNum(TDate);
  347.       end
  348.     else begin
  349.       FromLotusDate := InvalidDate;
  350.       end;
  351.     end; {with TDate do}
  352.   end;  {FromLotusDate}
  353.  
  354. {.pa}
  355. function ExtDate(D: DateNum): string;
  356. { returns date of format:   Fri, Aug 28, 1987 }
  357.  
  358. var
  359.   TDate: DateTime;
  360.   S:     string;
  361.  
  362. begin  {ExtDate}
  363.  
  364.   if D = InvalidDate then ExtDate := '**** Invalid ****'
  365.   else begin
  366.     FromDateNum(D,TDate);
  367.     with TDate do begin
  368.       str( Year:4, S );
  369.       ExtDate := copy(DayName[DayOfWeek((D+DayOffset) mod 7)],1,3) + ', ' +
  370.         copy(MonthName[Month],1,3) + ' ' + Str2LeadBlank( Day) +  ', ' + S;
  371.       end;
  372.     end;  {if D = InvalidDate}
  373. end;
  374. {.pa}
  375. function ExtTime( T: word ): string;
  376. {returns time of format:  12:46 PM}
  377.  
  378. var
  379.   Hour,
  380.   Minute:   integer;
  381.   AM_PM:    string[2];
  382.   S:        string;
  383.  
  384. begin    {ExtTime}
  385.  
  386.   Hour := T div 60;
  387.   Minute := T mod 60;
  388.   if Hour >= 12 then AM_PM := 'PM' else AM_PM := 'AM';
  389.   Hour := Hour mod 12;
  390.   if Hour = 0 then Hour := 12;
  391.   S := Str2LeadBlank( Hour ) + ':' + Str2Lead0( Minute ) + ' ' + AM_PM;
  392.   if S[4] = ' ' then S[4] := '0';
  393.   ExtTime := S;
  394.  
  395.   end;   {ExtTime}
  396.  
  397. function TimeStr( T: DateNum ): string;
  398.  
  399. var
  400.   S:             string;
  401.   ThisDateTime:  DateTime;
  402.  
  403. begin
  404.  
  405.   UnpackTime( T, ThisDateTime );
  406.   with ThisDateTime do begin
  407.     if Hour >= 12 then S := 'P' else S := 'A';
  408.     Hour := Hour mod 12;
  409.     if Hour = 0 then Hour := 12;
  410.     S := Str2Lead0( Min ) + ' ' + S + 'M';
  411.     TimeStr := Str2LeadBlank( Hour ) + ':' + S;
  412.     end;   {with ThisDateTime}
  413.  
  414.   end;  {TimeStr}
  415.  
  416. {.pa}
  417. function ToMMDDYY(D: DateNum): string;
  418. {Returns string of format:  030288   (MonthDayYear)}
  419.  
  420. var TDate: DateTime;
  421.     S:     string;
  422.  
  423. begin
  424.   FromDateNum(D, TDate);
  425.   with TDate do
  426.     ToMMDDYY := Str2Lead0( ord( Month ) + 1 ) + Str2Lead0( Day ) +
  427.       Str2Lead0( Year mod 100 );
  428.   end;  {ToMMDDYY}
  429.  
  430. function FromMMDDYY(S: string): DateNum;
  431. {Decodes string of format:   030288   (MonthDayYear)}
  432.  
  433. var TDate:    DateTime;
  434.     TMonth,
  435.     TYear:    word;
  436.  
  437. begin
  438.  
  439.   FromMMDDYY := InvalidDate;
  440.   with TDate do begin
  441.     if Str2Word( copy(S,1,2), Month ) then begin
  442.       if Str2Word( copy(S,3,2), Day ) then begin
  443.         if Str2Word( copy(S,5,2), TYear ) then begin
  444.           TYear := TYear + 1900;
  445.           if TYear < BaseYear then
  446.             TYear := TYear + 100;   {After turn of century}
  447.           Year := TYear;
  448.           FromMMDDYY := ToDateNum( TDate )
  449.           end;
  450.         end;
  451.       end;
  452.     end; {with TDate}
  453.   end;  {FromMMDDYY}
  454.  
  455. {.pa}
  456. function ToDDMMYY(D: DateNum): string;
  457. {Returns string of format:  020388  (DayMonthYear)}
  458.  
  459. var TDate: DateTime;
  460.     S:     string;
  461.  
  462. begin
  463.   FromDateNum(D, TDate);
  464.   with TDate do
  465.     ToDDMMYY := Str2Lead0( Day ) + Str2Lead0( ord( Month ) + 1 ) +
  466.       Str2Lead0( Year mod 100 );
  467.   end;  {ToDDMMYY}
  468.  
  469. function FromDDMMYY(S: string): DateNum;
  470. {Decodes string of format:   030288   (DayMonthYear)}
  471.  
  472. begin
  473.  
  474.   FromDDMMYY := FromMMDDYY(Copy(S,3,2) + copy(S,1,2) + copy(S,5,2));
  475.  
  476.   end;  {FromDDMMYY}
  477. {.pa}
  478. function HolidaysBetween( D1,
  479.                           D2: DateNum;
  480.                           var Calendar: CalendarPtr ): integer;
  481. {Return Number of Holidays between D1 and D2}
  482.  
  483. var Top,
  484.     Bot,
  485.     Mid:  integer;
  486.  
  487. function SearchHoliday( Max:   integer;
  488.                         D:     DateNum;
  489.                         var A: DateArray): integer;
  490. {returns index into DateArray of D such that A[index] >= D}
  491.  
  492. begin
  493.  
  494.   Bot := 1;
  495.   Top := Max;
  496.  
  497.   if Top > 0 then
  498.     repeat
  499.       Mid := ( Top + Bot ) div 2;
  500.       if D <= A[Mid] then
  501.         Top := Mid - 1;
  502.       if D >= A[Mid] then
  503.         Bot := Mid + 1;
  504.       until Top < Bot;
  505.  
  506.   SearchHoliday := ( Top + Bot ) div 2 + 1;
  507.  
  508.   end;  {SearchHoliday}
  509.  
  510. begin  {function HolidaysBetween}
  511.  
  512.   with Calendar^ do
  513.     HolidaysBetween := Abs( SearchHoliday( LastH, D1, HDate ) -
  514.                             SearchHoliday( LastH, D2, HDate ) ) -
  515.                        Abs( SearchHoliday( LastE, D1, EDate ) -
  516.                             SearchHoliday( LastE, D2, EDate ) );
  517.  
  518.   end;  {HolidaysBetween}
  519.  
  520. {.pa}
  521. function WorkDaysBetween( D1, D2: DateNum;
  522.                           var Calendar: CalendarPtr ): integer;
  523. {Return Number of WorkDays between D1 and D2}
  524.  
  525. var
  526.   WeeksBetween,
  527.   DaysBetween: integer;
  528.   DW,
  529.   DW1,
  530.   DW2: DayOfWeek;
  531.  
  532. begin
  533.   WeeksBetween := abs( (D2 + DayOffset) div 7 - (D1 + DayOffset) div 7 ) -1;
  534.                                           {Number of whole weeks between}
  535.  
  536.   with Calendar^ do begin
  537.     DaysBetween := WeeksBetween * WorkDaysPerWeek;
  538.     DW1 := DayOfWeek( (D1 + DayOffset) mod 7 );
  539.     DW2 := DayOfWeek( (D2 + DayOffset) mod 7 );
  540.  
  541.     if D1 < D2 then begin
  542.       for DW := DW1 to Saturday do
  543.         if DW in WorkDays then
  544.           DaysBetween := succ( DaysBetween );
  545.       for DW := Sunday to DW2 do
  546.         if DW in WorkDays then
  547.           DaysBetween := succ( DaysBetween );
  548.       end {D1 < D2}
  549.     else begin
  550.       for DW := Sunday to DW1 do
  551.         if DW in WorkDays then inc( DaysBetween );
  552.       for DW := DW2 to Saturday do
  553.         if DW in WorkDays then inc( DaysBetween );
  554.       end;
  555.     end; {with Calendar^}
  556.  
  557.   WorkDaysBetween := DaysBetween - HolidaysBetween( D1, D2, Calendar );
  558.   end;  {WorkDaysBetween}
  559.  
  560. procedure SetDate(NewDate: DateNum);    {sets today's date as an integer}
  561.  
  562. var Reg: Registers;
  563.     TDate: DateTime;
  564.  
  565. begin
  566.  
  567.   FromDateNum( NewDate, TDate );
  568.   with Reg, TDate do begin
  569.     AH := $2B;
  570.     DH := ord(Month) + 1;
  571.     DL := Day;
  572.     CX := Year;
  573.     MSDos( Reg );
  574.     end;  {with Reg, TDate do}
  575.  
  576.   end; {SetDate}
  577. {.pa}
  578. function TimeNow: word; {returns current time as integer minutes since 0:00}
  579.  
  580. var Reg: Registers;
  581.  
  582. begin
  583.  
  584.   with Reg do begin
  585.     AH := $2C;
  586.     MSDos( Reg );
  587.     TimeNow := CH * 60 + CL;
  588.     end;  {with Reg do}
  589.  
  590.   end; {TimeNow}
  591.  
  592. procedure GetTime( var Minutes,
  593.                        Seconds: word); {gets current time as minutes since 0:00}
  594.  
  595. var Reg: Registers;
  596.  
  597. begin
  598.  
  599.   with Reg do begin
  600.     AH := $2C;
  601.     MSDos( Reg );
  602.     Minutes := CH * 60 + CL;
  603.     Seconds := DH;
  604.     end;  {with Reg do}
  605.  
  606.   end; {GetTime}
  607.  
  608. procedure SetTime( Minutes,
  609.                    Seconds: word); {sets current time as minutes since 0:00}
  610.  
  611. var Reg: Registers;
  612.  
  613. begin
  614.  
  615.   with Reg do begin
  616.     AH := $2D;
  617.     CH := Minutes div 60;    {hours}
  618.     CL := Minutes mod 60;    {minutes}
  619.     DH := Seconds;
  620.     DL := 0;         {hundredths of seconds}
  621.     MSDos( Reg );
  622.     end;  {with Reg do}
  623.  
  624.   end; {SetTime}
  625.  
  626. begin
  627.   end.
  628.  
  629.