home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / INFO / TURBOPAS / EXDATE.ZIP / EXDATE.PAS next >
Encoding:
Pascal/Delphi Source File  |  1988-01-04  |  6.9 KB  |  214 lines

  1. unit exdate;
  2.  
  3. {      EXDATE.PAS  -- Turbo Pascal Extended Date Subroutines
  4.  
  5.        Author: Ted Lassagne
  6.                Cor Communications
  7.                P. O. Box 1587
  8.                Cupertino, CA  95015
  9.                (Compuserve 70325,206)
  10.  
  11.  This is a collection of useful calendar date subroutines which are
  12.  valid from October 15, 1582 until such time as the Gregorian calendar
  13.  is replaced.  Note that Great Britain did not change to the Gregorian
  14.  calendar until 1752, Russia until 1918, and Turkey until 1928.  (These
  15.  routines will work until the year 32767; after that, you will need
  16.  to replace ints with longints.)
  17.  
  18.  The day of the week algorithm derivation is described very well in
  19.  Rosen's "Elementary Number Theory and Its Applications" (Addison-Wesley,
  20.  1984, pp 134-137).  The ordinal day algorithms are derived using
  21.  reasoning similar to that of Rosen's derivation.  The serial day
  22.  algorithms are based upon Julian day algorithms in Algorithm 199
  23.  by Robert G. Tantzen in Communications of the ACM  6, 8 (Aug 1963),
  24.  page 444.}
  25.  
  26. {==================================================================}
  27.  
  28.                          INTERFACE
  29.  
  30. function day_of_week (day, month, year: integer) : integer;
  31. {Returns integer day of week for date.  0 = Sunday, 6 = Saturday}
  32.  
  33.  
  34. function ordinal_day (day, month, year: integer) : integer;
  35. {Returns ordinal day of year (1-366) for date}
  36.  
  37. procedure from_ordinal_day (ordinal_day, year: integer;
  38.     var day, month: integer);
  39. {Returns day and month for ordinal_day of a year}
  40.  
  41.  
  42. function valid_date(day, month, year: integer) : boolean;
  43. {Returns true if day, month, year represent a valid date}
  44.  
  45.  
  46. function day_diff(day_1, month_1, year_1, day_2, month_2, year_2: integer)
  47.    : longint;
  48. {Returns the number of days between two dates, the first date being denoted
  49.  by day_1, month_1, year_1, and the second by day_2, month_2, year_2.
  50.  A negative value means that the second date is earlier than the first date.}
  51.  
  52. procedure days_from(day, month, year, days: integer;
  53.     var new_day, new_month, new_year: integer);
  54. {Returns a date (new_day, new_month, new_year) which is a specified number
  55.  of days (days) from a given date (day, month, year).   The number of days
  56.  may be positive or negative.}
  57.  
  58.  
  59.   {The following auxiliary procedures are in the interface just in case
  60.    they may be useful for other purposes.}
  61.  
  62. function leap_year(year: integer) : integer;
  63.    { Returns 1 for a leap year and 0 for others }
  64.  
  65. function serial_day(day, month, year: integer) : longint;
  66. {Converts a date to a "serial day" for performing calendar arithmetic.
  67.  The serial day is the classic Julian date less 1721119.}
  68.  
  69. procedure from_serial_day (serial_day: longint;
  70.     var day, month, year:integer);
  71. {Returns the day, month, year corresponding to a "serial day".}
  72.  
  73. {==================================================================}
  74.  
  75.                         IMPLEMENTATION
  76.  
  77. function day_of_week (day, month, year: integer) : integer;
  78. {Returns integer day of week for date.  0 = Sunday, 6 = Saturday
  79.  Uses Zeller's congruence.}
  80.    var century, yr, dw: integer;
  81.    begin
  82.       if month < 3 then begin
  83.          month := month + 10;
  84.          year := year -1
  85.          end
  86.       else
  87.          month := month - 2;
  88.       century := year div 100;
  89.       yr := year mod 100;
  90.       dw := (((26*month - 2) div 10)+day+yr+(yr div 4)+
  91.          (century div 4) - (2*century)) mod 7;
  92.       if dw < 0 then day_of_week := dw + 7 else day_of_week := dw;
  93.    end;
  94.  
  95.  
  96.  
  97. function leap_year(year: integer) : integer;
  98.    { Returns 1 for a leap year and 0 for others }
  99.    begin
  100.    if year and 3 <> 0 then leap_year := 0
  101.    else if year mod 100 <> 0 then leap_year := 1
  102.    else if year mod 400 <> 0 then leap_year := 0
  103.    else leap_year := 1;
  104.    end;
  105.  
  106. function ordinal_day (day, month, year: integer) : integer;
  107. {Returns ordinal day of year (1-366) for date}
  108.    var od: integer;
  109.    begin
  110.    if month < 3 then
  111.       month := month + 10
  112.    else
  113.       month := month - 2;
  114.    od := (306 * month - 2) div 10 - 30;
  115.    if od < 306 then
  116.       ordinal_day := od + 59 + leap_year(year) + day
  117.    else
  118.       ordinal_day := od - 306 + day;
  119.    end;
  120.  
  121. procedure from_ordinal_day (ordinal_day, year: integer;
  122.     var day, month: integer);
  123. {Returns day and month for ordinal day of a year}
  124.    var lyf, adj_mo: integer;
  125.    begin
  126.    lyf := leap_year(year) + 60;
  127.    if ordinal_day < lyf then
  128.       ordinal_day := ordinal_day + 305
  129.    else
  130.       ordinal_day := ordinal_day - lyf;
  131.    adj_mo := (ordinal_day * 10 + 4) div 306 + 1;
  132.    day := ordinal_day - ((adj_mo * 306 - 2) div 10 - 30) + 1;
  133.    if adj_mo < 11 then
  134.       month := adj_mo + 2
  135.    else
  136.       month := adj_mo - 10;
  137.    end;
  138.  
  139. function valid_date(day, month, year: integer) : boolean;
  140. {Determines whether a date is valid by transforming to an ordinal and
  141.  trying to transform it back again.}
  142.    var od, m, d: integer;
  143.    begin
  144.    od := ordinal_day(day, month, year);
  145.    if (od > 366) or (od < 1) then
  146.       valid_date := false
  147.    else begin
  148.       from_ordinal_day(od, year, d, m);
  149.       if (d = day) and (m = month) then valid_date := true
  150.       else valid_date := false
  151.    end;
  152.    end;
  153.  
  154. function serial_day(day, month, year: integer) : longint;
  155. {Converts a date to a "serial day" for performing calendar arithmetic.
  156.  The serial day is the classic Julian date less 1721119.}
  157. var  m, y : longint;
  158.    begin
  159.       if month > 2 then begin
  160.          m := month - 3;
  161.          y := year;
  162.       end
  163.       else begin
  164.          m := month + 9;
  165.          y := year - 1;
  166.       end;
  167.  
  168.       serial_day :=
  169.          ((y div 100) * 146097) div 4 +
  170.          ((y mod 100) * 1461) div 4 +
  171.          (153 * m + 2) div 5 + day;
  172.    end;
  173.  
  174. function day_diff(day_1, month_1, year_1, day_2, month_2, year_2: integer)
  175.    : longint;
  176. {Returns the number of days between two dates. A negative value means that the
  177.  second date is earlier than the first date.}
  178.    begin
  179.    day_diff := serial_day(day_2, month_2, year_2) -
  180.       serial_day(day_1, month_1, year_1);
  181.    end;
  182.  
  183. procedure from_serial_day (serial_day: longint;
  184.     var day, month, year:integer);
  185. {Returns the date corresponding to a "serial day".}
  186.    var j, d : longint;
  187.    begin
  188.       j := serial_day * 4 - 1;
  189.       d := ((j mod 146097) div 4) * 4 + 3;
  190.       year := (j div 146097) * 100 + (d div 1461);
  191.       d := (((d mod 1461) + 4) div 4) * 5 - 3;
  192.       month := d div 153;
  193.       day := ((d mod 153) + 5) div 5;
  194.  
  195.       if month < 10 then
  196.          month := month + 3
  197.       else begin
  198.          month := month - 9;
  199.          year := year + 1;
  200.       end;
  201.    end;
  202.  
  203. procedure days_from(day, month, year, days: integer; var new_day,
  204.       new_month, new_year: integer);
  205. {Returns a date which is a specified number of days from a given date.
  206.  The number of days may be positive or negative.}
  207.    begin
  208.    from_serial_day(serial_day(day, month, year) + days,
  209.       new_day, new_month, new_year);
  210.    end;
  211.  
  212. begin
  213. end.
  214.