|
Вопрос # 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)) то все отрабатывает. Как правильно передать дату и время в процедуру?
|
Чтобы оставлять сообщения в мини-форумах, Вы должны авторизироваться на сайте.
|