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

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

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

Delphi.int.ru Expert

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

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

#   

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


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

Подробнее »



Вопрос # 3 377

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

Приветствую, уважаемые эксперты!
Jedi TJvTFDays
Событие получается на текущую дату и время и длительностью минута.
В чем я ошибаюсь?

К вопросу прикреплён файл. Загрузить » (срок хранения: 60 дней с момента отправки вопроса)

Приложение:
  1. procedure TfrmMain.NewTimeLineItem(ShedName: string;
  2. DiscriptionApp: string;
  3. AppColor: TColor;
  4. StartDate: TDate;
  5. EndDate: TDate;
  6. StartTime: TTime;
  7. EndTime: TTime;
  8. AppAlarmEnabled: Boolean;
  9. AppAlarmAdvance: Integer);
  10. var
  11. Appt : TJvTFAppt;
  12. DaysGrid: TJvTFDays;
  13. i: integer;
  14. // NewAppt: Boolean;
  15. begin
  16. showmessage(DateTimeToStr(Startdate)+#13+DateTimeToStr(Enddate)+#13+
  17. DateTimeToStr(StartTime)+#13+DateTimeToStr(EndTime));
  18. Appt := JvTFDays1.ScheduleManager.dbNewAppt('');
  19. Appt.Persistent:= True;
  20. with Appt do
  21. begin
  22. BeginUpdate;
  23. AddSchedule(ShedName);
  24. SetStartEnd(StartDate, StartTime, EndDate, EndTime);
  25. Description:=DiscriptionApp+' '+ DateTimeToStr(Appt.StartDateTime)+' '+ DateTimeToStr(Appt.EndDateTime);
  26. AlarmEnabled:=AppAlarmEnabled;
  27. AlarmAdvance:=AppAlarmAdvance;
  28. BarColor:=clGreen;
  29. Appt.Color:=AppColor;
  30.  
  31. if DaysGrid.ValidSelection then
  32. for i:=DaysGrid.SelStart.X to DaysGrid.SelEnd.X do
  33. Appt.AddSchedule(DaysGrid.Cols[i].SchedName);
  34.  
  35.  
  36. Persistent:= False;
  37. Post;
  38. EndUpdate;
  39. JvTFScheduleManager1.RefreshAppts;
  40. JvTFDays1.Refresh;
  41.  
  42. end;
  43.  
  44. Appt:=nil;
  45. ResourceCombo.Items.Add(ShedName);
  46. ResourceCombo.ItemIndex:=0;
  47. ResourceComboChange(nil);
  48. GotoDatePickerChange(nil);
  49.  
  50. end;
  51. {{/code}}
  52.  
  53.  
  54. {{code}}
  55. NewTimeLineItem('TEST',
  56.  
  57. clRed,
  58. //EncodeDate(2009,11,06),
  59. //EncodeDate(2009,11,06),
  60. Now(),Now(),
  61. Now(),
  62. Now()+EncodeTime(2,2,0,0),
  63. False,
  64. 10);


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

Вопрос задал: JoKeR_13 (статус: Посетитель)
Вопрос отправлен: 7 ноября 2009, 22:17
Состояние вопроса: открыт, ответов: 1.

Ответ #1. Отвечает эксперт: Вадим К

Здравствуйте, JoKeR_13!
Долго смотрел на код и понял, что с "временем" у Вас плохо. Для начала разберем некоторые базовые понятия. Время в делфовских типах TDate, TTime, TDateTime представлено в интересной форме - это просто вещественное число. И не более. При этом целая часть числа - это кол-во дней с 30 декабря 1899 года, а дробная - часть суток. То есть все сутки - это единица, 0.667 - это 4 часа дня ( 4 часа дня это 16 часов. 16/24 = 2/3), а 0.75 - 6 часов вечера.
Поэтому значения для типа TDate должны быть целыми положительными числами, а для TTime - дробными в пределах 0 ... 0.9999999.
Также можно записать образно, что TDateTime = TDate + TTime.
Весело то, что если глянуть определение этих типов, то можно узнать веселое:)

type
  TDateTime = type Double; //создали новый тип, не приводимый по умолчанию. То есть просто так смешать их нельзя
  TDate = type TDateTime; //просто псевдоним...
  TTime = type TDateTime; //поразмышляйте на досуге над этими строками.

Теперь второй шаг понимания.
Разберемся, что делает функция Now. Она просто возвращает текущую дату-время. Паралельно существуют ещё две функции - Date и Time. Думаю, не надо долго объяснять, что Date+Time как раз равно Now.

Теперь третий шаг. А что будет, если типу Time присвоить число больше единицы? В принципе, ничего страшного, кроме UB. UB - это программерское сокращение, которое в переводе значит "неопределенное поведение". То есть, результат может быть какой угодно. Да, в некоторых случаях можно "угадать" результат, и даже объяснить, почему он такой. Но это абсолютно не значит, что в следующей версии компилятора этот побочный эффект останется. Поэтому лучше обходить подобные моменты.

Теперь посмотрим на вызов процедуры. Видим, что в качестве параметра для даты и времени передается Now. И когда доходит дело до вызова SetStartEnd(StartDate, StartTime, EndDate, EndTime);
код наверно пытается сложить попарно время и дату (он же надеется, что всё прекрасно), и получает дату где то с 2218 года. (2009 - 1900 = 109. 109 + 109 = 218) А тут надо знать, что такую дату может назад и не перевести. (многие функции работы с датами имеет исторически сложившиеся верхние границы).
Компонент наверно тоже не знает, что делать.

Как же излечить код. один вариант я уже привел выше - вызывать функцию где то так
NewTimeLineItem('TEST',
                  'Пробное собщение TEST',
                  clRed,
                  //EncodeDate(2009,11,06),
                  //EncodeDate(2009,11,06),
                  Date(),Date(),
                  Time(),
                  Time()+EncodeTime(2,2,0,0),
                  False,
                  10);

Но я бы так лично не делал. Функции, у которых такое множество параметров и которые не бьют программиста по пальцами, когда он ошибается в параметрах - плохие функции. Как минимум заголовок функции надо переписать так
procedure TfrmMain.NewTimeLineItem(ShedName: string;
                              DiscriptionApp: string;
                              AppColor: TColor;
                              StartDate: TDateTime;
                              EndDate: TDateTime;
                              AppAlarmEnabled: Boolean;
                              AppAlarmAdvance: Integer);
А вот как извлечть и передать их внутри - оставляю в качестве домашнего задания. Помните, то целая часть, то дробная.

Попутно замечания к коду. А зачем там такая строка
Appt:=nil;
в даном примере она скорее всего безобидная (для точного анализа надо смотреть определение TJvTFAppt), но в некоторых может быть печально. Лучше удалить её.

Ответ отправил: Вадим К (статус: Академик)
Время отправки: 8 ноября 2009, 02:41
Оценка за ответ: 4


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

Всего сообщений: 1; последнее сообщение — 8 ноября 2009, 10:54; участников в обсуждении: 1.
JoKeR_13

JoKeR_13 (статус: Посетитель), 8 ноября 2009, 10:54 [#1]:

Спасибо за быстрый ответ!
К сожалению не получается тат как Вы предлагаете.
В данном примере я писал функцию Now() из-за того, что уже все перепробывал.
Даже если я вызываю с параметрами Date и Time все равно длительность события всего 1 минута.
Пробывал передавать параметры как EncodeDate(2009,10,10) и тоже самое с временем - Тоже самое.
Пробывал StrToDateTime('09.10.2009 6:00:00') - и снова ТЕКУЩАЯ ДАТА и ВРЕМЯ и длительность минута.
А вот если на прямую написать SetStartEnd(date, time, date, time+EncodeTime(2,0,0,0)) то все отрабатывает. Как правильно передать дату и время в процедуру?

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

Версия движка: 2.6+ (26.01.2011)
Текущее время: 2 апреля 2023, 12:18
Выполнено за 0.03 сек.
Рейтинг@Mail.ru