Экспертная система Delphi.int.ru

Сообщество программистов
Общение, помощь, обмен опытом

Логин:
Пароль:
Регистрация | Забыли пароль?

Delphi.int.ru Expert

Другие разделы портала

Переход к вопросу:

#   

Статистика за сегодня:  


Лучшие эксперты

DNK
I. DNK
Баллы: 5

Подробнее »



Вопрос # 6 648

/ вопрос открыт /

Доброго времени суток, уважаемые эксперты!


Подскажите кто знает, нужно выводить к-во отработанных лет,месяцев,дней (другими словами высчитать стаж). Сделал так, ниже код, но проблема с февралем, нужно трактовать занятый месяц: 1 месяц = 28, 29, 30, 31 дней? Вдобавок, дело осложняется с высокосностью годов.

Если поставить с 01.02 по 28.02 должно получится 0 лет 1 месяц 0 дней (получается 0 лет 0 месяцев 28 дней), а с 01.02 по 01.03 0лет 1 месяц 1 день (получается 0 лет 0 месяцев 29 дней), 2й вариант с DecodeDate тоже не корректно работает

Приложение:
  1.  
  2. function StrBetweenDate(Date1, Date2: TDate): string;
  3. var
  4. id, im, iy: Integer;
  5. d: TDate;
  6. begin
  7. Result:= '';
  8. if Date1 < Date2 then
  9. begin
  10. d:= Date1;
  11. Date1:= Date2;
  12. Date2:= d;
  13. Date1:= Date1 + 1;
  14. end;
  15. d:= DaysBetween(Date1 + 1, Date2);
  16. id:= DayOf(d);
  17. im:= MonthOf(d)-1;
  18. iy:= YearOf(d);
  19. iy:= iy - 1900;
  20.  
  21. if im = 12 then
  22. begin
  23. im:= 0;
  24. inc(iy);
  25. end;
  26.  
  27.  
  28. if id = 31 then
  29. begin
  30. id:= 0;
  31. inc(im);
  32.  
  33. if im = 12 then
  34. begin
  35. im:= 0;
  36. inc(iy);
  37. end;
  38. end;
  39. Result:= (IntToStr(iy)+ StrYears(iy) + IntToStr(im) +
  40. StrMonths(im) + IntToStr(id)+ StrDays(id));
  41. end;
  42.  
  43. procedure TForm1.Button1Click(Sender: TObject);
  44. var
  45. aDate, date1: TDateTime;
  46.  
  47. begin
  48. aDate := DateTimePicker1.Date;
  49. date1 := DateTimePicker2.Date;
  50.  
  51. label5.Caption := StrBetweenDate(aDate, date1);
  52.  
  53.  
  54. var
  55. aDate, date1,dtDiff: TDateTime;
  56. dd, mm, yy, days: Word;
  57. str: string;
  58. begin
  59. aDate := DateTimePicker1.Date;
  60. date1 := DateTimePicker2.Date;
  61.  
  62. days := DayOfTheYear(aDate) - 1;
  63. DecodeDate((date1 - Days), yy, mm, dd);
  64. yy := yy - YearOf(aDate);
  65. str := Format('Year: %d', [yy]) + #13#10 +
  66. Format('Month: %d', [mm]) + #13#10 +
  67. Format('Day: %d', [dd]);
  68. ShowMessage(str);


casio Вопрос ожидает решения (принимаются ответы, доступен мини-форум)

Вопрос задал: casio (статус: Посетитель)
Вопрос отправлен: 12 февраля 2017, 16:23
Состояние вопроса: открыт, ответов: 1.

Ответ #1. Отвечает эксперт: DNK

Здравствуйте, casio!

function TForm1.DaysOfMonth( mm, yy: integer ): integer;
begin
   if mm = 2 then
   begin
      Result := 28;
      if IsLeapYear( yy ) then Result := 29;
   end
   else
   begin
      if mm < 8 then
      begin
         if ( mm mod 2 ) = 0 then
            Result := 30
         else
            Result := 31;
      end
      else
      begin
         if ( mm mod 2 ) = 0 then
            Result := 31
         else
            Result := 30;
      end;
   end;
end;
 
function TForm1.StrBetweenDate(Date1, Date2: TDate): string;
var
  to_date, from_date: TDateTime;
  y1, y2, m1, m2, d1, d2, Full_Months, Days: Integer; 
begin
  to_date:=DateTimePicker1.DateTime;
  from_date:=DateTimePicker2.DateTime;
 
  DecodeDate(from_date,y1,m1,d1);
  DecodeDate(to_date,y2,m2,d2);
 
  Full_Months:=(y1-y2)*12+(m1-m2);
 
  // если дни в конечной дате меньше чем в начальной
  If d1<d2 then begin
    // вычитаем один месяц
    Full_Months:=Full_Months-1;
    // из количества дней в предпоследнем месяце вычитаем дни  начальной даты и прибавляем дни конечной
    Days := MonthDays(m1 - 1, y1) - d2 + d1;
  end else
    // иначе просто находим разницу в днях
    Days := d1 - d2;
  Inc(Days);
  Result := Format('Month: %d'#13#10'Day: %d', [Full_Months, Days]);
end;

Ответ отправил: DNK (статус: Студент)
Время отправки: 20 февраля 2017, 21:06


Мини-форум вопроса

Всего сообщений: 11; последнее сообщение — 19 февраля 2017, 16:19; участников в обсуждении: 2.
DNK

DNK (статус: Студент), 12 февраля 2017, 19:29 [#1]:

Тут надо сначала декодировать обе даты и потом отдельно вычитать сначала года, потом месяцы и потом дни. Если при вычитании месяцев или дней получается отрицательное число, занять 1 у предыдущей части результата.
"Digital Networked Knight"
casio

casio (статус: Посетитель), 12 февраля 2017, 22:36 [#2]:

DNK: спасибо, разобрался, считает верно, подскажите как сделать для моего варианта что бы было в первом варианте 28 дней/29 дней, а во втором 1месяц 1день
1) с 01.02.17 по 28.08.17 - отображает 27 дней
2) с 01.02.17 по 01.03.17 показывает 1 месяц,

to_date:=DateTimePicker1.DateTime;
from_date:=DateTimePicker2.DateTime;
 
   DecodeDate(from_date,y1,m1,d1);
DecodeDate(to_date,y2,m2,d2);
 
 Full_Months:=(y1-y2)*12+(m1-m2);
 
If d1<d2 then
 
   Full_Months:=Full_Months-1;
 
Days:=Round(from_date-to_date);
For i:=1 to Full_Months do
begin
   DayTable:=MonthDays[IsLeapYear(y2)];
   k:=DayTable[m2];
   Days:=Days-k;
   m2:=m2+1;
   If m2>12 then
   begin
      y2:=y2+1;
      m2:=1;
   end;
end;
DNK

DNK (статус: Студент), 12 февраля 2017, 23:12 [#3]:

If d1<d2 then
   Full_Months:=Full_Months-1;

Вот до этих строчек всё четко. Дальше хрень полная. Я бы сделал примерно так:

// если дни в конечной дате меньше чем в начальной
If d1<d2 then begin
    // вычитаем один месяц
    Full_Months:=Full_Months-1;
    // из количества дней в предпоследнем месяце вычитаем дни  начальной даты и прибавляем дни конечной
    Days := MonthDays(m1 - 1, y1) - d2 + d1;
end else
    // иначе просто находим разницу в днях
    Days := d1 - d2;
"Digital Networked Knight"
casio

casio (статус: Посетитель), 12 февраля 2017, 23:30 [#4]:

DNK:
Days := MonthDays(m1 - 1, y1) - d2 + d1;
выбивает в этой строке ошибку
DNK

DNK (статус: Студент), 12 февраля 2017, 23:36 [#5]:

И догадываюсь какую... Функцию нахождения количества дней в месяце сам реализовывать способен?
"Digital Networked Knight"
casio

casio (статус: Посетитель), 12 февраля 2017, 23:45 [#6]:

DNK:
вроде этого?
function TForm1.DaysOfMonth( mm, yy: integer ): integer;
begin
   if mm = 2 then
   begin
      Result := 28;
      if IsLeapYear( yy ) then Result := 29;
   end
   else
   begin
      if mm < 8 then
      begin
         if ( mm mod 2 ) = 0 then
            Result := 30
         else
            Result := 31;
      end
      else
      begin
         if ( mm mod 2 ) = 0 then
            Result := 31
         else
            Result := 30;
      end;
   end;
end;
casio

casio (статус: Посетитель), 12 февраля 2017, 23:56 [#7]:

DNK: согласно вашему коду сократилось на 11 стр кода, спасибо))) но не получилось все равно реализовать задуманное,
1) с 01.02.17 по 28.08.17 - отображает 27 дней (должно быть 28 дней)
2) с 01.02.17 по 01.03.17 показывает 1 месяц(должно быть 1месяц 1 день)
DNK

DNK (статус: Студент), 13 февраля 2017, 00:46 [#8]:

следуя этой логике: с 1.02.17 по 1.02.17 должно быть 1 день?
хочешь странного...
"Digital Networked Knight"
casio

casio (статус: Посетитель), 14 февраля 2017, 10:48 [#9]:

DNK: Как не странно но так и есть, в рабочий стаж зачитывается день увольнения, праздничные,выходные.
вот пример с онлайн калькулятора http://savepic.ru/12962179.jpg
DNK

DNK (статус: Студент), 14 февраля 2017, 20:57 [#10]:

Очевидно же, к дням надо единичку прибавить
"Digital Networked Knight"
casio

casio (статус: Посетитель), 19 февраля 2017, 16:19 [#11]:

DNK: спасибо,вроде получилось!

Чтобы оставлять сообщения в мини-форумах, Вы должны авторизироваться на сайте.

Версия движка: 2.6+ (26.01.2011)
Текущее время: 22 июля 2017, 01:50
Выполнено за 0.05 сек.
Рейтинг@Mail.ru