home *** CD-ROM | disk | FTP | other *** search
/ CP/M / CPM_CDROM.iso / mbug / mbug171.arc / TURBO-IO.LBR / DATE20.IZC / DATE20.INC
Text File  |  1979-12-31  |  13KB  |  392 lines

  1. { DATE20.INC -- Routines to write, read and compare dates, etc.
  2.   Version 2.0 includes type declarations in this module and allows
  3.   entry of a null date (00/00/0000).   WPM -- 1/19/86 .
  4.   Cosmetic improvement -- 4/16/86 }
  5.  
  6. type
  7.     date = record
  8.         yr : integer ; { 0 .. 9999 }
  9.         mo : integer ; { 1 .. 12 }
  10.         dy : integer ; { 1 .. 31 }
  11.       end ;
  12.  
  13.     datestring = string[10] ;  { 'MM/DD/YYYY' }
  14.  
  15.     juldate = record
  16.         yr  : integer ; { 0 .. 9999 }
  17.         day : integer ; { 1 .. 366 }
  18.       end ;
  19.  
  20.     juldatestring = string[8] ; { 'YYYY/DDD' }
  21.  
  22.     montharray = array [1 .. 13] of integer ;
  23.  
  24. const
  25.     monthtotal : montharray = (0,31,59,90,120,151,181,212,243,273,304,334,365) ;
  26.                  { used to convert julian date to gregorian and back }
  27.  
  28.     null_date  : date       = (yr:0 ; mo:0 ; dy:0) ;
  29.     null_date_str : datestring = 'MM/DD/YYYY' ;
  30.  
  31.  
  32. { ------------------------------------------------------------ }
  33.  
  34. function mk_dt_st (dt : date) : datestring ;
  35.   { Makes a string out of a date -- used for printing dates }
  36.     var
  37.         yr_st : string[4] ;
  38.         mo_st : string[2] ;
  39.         dy_st : string[2] ;
  40.         dt_st : datestring ;
  41.     begin
  42.         with dt do
  43.           begin
  44.             if (yr=0) and (mo=0) and (dy=0) then
  45.                 dt_st := 'MM/DD/YYYY'
  46.             else
  47.               begin
  48.                 str (yr:4,yr_st) ;
  49.                 str (mo:2,mo_st) ;
  50.                 str (dy:2,dy_st) ;
  51.                 dt_st := concat (mo_st,'/',dy_st,'/',yr_st)
  52.               end  { else }
  53.           end ;  { with dt do }
  54.         mk_dt_st := dt_st
  55.     end ;  { --- proc mk_dt_st --- }
  56.  
  57. { ------------------------------------------------------------ }
  58.  
  59. procedure write_date (dt: date ; col, row: integer) ;
  60.   { Writes date at column and row specified }
  61.     var
  62.         ds : datestring ;
  63.     begin
  64.         ds := mk_dt_st (dt) ;
  65.         write_str (ds,col,row)
  66.     end ; { --- proc write_date --- }
  67.  
  68. { ------------------------------------------------------------ }
  69.  
  70. function mk_jul_dt_st (jdt : juldate) : juldatestring ;
  71. { makes a string out of a julian date }
  72.   var
  73.       yr_st  : string[4] ;
  74.       day_st : string[3] ;
  75.       jdt_st : juldatestring ;
  76.   begin
  77.       with jdt do
  78.         if (yr=0) and (day = 0) then
  79.             jdt_st := 'YYYY/DDD'
  80.         else
  81.           begin
  82.             str(yr:4,yr_st) ;
  83.             str(day:3,day_st) ;
  84.             jdt_st := concat (yr_st,'/',day_st)
  85.           end ;
  86.       mk_jul_dt_st := jdt_st
  87.   end ;  { function mk_jul_dt_st }
  88.  
  89. { ------------------------------------------------------------ }
  90.  
  91. function leapyear (yr : integer) : boolean ;
  92. { Whether the year is a leap year or not.
  93.   The year is year and century, e.g. year '1984' is 1984, not 84 }
  94.   begin
  95.     leapyear := ((yr mod 4 = 0) and (not(yr mod 100 = 0)))
  96.              or ( yr mod 400 = 0 )
  97.   end ;
  98.  
  99. { ------------------------------------------------------------ }
  100.  
  101. function valid_date (dt:date) : boolean ;
  102.   { Test whether date is valid }
  103.     var
  104.         bad_fld : integer ;
  105.     begin
  106.         bad_fld := 0 ;
  107.         with dt do
  108.             begin
  109.                 if (mo = 0) and (dy = 0) and (yr = 0) then
  110.                     bad_fld := 0
  111.                 else if not (mo in [1 .. 12]) then
  112.                         bad_fld := 1
  113.                 else if (dy > 31)
  114.                 or (dy < 1)
  115.                 or ((mo in [4,6,9,11]) and (dy > 30)) then
  116.                         bad_fld := 2
  117.                 else if mo = 2 then
  118.                   begin
  119.                     if (leapyear(yr) and (dy > 29))
  120.                     or ((not leapyear(yr)) and (dy > 28)) then
  121.                         bad_fld := 2
  122.                   end
  123.                 else if yr = 0 then
  124.                         bad_fld := 3
  125.             end ; { with dt do }
  126.         valid_date := (bad_fld = 0)
  127.     end ; { function valid_date }
  128.  
  129. { ------------------------------------------------------------ }
  130.  
  131. procedure read_date (var dt: date ; col, row: integer) ;
  132.  
  133.   { Read date at column and row specified.  If the user enters only
  134.     two digits for the year, the procedure plugs the century as 1900 or
  135.     2000, but the user can enter all four digits to override the plug. }
  136.  
  137.     var
  138.         savefld, bad_fld : integer ;
  139.  
  140.     procedure edit_date ;                  { Edit for valid date }
  141.         begin
  142.             bad_fld := 0 ;
  143.             with dt do
  144.                 begin
  145.                     if (mo = 0) and (dy = 0) and (yr = 0) then
  146.                         bad_fld := 0
  147.                     else if not (mo in [1 .. 12]) then
  148.                         begin
  149.                             mo  := 0 ;
  150.                             bad_fld := 1
  151.                         end
  152.                     else if (dy > 31)
  153.                     or (dy < 1)
  154.                     or ((mo in [4,6,9,11]) and (dy > 30)) then
  155.                         begin
  156.                             dy  := 0 ;
  157.                             bad_fld := 2
  158.                         end
  159.                     else if mo = 2 then
  160.                       begin
  161.                         if (leapyear(yr) and (dy > 29))
  162.                         or ((not leapyear(yr)) and (dy > 28)) then
  163.                             begin
  164.                                 dy  := 0 ;
  165.                                 bad_fld := 2
  166.                             end
  167.                       end
  168.                     else if yr = 0 then
  169.                             bad_fld := 3
  170.                 end   { with dt do }
  171.         end ; { --- of edit_date --- }
  172.  
  173.     begin { read_date }
  174.         savefld := fld ;                    { Save FLD for rest of screen }
  175.         fld := 1 ;                          { Set up FLD for use locally }
  176.         write_date (dt, col, row) ;
  177.         with dt do
  178.             repeat
  179.                 repeat
  180.                     case fld of
  181.                         1 : read_int (mo, 2, col, row) ;
  182.                         2 : read_int (dy, 2, col+3, row) ;
  183.                         3 : begin
  184.                               read_int (yr, 4, col+6, row) ;
  185.                               if  (yr < 0) then
  186.                                 begin
  187.                                   yr := 0 ;
  188.                                   if (fld > 3) and (fld < maxint) then
  189.                                       fld := 3
  190.                                 end
  191.                               else if not((yr = 0) and (mo = 0) and (dy = 0)) then
  192.                                 begin
  193.                                   if yr < 80 then         { Plug century }
  194.                                       yr := 2000 + yr
  195.                                   else if yr < 100 then
  196.                                       yr := 1900 + yr
  197.                                 end ;
  198.                               write_int (yr, 4, col+6, row)
  199.                             end ; { 3 }
  200.                     end ; { CASE }
  201.                 until (fld < 1) or (fld > 3) ;
  202.                 if (fld > 3) and (fld < maxint) then      { edit only }
  203.                   begin                                   { going forward }
  204.                     edit_date ;
  205.                     if not (bad_fld = 0) then   { Date is bad }
  206.                         begin
  207.                             beep ;
  208.                             fld := bad_fld
  209.                         end
  210.                   end
  211.             until (fld < 1) or (fld > 3) ;
  212.         write_date (dt,col,row) ;
  213.         if fld = 0 then                     { Restore FLD for rest of screen }
  214.                 fld := savefld - 1
  215.         else if fld = 4 then
  216.                 fld := savefld + 1
  217.  
  218.     end ; {--- of read_date ---}
  219.  
  220. { ------------------------------------------------------------ }
  221.  
  222. function greater_date (dt1, dt2 : date) : integer ;
  223.   { Compares two dates, returns 0 if both equal, 1 if first is
  224.     greater, 2 if second is greater.  Converts both to strings,
  225.     then compares the strings. }
  226.  
  227.     var
  228.         stdt1, stdt2 : string[8] ;
  229.         styr1, styr2 : string[4] ;
  230.         stmo1, stmo2 : string[2] ;
  231.         stdy1, stdy2 : string[2] ;
  232.  
  233.     begin
  234.         with dt1 do
  235.             begin
  236.                 str(yr:4,styr1) ;
  237.                 str(mo:2,stmo1) ;
  238.                 str(dy:2,stdy1) ;
  239.                 stdt1 := concat (styr1,stmo1,stdy1)
  240.             end ;
  241.         with dt2 do
  242.             begin
  243.                 str(yr:4,styr2) ;
  244.                 str(mo:2,stmo2) ;
  245.                 str(dy:2,stdy2) ;
  246.                 stdt2 := concat (styr2,stmo2,stdy2)
  247.             end ;
  248.         if stdt1 > stdt2 then
  249.                 greater_date := 1
  250.         else if stdt2 > stdt1 then
  251.                 greater_date := 2
  252.         else { both equal }
  253.                 greater_date := 0
  254.     end ; { --- of greater_date --- }
  255.  
  256. { ------------------------------------------------------------ }
  257.  
  258. procedure greg_to_jul (dt : date ; var jdt : juldate) ;
  259. { converts a gregorian date to a julian date }
  260.   begin
  261.     jdt.yr := dt.yr ;
  262.     if (dt.yr = 0) and (dt.mo = 0) and (dt.dy = 0) then
  263.         jdt.day := 0
  264.     else
  265.       begin
  266.         if (leapyear(dt.yr)) and (dt.mo > 2) then
  267.             jdt.day := 1
  268.         else
  269.             jdt.day := 0 ;
  270.         jdt.day := jdt.day + monthtotal[dt.mo] + dt.dy
  271.       end
  272.   end ;  { --- procedure greg_to_jul --- }
  273.  
  274. { ------------------------------------------------------------ }
  275.  
  276. procedure jul_to_greg (jdt : juldate ; var dt : date) ;
  277. { converts a julian date to a gregorian date }
  278.   var
  279.       i, workday : integer ;
  280.   begin
  281.     dt.yr := jdt.yr ;
  282.     if (jdt.yr = 0) and (jdt.day = 0) then
  283.       begin
  284.         dt.mo := 0 ; dt.dy := 0
  285.       end
  286.     else
  287.       begin
  288.         workday := jdt.day ;
  289.         if (leapyear(jdt.yr)) and (workday > 59) then
  290.             workday := workday - 1 ;   { make it look like a non-leap year }
  291.         i := 1 ;
  292.         repeat
  293.             i := i + 1
  294.         until not (workday > monthtotal[i]) ;
  295.         i := i - 1 ;
  296.         dt.mo := i ;
  297.         dt.dy := workday - monthtotal[i] ;
  298.         if leapyear(jdt.yr) and (jdt.day = 60) then
  299.             dt.dy := dt.dy + 1
  300.       end
  301.   end ;  { --- procedure jul_to_greg --- }
  302.  
  303. { ------------------------------------------------------------ }
  304.  
  305. procedure next_day (var dt : date) ;
  306.   { Adds one day to the date }
  307.     var
  308.         jdt  : juldate ;
  309.         leap : boolean ;
  310.     begin
  311.         greg_to_jul (dt,jdt) ;
  312.         jdt.day := jdt.day + 1 ;
  313.         leap := leapyear (dt.yr) ;
  314.         if (leap and (jdt.day = 367))
  315.         or (not leap and (jdt.day = 366)) then
  316.           begin
  317.             jdt.yr := jdt.yr + 1 ;
  318.             jdt.day := 1
  319.           end ;
  320.         jul_to_greg (jdt,dt)
  321.     end ;  { --- procedure next_day --- }
  322.  
  323. { ------------------------------------------------------------ }
  324.  
  325. procedure prev_day (var dt : date) ;
  326.   { Subtracts one day from the date }
  327.     var
  328.         jdt : juldate ;
  329.     begin
  330.         greg_to_jul (dt,jdt) ;
  331.         jdt.day := jdt.day - 1 ;
  332.         if jdt.day < 1 then
  333.           begin
  334.             jdt.yr := jdt.yr - 1 ;
  335.             if leapyear (jdt.yr) then
  336.                 jdt.day := 366
  337.             else
  338.                 jdt.day := 365
  339.           end ;
  340.         jul_to_greg (jdt,dt)
  341.     end ;  { --- procedure prev_day --- }
  342.  
  343. { ------------------------------------------------------------ }
  344.  
  345. function date_diff (dt1, dt2 : date) : real ;
  346.   { computes the number of days between two dates }
  347.     var
  348.         jdt1, jdt2 : juldate ;
  349.         i, num_leap_yrs : integer ;
  350.     begin
  351.         greg_to_jul (dt1, jdt1) ;
  352.         greg_to_jul (dt2, jdt2) ;
  353.  
  354.         num_leap_yrs := 0 ;         { adjust for leap years }
  355.         if dt2.yr > dt1.yr then
  356.           begin
  357.             for i := dt1.yr to dt2.yr - 1 do
  358.                 if leapyear(i) then
  359.                     num_leap_yrs := num_leap_yrs + 1
  360.           end
  361.         else if dt1.yr > dt2.yr then
  362.           begin
  363.             for i := dt2.yr to dt1.yr - 1 do
  364.                 if leapyear(i) then
  365.                     num_leap_yrs := num_leap_yrs - 1
  366.           end ;
  367.  
  368.         date_diff := jdt2.day - jdt1.day + ((jdt2.yr - jdt1.yr) * 365.0) + num_leap_yrs
  369.     end ;
  370.  
  371. { ------------------------------------------------------------ }
  372.  
  373. function month_diff (dt1, dt2 : date ) : integer ;
  374.   { Computes number of months between two dates, rounded.
  375.     30.4167 = 356/12, average number of days in a month. }
  376.     begin
  377.         month_diff := round((date_diff(dt1, dt2) + 1) / 30.4167)
  378.     end ;
  379.  
  380. { ------------------------------------------------------------ }
  381.  
  382. function equal_date (dt1, dt2 : date) : boolean ;
  383.   { Tests whether two dates are equal }
  384.     begin
  385.         equal_date := (dt1.mo = dt2.mo) and (dt1.dy = dt2.dy)
  386.                       and (dt1.yr = dt2.yr)
  387.     end ;
  388.  
  389. { ----- EOF DATE20.INC --------------------------------------- }
  390. rs + 1
  391.           end
  392.         else if dt1.yr > d