Topic: разница между двумя датами количество лет месяцев дней

Добрый вечер
Появилась необходимость посчитать разницу между двумя датами (стаж работы) по типу сколько лет, месяцев, дней
Есть таблица: dates
Колонки: data1 data2
в колонку data1 - записывается начальная дата (к примеру 01.04.2020)
в колонку data2 - записывается конечная дата (к примеру 16.04.2020)
Результат = 0 лет 0 месяцев 16 дней

сами функции подсчета правописания дней, месяцев, лет

// Вывод строки дней
function StrDays(iDay: integer): string;
begin
  Result:= ' дней ';
  case iDay of
    1, 21, 31: Result:= ' день ';
    2, 3, 4, 22, 23, 24: Result:= ' дня ';
  end;
end;

// Вывод строки месяцев
function StrMonths(iMonth: integer): string;
begin
  Result:= ' месяцев ';
  case iMonth of
    1: Result:= ' месяц ';
    2, 3, 4: Result:= ' месяца ';
  end;
end;

// Вывод строки лет
function StrYears(iYear: integer): string;
var
  s: string;
  sYear: string;
  i: integer;
begin
  result := ' лет ';
  if (iYear > 4) and (iYear < 21) then exit;
  sYear := IntToStr(iYear);
  s := Copy(sYear, Length(sYear), 1);
  i := StrToInt(s);
  case i of
    1: result := ' год ';
    2, 3, 4: result := ' года ';
  end;
end;

// Сама функция
function StrBetweenDate(Date1, Date2: TDate): string;
var
  id, im, iy: Integer;
  d: TDate;
begin
  Result:= '';
  if Date1 < Date2 then
  begin
    d:= Date1;
    Date1:= Date2;
    Date2:= d;
    Date1:= Date1 + 1;
  end;
  d:= DaysBetween(Date1 + 1, Date2);
  id:= DayOf(d);
  im:= MonthOf(d)-1;
  iy:= YearOf(d);
  iy:= iy - 1900;
  if im = 12 then
    begin
      im:= 0;
      inc(iy);
    end;
  if id = 31 then
  begin
    id:= 0;
    inc(im);
    if im = 12 then
    begin
      im:= 0;
      inc(iy);
    end;
  end;
  Result:= (IntToStr(iy)+ StrYears(iy) + IntToStr(im) +
            StrMonths(im) + IntToStr(id)+ StrDays(id));
end;

Использование

procedure Form1_Button3_OnClick(Sender: string);
var
  dt1, dt2: TDateTime;
begin
  dt1:=SQLExecute('SELECT StrToDate(data1) FROM dates  WHERE id='+Form1.TableGrid1.sqlValue);
  dt2:=SQLExecute('SELECT StrToDate(data2) FROM dates  WHERE id='+Form1.TableGrid1.sqlValue);
  ShowMessage(StrBetweenDate(dt1, dt2));
end;

по разному уже пробовал использовать данные с таблицы (и уже просто даты вписывал в dt1 и dt2, все время ошибка
List index out of bounds (1)
Что делаю не так, можете подсказать или направить?

2 (edited by vit007 2020-04-17 08:03:44)

Re: разница между двумя датами количество лет месяцев дней

у меня в проекте разность реализована так

if ((Trunc(frmAddNote.DateTimePicker1.DateTime) - Trunc(Now)) <0) then ShowHint(frmAddNote.DateTimePicker1, 'Неверное значение даты') else

3 (edited by eugene1995miroshnikov 2020-04-17 19:03:07)

Re: разница между двумя датами количество лет месяцев дней

vit007 wrote:

у меня в проекте разность реализована так

if ((Trunc(frmAddNote.DateTimePicker1.DateTime) - Trunc(Now)) <0) then ShowHint(frmAddNote.DateTimePicker1, 'Неверное значение даты') else

В какой цели Вы это используете? Какой результат?
В этой функции я не уверен что будет правильный результат, мне необходимо посчитать разницу в n-лет n-месяцев n-дней, необходимо учитывать количество дней в месяце

Re: разница между двумя датами количество лет месяцев дней

Идет сравнение дат с сегодняшней, в случаи отрицательной разности выкидывает сообщение...

5 (edited by eugene1995miroshnikov 2020-04-22 18:28:39)

Re: разница между двумя датами количество лет месяцев дней

Проблема не решена...
думаю проблема из-за отсутствия методов в mvd

id:= DayOf(d);
im:= MonthOf(d)-1;
iy:= YearOf(d);

Кто нибудь сталкивался с подсчетом количества n-лет n-месяцев n-дней? количество дней посчитать могу, но решение общее количество дней делить на количество дней в году, месяце - плохое решение, будет не точность
Или каким способом можно прикрутить то что я хочу в вычислительное поле?

Re: разница между двумя датами количество лет месяцев дней

Попробуйте так

function DateDiff(date1, date2: TDateTime): string;
var
    years, months, days: integer;
    monthsTotal: integer;

    minDate: TDateTime;
    i, c: integer;
    DD, MM, YY: word;
begin
   date1 := trunc(date1);
   date2 := trunc(date2);


    years := YearsBetween(date1, date2);
    monthsTotal := MonthsBetween(date1, date2);
    months := monthsTotal - (years * 12);

    if date1 > date2 then minDate := date2 else minDate := date1;

    date1 := IncMonth(minDate, monthsTotal);
    days := DaysBetween(date1, date2);

    result := 'Days:' + IntToStr(days)+', Months:'+IntToStr(months)+', Years:'+IntToStr(years);
end;

Но не уверен, что результат на 100% правильный.
Есть ньюанс для подсчета лет
http://docwiki.embarcadero.com/Librarie … arsBetween

Dmitry.

Re: разница между двумя датами количество лет месяцев дней

DriveSoft wrote:

Попробуйте так

function DateDiff(date1, date2: TDateTime): string;
var
    years, months, days: integer;
    monthsTotal: integer;

    minDate: TDateTime;
    i, c: integer;
    DD, MM, YY: word;
begin
   date1 := trunc(date1);
   date2 := trunc(date2);


    years := YearsBetween(date1, date2);
    monthsTotal := MonthsBetween(date1, date2);
    months := monthsTotal - (years * 12);

    if date1 > date2 then minDate := date2 else minDate := date1;

    date1 := IncMonth(minDate, monthsTotal);
    days := DaysBetween(date1, date2);

    result := 'Days:' + IntToStr(days)+', Months:'+IntToStr(months)+', Years:'+IntToStr(years);
end;

Но не уверен, что результат на 100% правильный.
Есть ньюанс для подсчета лет
http://docwiki.embarcadero.com/Librarie … arsBetween

Спасибо огромное... Как мне правильно использовать функцию, если мне необходимо получить данные по нажатию в TableGrid на n-строку и вывести в Label?
В TableGrid используется таблица Poslu, в таблице две колонки типа Дата PosluDate (начальная дата) PosluDateEnd (конечная дата)
в TableGrid событие OnCellClick

Мой код:

procedure frmClient_gridPoslu_OnCellClick (Sender:  TObject; ACol, ARow: Integer; Action: string);
var
years, months, days: integer;
    monthsTotal: integer;

    minDate: TDateTime;
    i, c: integer;
    DD, MM, YY: word;

date1, date2:  TDateTime;
begin

frmClient.gridPoslu.BeginUpdate;
    date1:= SQLExecute('SELECT PosluDate FROM Poslu WHERE id='+IntToStr(frmClient.gridPoslu.dbItemID));
    date2:= SQLExecute('SELECT PosluDateEnd FROM Poslu WHERE id='+IntToStr(frmClient.gridPoslu.dbItemID));

date1 := trunc(date1);
   date2 := trunc(date2);

    years := YearsBetween(date1, date2);
    monthsTotal := MonthsBetween(date1, date2);
    months := monthsTotal - (years * 12);

    if date1 > date2 then minDate := date2 else minDate := date1;

    date1 := IncMonth(minDate, monthsTotal);
    days := DaysBetween(date1, date2);

    frmClient.Label7.Caption := 'Days:' + IntToStr(days)+', Months:'+IntToStr(months)+', Years:'+IntToStr(years);
    frmClient.gridPoslu.EndUpdate;
end;

Получаю ошибку could not convert variant of type (unicodestring) into type (double)

Если заменяю

    
date1:= SQLExecute('SELECT PosluDate FROM Poslu WHERE id='+IntToStr(frmClient.gridPoslu.dbItemID));
date2:= SQLExecute('SELECT PosluDateEnd FROM Poslu WHERE id='+IntToStr(frmClient.gridPoslu.dbItemID));

На

    date1:= frmClient.DateTimePicker2.DateTime;
    date2:= frmClient.DateTimePicker5.DateTime;

То все хорошо и результат верный... но как сделать не через DateTimePicker?

Re: разница между двумя датами количество лет месяцев дней

date1:= (strtodate(frmClient.gridPoslu.Cells[0, frmClient.gridPoslu.SelectedRow]));
date2:= (strtodate(frmClient.gridPoslu.Cells[1, frmClient.gridPoslu.SelectedRow]));