Link to home
Start Free TrialLog in
Avatar of binho
binho

asked on

# of months between 2 dates

How can I get the number of months between 2 dates?
For example: 01-jan-2000 and 02-feb-2000. I can have the # of days (Date2 - Date1). I can even "get" the # of months dividing it by 30, but it's not an EXACT calculation...
Any idea?
Avatar of jeurk
jeurk

hello pasted from the rxlib :

function DaysPerMonth(AYear, AMonth: Integer): Integer;
const
  DaysInMonth: array[1..12] of Integer =
    (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
begin
  Result := DaysInMonth[AMonth];
  if (AMonth = 2) and IsLeapYear(AYear) then Inc(Result); { leap-year Feb is special }
end;

procedure DateDiff(Date1, Date2: TDateTime; var Days, Months, Years: Word);
{ Corrected by Anatoly A. Sanko (2:450/73) }
var
  DtSwap: TDateTime;
  Day1, Day2, Month1, Month2, Year1, Year2: Word;
begin
  if Date1 > Date2 then begin
    DtSwap := Date1;
    Date1 := Date2;
    Date2 := DtSwap;
  end;
  DecodeDate(Date1, Year1, Month1, Day1);
  DecodeDate(Date2, Year2, Month2, Day2);
  Years := Year2 - Year1;
  Months := 0;
  Days := 0;
  if Month2 < Month1 then begin
    Inc(Months, 12);
    Dec(Years);
  end;
  Inc(Months, Month2 - Month1);
  if Day2 < Day1 then begin
    Inc(Days, DaysPerMonth(Year1, Month1));
    if Months = 0 then begin
      Dec(Years);
      Months := 11;
    end
    else Dec(Months);
  end;
  Inc(Days, Day2 - Day1);
end;

function MonthsBetween(Date1, Date2: TDateTime): Double;
var
  D, M, Y: Word;
begin
  DateDiff(Date1, Date2, D, M, Y);
  Result := 12 * Y + M;
  if (D > 1) and (D < 7) then Result := Result + 0.25
  else if (D >= 7) and (D < 15) then Result := Result + 0.5
  else if (D >= 15) and (D < 21) then Result := Result + 0.75
  else if (D >= 21) then Result := Result + 1;
end;

this should be it...
I think this is better and 100% accurate:

procedure TForm1.Button1Click(Sender: TObject);
var Date1, Date2: TDateTime;
    y1, y2, m1, m2, d1, d2: Word;
begin
  Date1 := Round(MonthCalendar1.Date);
  Date2 := Round(MonthCalendar2.Date);
  DecodeDate(Date1, y1 , m1, d1);
  DecodeDate(Date2, y2 , m2, d2);
  Label1.Caption := IntToStr(m2 - m1) + ' months between the two dates';
  Label2.Caption := FloatToStr((Date2 - Date1))
                  + ' days between the two dates';
end;
Avatar of binho

ASKER

Epsylon:
I don't think this works. If I take 31-jan-2000 as Date1 and 01-feb-2000 as Date2, the code you wrote returns 1 months, but it's wrong!...
And if I take 01-jan-2000 and 15-jan-2001, it returns 0 months, but it should be 12...

Jeurk:
If I have a 29 day february, I have a problem with your code...
Why ? the fact is handled with :
if (AMonth = 2) and IsLeapYear(AYear) then Inc(Result); { leap-year Feb is special }  No ?
Still a problem ?
ASKER CERTIFIED SOLUTION
Avatar of Epsylon
Epsylon

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of binho

ASKER

Epsylon worked out fine...
I hope you're right  :o)

I did some testing but not excessively.

Cheers.