home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / pascal / library / dos / io / io_22 / date22.inc next >
Encoding:
Text File  |  1987-05-24  |  16.5 KB  |  578 lines

  1. { DATE22.INC -- Routines to write, read and compare dates, etc.,
  2.   by Bill Meacham.
  3.   Ver 2.0 --  Includes type declarations in this module and allows
  4.               entry of a null date (00/00/0000) -- 1/19/86.
  5.               Cosmetic improvement -- 4/16/86.
  6.   Ver 2.1 --  Function Zeller to determine the day of the week -- 10/8/86.
  7.   Ver 2.1a -- New Read_date -- 10/11/86
  8.   Ver 2.2 --  Made compatible with IO22.INC }
  9.  
  10. const
  11.     fdslen     = 29 ;  { length of fulldatestring }
  12.  
  13. type
  14.     date = record
  15.         yr : integer ; { 0 .. 9999 }
  16.         mo : integer ; { 1 .. 12 }
  17.         dy : integer ; { 1 .. 31 }
  18.       end ;
  19.  
  20.     datestring = string[10] ;  { 'MM/DD/YYYY' }
  21.  
  22.     fulldatestring = string[fdslen] ;
  23.  
  24.     juldate = record
  25.         yr  : integer ; { 0 .. 9999 }
  26.         day : integer ; { 1 .. 366 }
  27.       end ;
  28.  
  29.     juldatestring = string[8] ; { 'YYYY/DDD' }
  30.  
  31.     montharray = array [1 .. 13] of integer ;
  32.  
  33. const
  34.     monthtotal : montharray = (0,31,59,90,120,151,181,212,243,273,304,334,365) ;
  35.                  { used to convert julian date to gregorian and back }
  36.  
  37.     null_date  : date       = (yr:0 ; mo:0 ; dy:0) ;
  38.     null_date_str : datestring = 'MM/DD/YYYY' ;
  39.  
  40.  
  41. { ------------------------------------------------------------ }
  42.  
  43. function mk_dt_st (dt : date) : datestring ;
  44.   { Makes a string out of a date -- used for printing dates }
  45.     var
  46.         yr_st : string[4] ;
  47.         mo_st : string[2] ;
  48.         dy_st : string[2] ;
  49.         dt_st : datestring ;
  50.     begin
  51.         with dt do
  52.           begin
  53.             if (yr=0) and (mo=0) and (dy=0) then
  54.                 dt_st := 'MM/DD/YYYY'
  55.             else
  56.               begin
  57.                 str (yr:4,yr_st) ;
  58.                 str (mo:2,mo_st) ;
  59.                 str (dy:2,dy_st) ;
  60.                 dt_st := concat (mo_st,'/',dy_st,'/',yr_st)
  61.               end  { else }
  62.           end ;  { with dt do }
  63.         mk_dt_st := dt_st
  64.     end ;  { --- proc mk_dt_st --- }
  65.  
  66. { ------------------------------------------------------------ }
  67.  
  68. procedure write_date (dt: date ; col, row: integer) ;
  69.   { Writes date at column and row specified }
  70.     var
  71.         ds : datestring ;
  72.     begin
  73.         ds := mk_dt_st (dt) ;
  74.         write_str (ds,col,row)
  75.     end ; { --- proc write_date --- }
  76.  
  77. { ------------------------------------------------------------ }
  78.  
  79. function mk_jul_dt_st (jdt : juldate) : juldatestring ;
  80. { makes a string out of a julian date }
  81.   var
  82.       yr_st  : string[4] ;
  83.       day_st : string[3] ;
  84.       jdt_st : juldatestring ;
  85.   begin
  86.       with jdt do
  87.         if (yr=0) and (day = 0) then
  88.             jdt_st := 'YYYY/DDD'
  89.         else
  90.           begin
  91.             str(yr:4,yr_st) ;
  92.             str(day:3,day_st) ;
  93.             jdt_st := concat (yr_st,'/',day_st)
  94.           end ;
  95.       mk_jul_dt_st := jdt_st
  96.   end ;  { function mk_jul_dt_st }
  97.  
  98. { ------------------------------------------------------------ }
  99.  
  100. function leapyear (yr : integer) : boolean ;
  101. { Whether the year is a leap year or not.
  102.   The year is year and century, e.g. year '1984' is 1984, not 84 }
  103.   begin
  104.     leapyear := ((yr mod 4 = 0) and (not(yr mod 100 = 0)))
  105.              or ( yr mod 400 = 0 )
  106.   end ;
  107.  
  108. { ------------------------------------------------------------ }
  109.  
  110. function valid_date (dt:date) : boolean ;
  111.   { Test whether date is valid }
  112.     var
  113.         bad_fld : integer ;
  114.     begin
  115.         bad_fld := 0 ;
  116.         with dt do
  117.             begin
  118.                 if (mo = 0) and (dy = 0) and (yr = 0) then
  119.                     bad_fld := 0
  120.                 else if not (mo in [1 .. 12]) then
  121.                         bad_fld := 1
  122.                 else if (dy > 31)
  123.                 or (dy < 1)
  124.                 or ((mo in [4,6,9,11]) and (dy > 30)) then
  125.                         bad_fld := 2
  126.                 else if mo = 2 then
  127.                   begin
  128.                     if (leapyear(yr) and (dy > 29))
  129.                     or ((not leapyear(yr)) and (dy > 28)) then
  130.                         bad_fld := 2
  131.                   end
  132.                 else if yr = 0 then
  133.                         bad_fld := 3
  134.             end ; { with dt do }
  135.         valid_date := (bad_fld = 0)
  136.     end ; { function valid_date }
  137.  
  138. { ------------------------------------------------------------ }
  139.  
  140. procedure read_date (var dt: date ; col, row: integer) ;
  141.  
  142. { Read date at column and row specified.  If the user enters only
  143.   two digits for the year, the procedure plugs the century as 1900 or
  144.   2000, but the user can enter all four digits to override the plug. }
  145.  
  146.   var
  147.     ch       : char ;
  148.     savefld,
  149.     bad_fld,
  150.     key,
  151.     p        : integer ;
  152.     s,
  153.     template : datestring ;
  154.  
  155. { ==================== }
  156.  
  157.   procedure add_to_str ;
  158.     var
  159.       l : integer ;
  160.     begin
  161.       l := length(s) ;
  162.       if l = 10 then
  163.           beep
  164.       else if (l=1) or (l=4) then
  165.         begin
  166.           s := concat(s,ch,'/') ;
  167.           write (ch,'/')
  168.         end
  169.       else
  170.         begin
  171.           s := concat(s,ch) ;
  172.           write (ch)
  173.         end
  174.     end ; { proc add_to_str }
  175.  
  176. { ==================== }
  177.  
  178.   procedure adjust_dt_str ;
  179.     var
  180.       l : integer ;
  181.     begin
  182.       case key of
  183.         del_fld :
  184.           begin
  185.             s := '' ;
  186.             write_str (template,col,row) ;
  187.             gotoxy (col,row)
  188.           end ;
  189.         del_left,
  190.         prev_char :                    { prev_char is destructive backspace! }
  191.           begin
  192.             l := length(s) ;
  193.             if l = 0 then
  194.                 beep
  195.             else if (l=3) or (l=6) then
  196.               begin
  197.                 write (^H,^H,chr(filler),^H) ;
  198.                 delete (s,l-1,2)
  199.               end
  200.             else
  201.               begin
  202.                 write (^H,chr(filler),^H) ;
  203.                 delete (s,l,1)
  204.               end
  205.           end
  206.       end { case }
  207.     end ; { proc adjust_dt_str }
  208.  
  209. { ==================== }
  210.  
  211.   procedure convert_date ;
  212.   { convert the string to a date -- three integers }
  213.     var
  214.       code : integer ;
  215.     begin
  216.       p := pos(' ',s) ;
  217.       while p <> 0 do
  218.         begin
  219.           s[p] := '0' ;
  220.           p := pos(' ',s)
  221.         end ;
  222.       with dt do
  223.         begin
  224.           if (copy(s,1,2) = '') then
  225.             begin
  226.               mo := 0 ; code := 0
  227.             end
  228.           else
  229.               val (copy(s,1,2),mo,code) ;
  230.           if code <> 0 then
  231.             begin
  232.               write ('** CONVERSION ERROR ',code) ;
  233.               halt
  234.             end ;
  235.           if (copy(s,4,2) = '') then
  236.             begin
  237.               dy := 0 ; code := 0
  238.             end
  239.           else
  240.               val (copy(s,4,2),dy,code) ;
  241.           if code <> 0 then
  242.             begin
  243.               write ('** CONVERSION ERROR ',code) ;
  244.               halt
  245.             end ;
  246.           if (copy(s,7,4) = '') then
  247.             begin
  248.               yr := 0 ; code := 0
  249.             end
  250.           else
  251.               val (copy(s,7,4),yr,code) ;
  252.           if code <> 0 then
  253.             begin
  254.               write ('** CONVERSION ERROR ',code) ;
  255.               halt
  256.             end ;
  257.           if not ((yr = 0) and (mo = 0) and (dy = 0)) then
  258.             begin                                          { plug century }
  259.               if yr < 80 then
  260.                   yr := 2000 + yr
  261.               else if yr < 100 then
  262.                   yr := 1900 + yr
  263.             end
  264.         end { with }
  265.     end ; { proc convert_date}
  266.  
  267. { ==================== }
  268.  
  269.   procedure edit_date ;                  { Edit for valid date }
  270.     begin
  271.       bad_fld := 0 ;
  272.       with dt do
  273.         begin
  274.           if (mo = 0) and (dy = 0) and (yr = 0) then
  275.               bad_fld := 0
  276.           else if not (mo in [1 .. 12]) then
  277.               bad_fld := 1
  278.           else if (dy > 31)
  279.           or (dy < 1)
  280.           or ((mo in [4,6,9,11]) and (dy > 30)) then
  281.               bad_fld := 2
  282.           else if mo = 2 then
  283.             begin
  284.               if (leapyear(yr) and (dy > 29))
  285.               or ((not leapyear(yr)) and (dy > 28)) then
  286.                   bad_fld := 2
  287.             end
  288.           else if yr = 0 then
  289.               bad_fld := 3
  290.         end   { with dt do }
  291.     end ; { proc edit_date }
  292.  
  293. { ==================== }
  294.  
  295. begin { proc read_date }
  296.   savefld := fld ;
  297.   ch := chr(filler) ;
  298.   template := concat(ch,ch,'/',ch,ch,'/',ch,ch,ch,ch) ;
  299.   if (dt.mo = 0) and (dt.dy = 0) and (dt.yr = 0) then
  300.     begin
  301.       write_str (template,col,row) ;
  302.       s := '' ;
  303.       gotoxy (col,row)
  304.     end
  305.   else
  306.     begin
  307.       s := mk_dt_st(dt) ;
  308.       p := pos(' ',s) ;
  309.       while p <> 0 do
  310.         begin
  311.           s[p] := '0' ;
  312.           p := pos(' ',s)
  313.         end ;
  314.       write_str (s,col,row)
  315.     end ;
  316.   repeat
  317.       keyin(ch) ;
  318.       key := ord(ch) ;
  319.       if ch in ['0'..'9'] then
  320.           add_to_str
  321.       else if key in adjusting then
  322.           adjust_dt_str
  323.       else if key in terminating then
  324.         begin
  325.           convert_date ;
  326.           edit_date ;
  327.           do_fld_ctl (key) ;
  328.           if (fld < maxint) and (fld > savefld) then
  329.             begin                               { edit only going forward }
  330.               if bad_fld <> 0 then
  331.                 begin
  332.                   case bad_fld of
  333.                     1 : show_msg ('INVALID MONTH') ;
  334.                     2 : show_msg ('INVALID DAY') ;
  335.                     3 : show_msg ('INVALID YEAR')
  336.                   end ; { case }
  337.                   fld := savefld
  338.                 end
  339.             end
  340.         end
  341. (*      else
  342.           beep  *)
  343.   until key in terminating ;
  344.   write_date (dt,col,row)
  345. end ; { proc read_date }
  346.  
  347. { ------------------------------------------------------------ }
  348.  
  349. function greater_date (dt1, dt2 : date) : integer ;
  350.   { Compares two dates, returns 0 if both equal, 1 if first is
  351.     greater, 2 if second is greater.  Converts both to strings,
  352.     then compares the strings. }
  353.  
  354.     var
  355.         stdt1, stdt2 : string[8] ;
  356.         styr1, styr2 : string[4] ;
  357.         stmo1, stmo2 : string[2] ;
  358.         stdy1, stdy2 : string[2] ;
  359.  
  360.     begin
  361.         with dt1 do
  362.             begin
  363.                 str(yr:4,styr1) ;
  364.                 str(mo:2,stmo1) ;
  365.                 str(dy:2,stdy1) ;
  366.                 stdt1 := concat (styr1,stmo1,stdy1)
  367.             end ;
  368.         with dt2 do
  369.             begin
  370.                 str(yr:4,styr2) ;
  371.                 str(mo:2,stmo2) ;
  372.                 str(dy:2,stdy2) ;
  373.                 stdt2 := concat (styr2,stmo2,stdy2)
  374.             end ;
  375.         if stdt1 > stdt2 then
  376.                 greater_date := 1
  377.         else if stdt2 > stdt1 then
  378.                 greater_date := 2
  379.         else { both equal }
  380.                 greater_date := 0
  381.     end ; { --- of greater_date --- }
  382.  
  383. { ------------------------------------------------------------ }
  384.  
  385. procedure greg_to_jul (dt : date ; var jdt : juldate) ;
  386. { converts a gregorian date to a julian date }
  387.   begin
  388.     jdt.yr := dt.yr ;
  389.     if (dt.yr = 0) and (dt.mo = 0) and (dt.dy = 0) then
  390.         jdt.day := 0
  391.     else
  392.       begin
  393.         if (leapyear(dt.yr)) and (dt.mo > 2) then
  394.             jdt.day := 1
  395.         else
  396.             jdt.day := 0 ;
  397.         jdt.day := jdt.day + monthtotal[dt.mo] + dt.dy
  398.       end
  399.   end ;  { --- procedure greg_to_jul --- }
  400.  
  401. { ------------------------------------------------------------ }
  402.  
  403. procedure jul_to_greg (jdt : juldate ; var dt : date) ;
  404. { converts a julian date to a gregorian date }
  405.   var
  406.       i, workday : integer ;
  407.   begin
  408.     dt.yr := jdt.yr ;
  409.     if (jdt.yr = 0) and (jdt.day = 0) then
  410.       begin
  411.         dt.mo := 0 ; dt.dy := 0
  412.       end
  413.     else
  414.       begin
  415.         workday := jdt.day ;
  416.         if (leapyear(jdt.yr)) and (workday > 59) then
  417.             workday := workday - 1 ;   { make it look like a non-leap year }
  418.         i := 1 ;
  419.         repeat
  420.             i := i + 1
  421.         until not (workday > monthtotal[i]) ;
  422.         i := i - 1 ;
  423.         dt.mo := i ;
  424.         dt.dy := workday - monthtotal[i] ;
  425.         if leapyear(jdt.yr) and (jdt.day = 60) then
  426.             dt.dy := dt.dy + 1
  427.       end
  428.   end ;  { --- procedure jul_to_greg --- }
  429.  
  430. { ------------------------------------------------------------ }
  431.  
  432. procedure next_day (var dt : date) ;
  433.   { Adds one day to the date }
  434.     var
  435.         jdt  : juldate ;
  436.         leap : boolean ;
  437.     begin
  438.         greg_to_jul (dt,jdt) ;
  439.         jdt.day := jdt.day + 1 ;
  440.         leap := leapyear (dt.yr) ;
  441.         if (leap and (jdt.day = 367))
  442.         or (not leap and (jdt.day = 366)) then
  443.           begin
  444.             jdt.yr := jdt.yr + 1 ;
  445.             jdt.day := 1
  446.           end ;
  447.         jul_to_greg (jdt,dt)
  448.     end ;  { --- procedure next_day --- }
  449.  
  450. { ------------------------------------------------------------ }
  451.  
  452. procedure prev_day (var dt : date) ;
  453.   { Subtracts one day from the date }
  454.     var
  455.         jdt : juldate ;
  456.     begin
  457.         greg_to_jul (dt,jdt) ;
  458.         jdt.day := jdt.day - 1 ;
  459.         if jdt.day < 1 then
  460.           begin
  461.             jdt.yr := jdt.yr - 1 ;
  462.             if leapyear (jdt.yr) then
  463.                 jdt.day := 366
  464.             else
  465.                 jdt.day := 365
  466.           end ;
  467.         jul_to_greg (jdt,dt)
  468.     end ;  { --- procedure prev_day --- }
  469.  
  470. { ------------------------------------------------------------ }
  471.  
  472. function date_diff (dt1, dt2 : date) : real ;
  473.   { computes the number of days between two dates }
  474.     var
  475.         jdt1, jdt2 : juldate ;
  476.         i, num_leap_yrs : integer ;
  477.     begin
  478.         greg_to_jul (dt1, jdt1) ;
  479.         greg_to_jul (dt2, jdt2) ;
  480.  
  481.         num_leap_yrs := 0 ;         { adjust for leap years }
  482.         if dt2.yr > dt1.yr then
  483.           begin
  484.             for i := dt1.yr to dt2.yr - 1 do
  485.                 if leapyear(i) then
  486.                     num_leap_yrs := num_leap_yrs + 1
  487.           end
  488.         else if dt1.yr > dt2.yr then
  489.           begin
  490.             for i := dt2.yr to dt1.yr - 1 do
  491.                 if leapyear(i) then
  492.                     num_leap_yrs := num_leap_yrs - 1
  493.           end ;
  494.  
  495.         date_diff := jdt2.day - jdt1.day + ((jdt2.yr - jdt1.yr) * 365.0) + num_leap_yrs
  496.     end ;
  497.  
  498. { ------------------------------------------------------------ }
  499.  
  500. function month_diff (dt1, dt2 : date ) : integer ;
  501.   { Computes number of months between two dates, rounded.
  502.     30.4167 = 356/12, average number of days in a month. }
  503.     begin
  504.         month_diff := round((date_diff(dt1, dt2) + 1) / 30.4167)
  505.     end ;
  506.  
  507. { ------------------------------------------------------------ }
  508.  
  509. function equal_date (dt1, dt2 : date) : boolean ;
  510.   { Tests whether two dates are equal }
  511.     begin
  512.         equal_date := (dt1.mo = dt2.mo) and (dt1.dy = dt2.dy)
  513.                       and (dt1.yr = dt2.yr)
  514.     end ;
  515.  
  516. { ------------------------------------------------------------ }
  517.  
  518. function zeller (dt : date) : integer ;
  519. { Compute the day of the week using Zeller's Congruence.
  520.   From ROS 3.4 source code }
  521.   var
  522.     century: integer ;
  523.   begin
  524.     with dt do
  525.       begin
  526.         if mo > 2
  527.           then mo := mo - 2
  528.           else
  529.             begin
  530.               mo := mo + 10 ;
  531.               yr := pred(yr)
  532.             end ;
  533.         century := yr div 100 ;
  534.         yr := yr mod 100 ;
  535.         zeller := (dy - 1 + ((13 * mo - 1) div 5) + (5 * yr div 4) +
  536.             century div 4 - 2 * century + 1) mod 7
  537.       end
  538.   end ;  { function zeller }
  539.  
  540. { ------------------------------------------------------------ }
  541.  
  542. function build_full_date_str (dt : date) : fulldatestring ;
  543. { Build printable string of current date -- from ROS 3.4 source code. }
  544.   const
  545.     day: array [0..6] of string[6] =
  546.       ('Sun','Mon','Tues','Wednes','Thurs','Fri','Satur') ;
  547.     month: array [1..12] of string[9] =
  548.       ('January','February','March','April','May','June','July','August','September','October','November','December') ;
  549.   var
  550.     i: integer ;
  551.     s: fulldatestring ;
  552.  
  553.   function intstr(n, w: integer): str_type ;
  554.   { Return a string value of width w for the input integer n }
  555.     var
  556.       st: str_type ;
  557.     begin
  558.       str(n:w, st) ;
  559.       st := purgech (st,' ') ;
  560.       intstr := st
  561.     end ;
  562.  
  563.   begin { build_full_date_str }
  564.     with dt do
  565.       begin
  566.         if  (mo = 0) and (dy = 0) and (yr = 0) then
  567.             s := 'No Date'
  568.         else
  569.             s := day[zeller(dt)] + 'day, ' +
  570.                  month[mo] + ' ' + intstr(dy, 2) + ', ' + intstr(yr, 4) ;
  571.         if length (s) < fdslen then
  572.             s := pad (s,' ',fdslen)
  573.       end ;
  574.     build_full_date_str := s
  575.   end ; { function build_full_date_str }
  576.  
  577. { ----- EOF DATE22.INC ---------------------------------------- }
  578.