Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Web программирование > SQL, базы данных
Регистрация

Восстановить пароль

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 21.08.2019, 12:13   #1
nactyx
Форумчанин
 
Регистрация: 11.10.2010
Сообщений: 152
По умолчанию Функция расчета стажа

Есть функция, считает стаж.
Но возникает вопрос, почему по отдельности два периода считает так:
24.05.1988 - 11.08.1988 = 0 лет 2 мес 19 дн
12.08.1988 - 12.07.1994 = 5 лет 11 мес 1 дн
В "уме" если сложить получим 6 лет 1 мес 20 дн
Но если объединить периоды и к ним применить функцию, то получим:
24.05.1988 - 12.07.1994 = 6 лет 1 мес 19 дн
Почему?
P.S. @stag_coeff_ принимать за 0 на входе, @ftime = 'P'

Код функции:
Код:
-- Функция расчета стажа по периоду между датами (день/месяц/год).
-- @ftime - флаг, указывающий возвращаемую часть стажа
-- 		"Y" - лет, "M" - месяцев, "D" - дней
--		"S" - период в формате YYY-MM-DD
--		"P" - период в формате лет:YYY мес:MM дн:DD (без лидирующих нулей)

ALTER FUNCTION [dbo].[pr_fn_calc_staj]
(
	@dd1 			DATETIME,
	@dd2 			DATETIME,
	@stag_coeff_  	NUMERIC(19,4) = 1,
	@ftime 			CHAR
)
RETURNS  VARCHAR(20) AS
BEGIN
  DECLARE
	@mm_ 	INTEGER,
	@yy_ 	INTEGER,
	@dd_ 	INTEGER,
	@mm_f 	NUMERIC(19,4),
	@yy_f 	NUMERIC(19,4),
	@dd_f 	NUMERIC(19,4),
	@yy	INTEGER,
	@mm	INTEGER,
	@dd	INTEGER

if 	@dd1 <= @dd2 /* проверка на корректность переданного диапазона дат*/
begin

  SELECT @yy   =  0,
	   @mm =  0,
	   @dd   = 0

  SELECT  @dd2 =  dateadd(day, 1, @dd2)

  if isnull(@stag_coeff_, 0) = 0  SELECT @stag_coeff_ = 1
  SELECT @yy = datediff(year, @dd1, @dd2)
  SELECT @mm = datediff(month, dateadd(year, @yy, @dd1), @dd2)

  if @mm < 0
  BEGIN
	SELECT @yy = @yy - 1
	SELECT @mm = datediff(month, dateadd(year, @yy, @dd1), @dd2)
  END

  SELECT  @dd = datediff(day, dateadd(month, @mm, dateadd(year, @yy, @dd1)), @dd2)
  if @dd < 0
  BEGIN
	SELECT @mm = @mm - 1 if @mm < 0
	SELECT @mm = 11, @yy = @yy - 1
	SELECT @dd = datediff(day, dateadd(month, @mm, dateadd(year, @yy, @dd1)), @dd2)
  END

  SELECT @yy_f = Cast(@yy as NUMERIC(19,4)) * @stag_coeff_, @mm_f = Cast(@mm * @stag_coeff_ as NUMERIC(19,4)), @dd_f = Cast(@dd * @stag_coeff_ as NUMERIC(19,4))

  SELECT @dd = convert(integer,@dd_f) + (@yy_f - convert(integer, @yy_f))*365 SELECT @yy = convert(integer, @yy_f)
  SELECT @dd = @dd + (@mm_f - convert(integer, @mm_f))*30 SELECT @mm = convert(integer, @mm_f)
  SELECT @dd = convert(integer, @dd) if @dd >= 30
  SELECT @mm = @mm + (@dd-(@dd%30))/30, @dd = @dd%30

  if @mm >= 12 SELECT @yy = @yy + (@mm-(@mm%12))/12, @mm = @mm%12
  if @yy < 0 SELECT @yy = 0, @mm = 0, @dd = 0

----------------------------------------------------------
if upper(@ftime) = 'Y' 		RETURN CONVERT(VARCHAR(10),@yy)
if upper(@ftime) = 'M' 		RETURN CONVERT(VARCHAR(2),@mm)
if upper(@ftime) = 'D' 		RETURN CONVERT(VARCHAR(2),@dd)

if upper(@ftime) = 'S'
begin
	if  @yy > 999			RETURN '999-99-99'
	else					RETURN RIGHT('000'+CONVERT(VARCHAR(3), @yy),3) +'-'+ RIGHT('00'+CONVERT(VARCHAR(2), @mm),2) +'-'+ RIGHT('00'+CONVERT(VARCHAR(2), @dd),2)
end

if upper(@ftime) = 'P'
begin
	if  @yy > 999			RETURN 'лет:999 мес:99 дн:99'
	else					RETURN 'лет:' + RIGHT('   '+CONVERT(VARCHAR(3), @yy),3) +' мес:'+ RIGHT('  '+CONVERT(VARCHAR(2), @mm),2) +' дн:'+ RIGHT('  '+CONVERT(VARCHAR(2), @dd),2)
end


end
RETURN '0'

END

Последний раз редактировалось nactyx; 21.08.2019 в 12:16.
nactyx вне форума Ответить с цитированием
Старый 21.08.2019, 12:32   #2
Аватар
Старожил
 
Аватар для Аватар
 
Регистрация: 17.11.2010
Сообщений: 18,922
По умолчанию

Потому что в году не всегда 365 дней, да и в месяце бывает не только 30 дней
Если бы архитекторы строили здания так, как программисты пишут программы, то первый залетевший дятел разрушил бы цивилизацию
Аватар вне форума Ответить с цитированием
Старый 21.08.2019, 13:06   #3
nactyx
Форумчанин
 
Регистрация: 11.10.2010
Сообщений: 152
По умолчанию

Цитата:
Сообщение от Аватар Посмотреть сообщение
Потому что в году не всегда 365 дней, да и в месяце бывает не только 30 дней
Это не новость. Главная загвоздка в том, что периоды одинаковые. Два отдельных, идущих друг за другом в сумме дают одно. А если их "слепить" и применить к таком периоду функцию - сумма другая на один день. Почему? Понять не могу. В этом вопрос.
nactyx вне форума Ответить с цитированием
Старый 21.08.2019, 13:47   #4
Аватар
Старожил
 
Аватар для Аватар
 
Регистрация: 17.11.2010
Сообщений: 18,922
По умолчанию

datediff(month, '20190201', '20190301') вернет 1 месяц, там разница по факту и есть месяц

datediff(day, '20190201', '20190301') вернет 28 дней, что с точки зрения функции совсем не месяц после деления нацело на 30
Если бы архитекторы строили здания так, как программисты пишут программы, то первый залетевший дятел разрушил бы цивилизацию
Аватар вне форума Ответить с цитированием
Старый 21.08.2019, 14:58   #5
Serge_Bliznykov
Старожил
 
Регистрация: 09.01.2008
Сообщений: 26,229
По умолчанию

Цитата:
Сообщение от nactyx Посмотреть сообщение
В этом вопрос.
Попробуйте рассмотреть такую ситуацию

24.05.1988
26.05.1988
разница 2 дня

27.05.1988
31.05.1988
разница 4 дня

24.05.1988
31.05.1988
Разница 7 дней

(когда находим разницу, то конечная дата не входит в диапазон)
Serge_Bliznykov вне форума Ответить с цитированием
Старый 22.08.2019, 11:18   #6
nactyx
Форумчанин
 
Регистрация: 11.10.2010
Сообщений: 152
По умолчанию

Спасибо, разобрался.
nactyx вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
расчет стажа работы SAUUNSAPR Microsoft Office Excel 9 15.06.2016 11:51
Расчет стажа сотрудников Zet_iKs Microsoft Office Excel 13 02.04.2016 12:37
Подсчет трудового стажа Paraz1t SQL, базы данных 6 27.06.2012 11:40
Сортировка по возрастанию и убыванию стажа betirsolt БД в Delphi 3 16.11.2010 17:52
Расчет стажа работы John_chek Общие вопросы Delphi 6 13.04.2007 13:38