Просмотрел часть вопросов по дате, но похожего не нашел.
Делаю отчет. В таблице хранятся дата начала и дата окончания. Нужно по каждому клиенту посчитать общее количество времени проведенного в учреждении за заданный период (в иделале нужно чтоб сразу выдавало итог по каждому в формате ##,## где целое - часы, дробное - минуты). Можно ли как-то на сервере быстро на основании двух имеющихся дат вычислить общее количество часов и минут? Имеется в виду можно ли это сделать все силами IB без использования UDF и уж тем более без программной обработки.
Уважаемые авторы вопросов! Большая просьба сообщить о результатах решения проблемы на этой странице. Иначе, следящие за обсуждением, возможно имеющие аналогичные проблемы, не получают ясного представления об их решении. А авторы ответов не получают обратной связи. Что можно расценивать, как проявление неуважения к отвечающим от автора вопроса.
06-05-2007 11:04
Доброго времени суток!
В общем, я покопался, потерзал разработчиков FB, и получается следующее: поскольку в 3-м диалекте разность дат представляется как NUMERIC(18,9), а не DOUBLE PRECISION, получаем погрешность вычитания - до ~0.856*10^(-4) секунды. Т.е. при вычитании можем получить ошибку в 1 десятитысячную секунды. Поэтому результат нужно всегда округлять до наибольшего по модулю целого числа и все дальнейшие расчеты вести уже на основе него.
Как верно заметил Python, решается это все с помощью ХП (писал я, поэтому не исключены ошибки):
create procedure date_diff(DATE1 TIMESTAMP,DATE2 TIMESTAMP)
returns (DAYS INTEGER,HOURS INTEGER,MINUTES INTEGER,SECONDS INTEGER,
MILLISECONDS INTEGER)
as
DECLARE VARIABLE TenThousands NUMERIC(18,9);
DECLARE VARIABLE Modulo BIGINT;
begin
TenThousands = (DATE1-DATE2)*86400*10000;
Modulo = case
when (TenThousands>0) THEN CAST(TenThousands+0.5 as BIGINT)
when (TenThousands<0) THEN CAST(TenThousands-0.5 as BIGINT)
else CAST(TenThousands AS BIGINT)
end;
Milliseconds = Modulo-Modulo/10000*10000;
Modulo = Modulo/10000;
Seconds = Modulo-Modulo/60*60;
Modulo = Modulo/60;
Minutes = Modulo-Modulo/60*60;
Modulo = Modulo/60;
Hours = Modulo-Modulo/24*24;
Modulo = Modulo/24;
Days = Modulo;
SUSPEND;
end
Процедура возвращает разложение DATE1-DATE2 (должна корректно работать с отрицательными датами). Естественно, работает только в 3-м диалекте, в FB 1.5 и выше
To _nautilus_
В третьем выдает на минуту меньше.
Для диапазонов (28.04.2007 22:30:59,28.04.2007 22:59:58) (01.04.2007 23:59:59, 02.04.2007 01:00:00) возвращает корректный результат, как и в первом диалекте. У меня ерунда начинается, если есть дробные доли секунды. Похоже, в 3-м диалекте мой вариант использовать нельзя. Надо копать дальше.
В первом диалекте число часов и минут можно получить следующим запросом
select start_date,end_date,
CAST((end_date-start_date)*24-0.5 AS INTEGER) as Hours,
CAST((end_date-start_date)*60*24-0.5 AS INTEGER)-
60*CAST((end_date-start_date)*24-0.5 AS INTEGER) as Minutes
from table_dates
Форматирование результата лучше сделать на клиенте
Если вы заметили орфографическую ошибку на этой странице, просто выделите ошибку мышью и нажмите Ctrl+Enter. Функция может не работать в некоторых версиях броузеров.