| 
| 
 | Вопрос # 3 377/ вопрос открыт / | 
 |  Приветствую, уважаемые эксперты!Jedi TJvTFDays
 Событие получается на текущую дату и время и длительностью минута.
 В чем я ошибаюсь?
 К вопросу прикреплён файл. Загрузить » (срок хранения: 60 дней с момента отправки вопроса) Приложение:Переключить в обычный режим procedure TfrmMain.NewTimeLineItem(ShedName: string;                              DiscriptionApp: string;                              AppColor: TColor;                              StartDate: TDate;                              EndDate: TDate;                              StartTime: TTime;                              EndTime: TTime;                              AppAlarmEnabled: Boolean;                              AppAlarmAdvance: Integer);var  Appt : TJvTFAppt;  DaysGrid: TJvTFDays;  i: integer;//  NewAppt: Boolean;begin showmessage(DateTimeToStr(Startdate)+#13+DateTimeToStr(Enddate)+#13+             DateTimeToStr(StartTime)+#13+DateTimeToStr(EndTime));  Appt := JvTFDays1.ScheduleManager.dbNewAppt('');  Appt.Persistent:= True;  with Appt do  begin    BeginUpdate;    AddSchedule(ShedName);    SetStartEnd(StartDate, StartTime, EndDate, EndTime);    Description:=DiscriptionApp+' '+ DateTimeToStr(Appt.StartDateTime)+' '+
DateTimeToStr(Appt.EndDateTime);    AlarmEnabled:=AppAlarmEnabled;    AlarmAdvance:=AppAlarmAdvance;    BarColor:=clGreen;    Appt.Color:=AppColor;     if DaysGrid.ValidSelection then      for i:=DaysGrid.SelStart.X to DaysGrid.SelEnd.X do        Appt.AddSchedule(DaysGrid.Cols[i].SchedName);      Persistent:= False;    Post;    EndUpdate;    JvTFScheduleManager1.RefreshAppts;    JvTFDays1.Refresh;   end;   Appt:=nil;    ResourceCombo.Items.Add(ShedName);    ResourceCombo.ItemIndex:=0;    ResourceComboChange(nil);    GotoDatePickerChange(nil); end;{{/code}}  {{code}}NewTimeLineItem('TEST',                   clRed,                  //EncodeDate(2009,11,06),                  //EncodeDate(2009,11,06),                  Now(),Now(),                  Now(),                  Now()+EncodeTime(2,2,0,0),                  False,                  10);
|  |   Вопрос задал: 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 (статус: Посетитель), 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)) то все отрабатывает. Как правильно передать дату и время в процедуру?
 |  Чтобы оставлять сообщения в мини-форумах, Вы должны авторизироваться на сайте. |