hoursBetween : BUG ?
13 отговора
309 прегледа
hoursBetween : BUG ?
delphi 7 , hoursBetween нещо не смята вярно.
пример:
(в примера : в 06:00, 07:00, 14:00.. 23:00)
uses dateutils;
procedure TForm1.Button1Click(Sender: TObject);
var dt1,dt2: tdatetime;
i: integer;
begin
dt1:=strtotime('00:00');
dt2:=dt1;
memo1.Lines.Clear;
for i:=0 to 23 do
begin
memo1.Lines.Add(timetostr(dt2)+char(vk_tab)+inttostr(i)+char(vk_tab)+inttostr(hoursBetween(dt2,dt1)));
dt2:=inchour(dt2,1);
end;
end;
резултат:
00:00:00 0 0
01:00:00 1 1
02:00:00 2 2
03:00:00 3 3
04:00:00 4 4
05:00:00 5 5
06:00:00 6 5
07:00:00 7 6
08:00:00 8 8
09:00:00 9 9
10:00:00 10 10
11:00:00 11 11
12:00:00 12 12
13:00:00 13 13
14:00:00 14 13
15:00:00 15 14
16:00:00 16 15
17:00:00 17 16
18:00:00 18 17
19:00:00 19 18
20:00:00 20 19
21:00:00 21 20
22:00:00 22 21
23:00:00 23 22
пример:
(в примера : в 06:00, 07:00, 14:00.. 23:00)
uses dateutils;
procedure TForm1.Button1Click(Sender: TObject);
var dt1,dt2: tdatetime;
i: integer;
begin
dt1:=strtotime('00:00');
dt2:=dt1;
memo1.Lines.Clear;
for i:=0 to 23 do
begin
memo1.Lines.Add(timetostr(dt2)+char(vk_tab)+inttostr(i)+char(vk_tab)+inttostr(hoursBetween(dt2,dt1)));
dt2:=inchour(dt2,1);
end;
end;
резултат:
00:00:00 0 0
01:00:00 1 1
02:00:00 2 2
03:00:00 3 3
04:00:00 4 4
05:00:00 5 5
06:00:00 6 5
07:00:00 7 6
08:00:00 8 8
09:00:00 9 9
10:00:00 10 10
11:00:00 11 11
12:00:00 12 12
13:00:00 13 13
14:00:00 14 13
15:00:00 15 14
16:00:00 16 15
17:00:00 17 16
18:00:00 18 17
19:00:00 19 18
20:00:00 20 19
21:00:00 21 20
22:00:00 22 21
23:00:00 23 22
Re: hoursBetween : BUG ?
Аритметиката с плаваща запетая не прощава никому
Още по-интересно ще ти стане ако завъртиш цикъла например до 100 - ще загубиш безвъзвратно цял час
Проблема ти всъщност е в:
dt2:=inchour(dt2,1);
Трябва да бъде:
dt2:=inchour(dt1,i+1);

Още по-интересно ще ти стане ако завъртиш цикъла например до 100 - ще загубиш безвъзвратно цял час
Проблема ти всъщност е в:
dt2:=inchour(dt2,1);
Трябва да бъде:
dt2:=inchour(dt1,i+1);
Редактирано от NDeu на
Re: hoursBetween : BUG ?
Проблемът, всъщност е "малко" по-тежък.
Някои (или всички?) функции за промяна на дата+час работят нехайно с милисекундите (резултата понякога е +1 или -1 милисекунда), а функциите за разлика между дата+час (hoursBetween daysBetween и т.н.) отчитат и милисекундите.
някакъв изход: човек да си напише функции за разлика в часове, дни, минути и да знае какво да очаква от тях.
пример:
резултат: от 14 до 16 часа - разлика 1 час (!!!)
от 14 до 17 часа - разлика 3 часа
var i: integer;
procedure TForm1.Button1Click(Sender: TObject);
begin
i:=hoursBetween(
strtodate('29.09.2003')+
strtotime('14:00'),
strtodate('29.09.2003')+
strtotime('16:00')
);
edit1.Text:=inttostr(i);
i:=hoursBetween(
strtodate('29.09.2003')+
strtotime('14:00'),
strtodate('29.09.2003')+
strtotime('17:00')
);
edit2.Text:=inttostr(i);
end;
Трудно е човек да повярва на очите си!
( но както е казал Граучо Маркс :
"Ти на мен ли ще вярваш или на неверните си очи?" )
Някои (или всички?) функции за промяна на дата+час работят нехайно с милисекундите (резултата понякога е +1 или -1 милисекунда), а функциите за разлика между дата+час (hoursBetween daysBetween и т.н.) отчитат и милисекундите.
някакъв изход: човек да си напише функции за разлика в часове, дни, минути и да знае какво да очаква от тях.
пример:
резултат: от 14 до 16 часа - разлика 1 час (!!!)
от 14 до 17 часа - разлика 3 часа
var i: integer;
procedure TForm1.Button1Click(Sender: TObject);
begin
i:=hoursBetween(
strtodate('29.09.2003')+
strtotime('14:00'),
strtodate('29.09.2003')+
strtotime('16:00')
);
edit1.Text:=inttostr(i);
i:=hoursBetween(
strtodate('29.09.2003')+
strtotime('14:00'),
strtodate('29.09.2003')+
strtotime('17:00')
);
edit2.Text:=inttostr(i);
end;
Трудно е човек да повярва на очите си!
( но както е казал Граучо Маркс :
"Ти на мен ли ще вярваш или на неверните си очи?" )
Re: hoursBetween : BUG ?
Погледни в сорса на функциите и ще разбереш, че тези функции изобщо не им пука и за минутите даже. Те си работят с времето като double. Необходимо е да извършваш съответно закръгляване за да получаваш коректен резултат, в зависимост от дефиницията на понятието "Часове (дни, месеци, години) между ...". Защото това понятие е дефинирано по различен начин напр. при лихварите, наемодателите, абонаментите и т.н.
Сорса на HoursBetween е:
Result := Trunc(HourSpan(ANow, AThen));
Вероятно на теб ти трябва:
Result := Round(HourSpan(ANow, AThen));
Имай предвид, че и 31 мин. да е разликата - пак ще ти дава 1 час.
А при 30 мин. отново ще имаш неприятности
Само за спорта:
Доста интересно ще ти е напр. да определиш и покажеш разлика м/у двe стойности TDateTime във формат dd.mm.yyyy hh:mm:ss

Сорса на HoursBetween е:
Result := Trunc(HourSpan(ANow, AThen));
Вероятно на теб ти трябва:
Result := Round(HourSpan(ANow, AThen));
Имай предвид, че и 31 мин. да е разликата - пак ще ти дава 1 час.
А при 30 мин. отново ще имаш неприятности
Само за спорта:
Доста интересно ще ти е напр. да определиш и покажеш разлика м/у двe стойности TDateTime във формат dd.mm.yyyy hh:mm:ss
Re: hoursBetween : BUG ?
Не че ще помогна много - ама погледни тези две неща
[линк]
[линк] - тука има един модул в който има доста допълнителни функции - мисля, че ще намериш вси4ко което те интересува тук.
---
Е т'ва е живот!
[линк]
[линк] - тука има един модул в който има доста допълнителни функции - мисля, че ще намериш вси4ко което те интересува тук.
---
Е т'ва е живот!
Re: hoursBetween : BUG ?
Само за спорта:
var dt1, dt2: TDateTime;
begin
dt1 := .....;
dt2 := .....;
ShowMessage(FormatDateTime('dd.mm.yyyy hh:nn:ss', dt2 - dt1);
end;

var dt1, dt2: TDateTime;
begin
dt1 := .....;
dt2 := .....;
ShowMessage(FormatDateTime('dd.mm.yyyy hh:nn:ss', dt2 - dt1);
end;
Re: hoursBetween : BUG ?
Според теб разликата Now-Now е 30.12.1899г. 00:00:00
Може би искаш да кажеш, че е 1899 години, 12 месеца, 30 дни, 0 часа, 0мин и 0 сек.
Понякога не винаги елегантното решение е вярно

Може би искаш да кажеш, че е 1899 години, 12 месеца, 30 дни, 0 часа, 0мин и 0 сек.
Понякога не винаги елегантното решение е вярно
Re: hoursBetween : BUG ?
Много си прав да знаеш
Горното е вярно само за часове - не трябва да има дни. И тогава трябва да се направи
dt := dt2 - dt1;
ShowMessage('Разликата е ' + IntToStr(Trunc(dt)) + ' дни и ' + Format('hh.nn.ss', dt));
Така по добре ли е? ;)
Човешкият ум е ограничен. Глупостта не е.
Горното е вярно само за часове - не трябва да има дни. И тогава трябва да се направи
dt := dt2 - dt1;
ShowMessage('Разликата е ' + IntToStr(Trunc(dt)) + ' дни и ' + Format('hh.nn.ss', dt));
Така по добре ли е? ;)
Човешкият ум е ограничен. Глупостта не е.
Re: hoursBetween : BUG ?
Не е по-добре.
Колко, според твоя пример, е разликата между 20:00:00 на 20.12.2003г и 18:00:00 на 21.12.2003г.
Пак побърза да пишеш, а мисленето го остави за после
В задачката има кукичка, затова съм я поставил в рубриката "за спорта"

Колко, според твоя пример, е разликата между 20:00:00 на 20.12.2003г и 18:00:00 на 21.12.2003г.
Пак побърза да пишеш, а мисленето го остави за после
В задачката има кукичка, затова съм я поставил в рубриката "за спорта"
Re: hoursBetween : BUG ?
Прав си. Трябва да се обработят отделно часовете от дните.
Ако става въпрос за мислене можеш ли да ми обясниш какво точно разбираш под понятието dd.mm.yyyy за разлика във време? От 1.1.2003 до 1.2.2003 разликата е един месец нали? И как искаш да се визуализира това във формат dd.mm.yyyy? BTW от 1.2.2003 до 1.3.2003 разликата също е един месец, ама малко не е равна на предната, нали?
Не смятам, че е проблем да се реализира подобно визуализиране, но ще изчакам да си уточниш заданието, за да не излезе че има още някоя кукичка, която си заложил
Ако става въпрос за мислене можеш ли да ми обясниш какво точно разбираш под понятието dd.mm.yyyy за разлика във време? От 1.1.2003 до 1.2.2003 разликата е един месец нали? И как искаш да се визуализира това във формат dd.mm.yyyy? BTW от 1.2.2003 до 1.3.2003 разликата също е един месец, ама малко не е равна на предната, нали?
Не смятам, че е проблем да се реализира подобно визуализиране, но ще изчакам да си уточниш заданието, за да не излезе че има още някоя кукичка, която си заложил
Редактирано от andrew_nikoloff на
Re: hoursBetween : BUG ?
Да-а, така е по-добре
"Преди да решиш една задача, трябва да я разбереш"
Елементарно е, всеки го знае, но .......
И така:
. 1.Формата на визуализиране не е съществен но си прав, че е по-естествено за разлика м/у две датетиме да бъде yyyy.mm.dd hh:mm:ss
. 2.Какво разбирам под разлика? По уточняващите въпроси, които задаваш разбирам, че двамата имаме едно и също разбиране за разлика м/у две датетиме. Действително разлика от един месец може да е различен брой дни.
Предлагам следния подход:
Нека разгледаме едно датетиме като 6 позиционно число (6цифрено)
Y.M.D h:m:s
където:
m и s са 60ични цифри (от 0 до 59)
h е 24ична цифра (0..23)
D e мммм..... понякога 28ична, понякога 29ична, 30ична или 31ична според зависи
M e 12ична цифра (0..11)
Изненадващо е нулев месец, но за разлика м/у две датетиме е нормално
Y e ммм ... зависи от диапазона на валидните времеви интервали, но на практика това не се явява ограничение (можем да си мислим например, че е 65535ична цифра)
Сега остава само да си припомним алгоритъма за изваждане на две многоцифрени числа от първи клас
Y2.M2.D2 h2:m2:s2
-
Y1.M1.D1 h1:m1:s1
===============
Y. M. D. h: m: s
Вадим първо младшите разреди. Ако получаваме отрицателно число, заемаме от по-старшия и т.н. като не забравяме кой разред в каква х-ична система е
Проблема с D се решава с още малко мислене, проби и грешки
Предполагам, че офсетването на M няма да създаде проблем.
ВЕСЕЛИ ПРАЗНИЦИ

"Преди да решиш една задача, трябва да я разбереш"
Елементарно е, всеки го знае, но .......
И така:
. 1.Формата на визуализиране не е съществен но си прав, че е по-естествено за разлика м/у две датетиме да бъде yyyy.mm.dd hh:mm:ss
. 2.Какво разбирам под разлика? По уточняващите въпроси, които задаваш разбирам, че двамата имаме едно и също разбиране за разлика м/у две датетиме. Действително разлика от един месец може да е различен брой дни.
Предлагам следния подход:
Нека разгледаме едно датетиме като 6 позиционно число (6цифрено)
Y.M.D h:m:s
където:
m и s са 60ични цифри (от 0 до 59)
h е 24ична цифра (0..23)
D e мммм..... понякога 28ична, понякога 29ична, 30ична или 31ична според зависи
M e 12ична цифра (0..11)
Y e ммм ... зависи от диапазона на валидните времеви интервали, но на практика това не се явява ограничение (можем да си мислим например, че е 65535ична цифра)
Сега остава само да си припомним алгоритъма за изваждане на две многоцифрени числа от първи клас
Y2.M2.D2 h2:m2:s2
-
Y1.M1.D1 h1:m1:s1
===============
Y. M. D. h: m: s
Вадим първо младшите разреди. Ако получаваме отрицателно число, заемаме от по-старшия и т.н. като не забравяме кой разред в каква х-ична система е
Проблема с D се решава с още малко мислене, проби и грешки
Предполагам, че офсетването на M няма да създаде проблем.
ВЕСЕЛИ ПРАЗНИЦИ
Редактирано от NDeu на
Re: hoursBetween : BUG ?
Добреее.... Да видим сега как стоят нещата...
Значи по въпросчетата - нямах точно това предвид. Идеята ми беше, че когато имаме разлика от време нямаме ясно дефинирани месеци и години. Веднага давам пример - имаме разлика от 365 дни. Прилича разликата да е 1 година, нали ?
Да, ,при условие, че датите ни са 1.1.2002 и 1.1.2003 например. Ама ако първата дата е 1.1.2000, то втората дата обаче ще дойде 31.12.2000...
По същия начин стоят нещата и с месеците - разлика от 30 дни може да е 1 месец, или 1 месец и 1 или 2 дена, или просто 30 дни
Мдаааа. А сега едно възможно решение:
(само да кажа, че при минус не знам си колко градуса навън и едноседмична почивка за климатика умирам от студ и не мога много-много да мисля, така че може и да съм объркал нещо
)
Дефинираме си типче, за да си улесним живота.
type TDateArray = Array[0..6] of Word;
const bases: TDateArray = (65535, 12, 30, 24, 60, 60, 1000);
И няколко помощни функцийки:
А самият код е следния:
Не е най-обстойно тестваното от мен нещо, но тъй като просто умирам от студ, а то има вид да работи горе-долу - поствам си го и оставям на народа да си каже мнението, пък аз довечера като се прибера на топло и полежа малко върху печката, че да ми се размрази оная работа (акъла имам предвид
) ще му хвърля още едно оченце 
Човешкият ум е ограничен. Глупостта не е.
Значи по въпросчетата - нямах точно това предвид. Идеята ми беше, че когато имаме разлика от време нямаме ясно дефинирани месеци и години. Веднага давам пример - имаме разлика от 365 дни. Прилича разликата да е 1 година, нали ?
Мдаааа. А сега едно възможно решение:
(само да кажа, че при минус не знам си колко градуса навън и едноседмична почивка за климатика умирам от студ и не мога много-много да мисля, така че може и да съм объркал нещо
Дефинираме си типче, за да си улесним живота.
type TDateArray = Array[0..6] of Word;
const bases: TDateArray = (65535, 12, 30, 24, 60, 60, 1000);
И няколко помощни функцийки:
function GetBase(da: TDateArray; idx: Integer): Word;
var y, m, d: Word;
begin
if idx = 2 then
begin
if da[1] = 12 then
begin
m := 1;
y := da[0] + 1;
end
else
begin
m := da[1];
y := da[0];
end;
DecodeDate(EncodeDate(y, m, 1) - 1, y, m, d);
Result := d;
end
else
Result := bases[idx];
end;
procedure DateDec(var da: TDateArray; idx: Integer; val: Word);
begin
if da[idx] < val then
begin
da[idx] := da[idx] + GetBase(da, idx) - val;
DateDec(da, idx - 1, 1);
end
else
Dec(da[idx], val);
end;
А самият код е следния:
var
a1, a2: TDateArray;
dt1, dt2: TDateTime;
//dt2 > dt1
DecodeDate(dt1, a1[0], a1[1], a1[2]);
DecodeTime(dt1, a1[3], a1[4], a1[5], a1[6]);
DecodeDate(dt2, a2[0], a2[1], a2[2]);
DecodeTime(dt2, a2[3], a2[4], a2[5], a2[6]);
for i := 6 downto 0 do
DateDec(a2, i, a1);
ShowMessage(Format('%4.4d.%2.2d.%2.2d %2.2d:%2.2d:%2.2d:%3.3d', [a2[0], a2[1], a2[2], a2[3], a2[4], a2[5], a2[6]]));
Не е най-обстойно тестваното от мен нещо, но тъй като просто умирам от студ, а то има вид да работи горе-долу - поствам си го и оставям на народа да си каже мнението, пък аз довечера като се прибера на топло и полежа малко върху печката, че да ми се размрази оная работа (акъла имам предвид
Човешкият ум е ограничен. Глупостта не е.
Re: Бутилка червено вино....
ЙЕЕЕЕЕ! Кефффф 

Човешкият ум е ограничен. Глупостта не е.
Човешкият ум е ограничен. Глупостта не е.