Contributor: DENNIS PASSMORE


unit JDates;

{ A unit providing Julian day numbers and date manipulations.

  NOTE:
   The range of Dates this unit will handle is 1/1/1900 to 1/1/2078

  Version 1.00 - 10/26/1987 - First general release

  Scott Bussinger
  Professional Practice Systems
  110 South 131st Street
  Tacoma, WA  98444
  (206)531-8944
  Compuserve 72247,2671

  Version 1.01 - 10/09/1995 - Updated for use with Delphi v1.0
                   Lets see some other code last this long without change

  Dennis Passmore
  1929 Mango Tree Drive
  Edgewater Fl, 32141

  Compuserve 71240,2464 }

interface
uses
  Sysutils;

const
  BlankDate = $FFFF;                         { Constant for Not-a-real-Date }

type TDate = Word;
     TDay = (Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday);
     TDaySet = set of TDay;

procedure GetDate(var Year,Month,Day,Wday: Word);
  { replacement for old WINDOS proc }

procedure GetTime(var Hour,Min,Sec,MSec: Word);
  { replacement for old WINDOS proc }

function  CurrentJDate: Tdate;

function  ValidDate(Day,Month,Year: Word): boolean;
  { Check if the day,month,year is a real date storable in a Date variable }


procedure DMYtoDate(Day,Month,Year: Word;var Julian: TDate);
  { Convert from day,month,year to a date }

procedure DateToDMY(Julian: TDate;var Day,Month,Year: Word);
  { Convert from a date to day,month,year }

function BumpDate(Julian: TDate;Days,Months,Years: Integer): TDate;
  { Add (or subtract) the number of days, months, and years to a date }

function DayOfWeek(Julian: TDate): TDay;
  { Return the day of the week for the date }

function DayString(WeekDay: TDay): string;
  { Return a string version of a day of the week }

function MonthString(Month: Word): string;
  { Return a string version of a month }

function DateToStr(Julian: TDate): string;
  { Convert a date to a sortable string }

function StrToDate(StrVar: string): TDate;
  { Convert a sortable string form to a date }

implementation

procedure GetDate(var Year,Month,Day,Wday: Word);
var
  td: TDatetime;
begin
  td := Date;

  DeCodeDate(td,Year,Month,Day);
  Wday := sysutils.DayofWeek(td);
end;

procedure GetTime(var Hour,Min,Sec,MSec: Word);
var
  td: TDatetime;
begin
  td := Now;
  DecodeTime(td,Hour,Min,Sec,MSec);
end;

function  CurrentJdate: Tdate;
var
 y,m,d,w: word;
 jd: TDate;
begin
  GetDate(y,m,d,w);
  DMYtoDate(d,m,y,jd);
  CurrentJDate:= jd;
end;

function ValidDate(Day,Month,Year: Word): boolean;
  { Check if the day,month,year is a real date storable in a Date variable }
begin
  if {(Day<1) or }(Year<1900) or (Year>2078) then
    ValidDate := false
  else
    case Month of
      1,3,5,7,8,10,12: ValidDate := Day <= 31;

      4,6,9,11: ValidDate := Day <= 30;
      2: ValidDate := Day <= 28 + ord((Year mod 4)=0)*ord(Year<>1900)
      else ValidDate := false
    end
end;

procedure DMYtoDate(Day,Month,Year: Word;var Julian: TDate);
  { Convert from day,month,year to a date }
  { Stored as number of days since January 1, 1900 }
  { Note that no error checking takes place in this routine -- use ValidDate }
begin
if (Year=1900) and (Month<3) then
  if Month = 1 then
    Julian := pred(Day)
  else
    Julian := Day + 30
else
  begin
    if Month > 2 then
      dec(Month,3)
    else
      begin
        inc(Month,9);
        dec(Year)

      end;
    dec(Year,1900);
    Julian := (1461*longint(Year) div 4) + ((153*Month+2) div 5) + Day + 58;
  end
end;

procedure DateToDMY(Julian: TDate;var Day,Month,Year: Word);
  { Convert from a date to day,month,year }
var
  LongTemp: longint;
      Temp: Word;
begin
  if Julian <= 58 then
    begin
      Year := 1900;
      if Julian <= 30 then
        begin
          Month := 1;
          Day := succ(Julian)
        end
      else
        begin
          Month := 2;
          Day := Julian - 30
        end
    end
  else
    begin
      LongTemp := 4*longint(Julian) - 233;

      Year := LongTemp div 1461;
      Temp := LongTemp mod 1461 div 4 * 5 + 2;
      Month := Temp div 153;
      Day := Temp mod 153 div 5 + 1;
      inc(Year,1900);
      if Month < 10 then
        inc(Month,3)
      else
        begin
          dec(Month,9);
          inc(Year)
        end
    end
end;

function BumpDate(Julian: TDate;Days,Months,Years: Integer): TDate;
  { Add (or subtract) the number of days, months, and years to a date }
  { Note that months and years are added first before days }
  { Note further that there are no overflow/underflow checks }
var Day: Word;
    Month: Word;
    Year: Word;
begin
  DateToDMY(Julian,Day,Month,Year);

  Month := Month + Months - 1;
  Year := Year + Years + (Month div 12) - ord(Month<0);
  Month := (Month + 12000) mod 12 + 1;
  DMYtoDate(Day,Month,Year,Julian);
  BumpDate := Julian + Days
end;

function DayOfWeek(Julian: TDate): TDay;
  { Return the day of the week for the date }
begin
  DayOfWeek := TDay(succ(Julian) mod 7)
end;

function DayString(WeekDay: TDay): string;
  { Return a string version of a day of the week }
const DayStr: array[Sunday..Saturday] of string[9] =
     ('Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday');

begin
  DayString := DayStr[WeekDay]
end;

function MonthString(Month: Word): string;
  { Return a string version of a month }
  const MonthStr: array[1..12] of string[9] =
     ('January','February','March','April','May','June','July','August',
                                 'September','October','November','December');
begin
  MonthString := MonthStr[Month]
end;

function DateToStr(Julian: TDate): string;
  { Convert a date to a sortable string - NOT displayable }
const tResult: record
                case integer of
                  0: (Len: byte;  W: word);
                  1: (Str: string[2])

                end = (Str:'  ');
begin
  tResult.W := swap(Julian);
  DateToStr := tResult.Str
end;

function StrToDate(StrVar: string): TDate;
  { Convert a sortable string form to a date }
var Temp: record
            Len: byte;
              W: word
          end absolute StrVar;
begin
  StrToDate := swap(Temp.W)
end;

end.