Имя: Пароль:
1C
1С v8
Количество рабочих дней между двумя датами
0 swallow05
 
15.08.11
22:59
Доброй ночи всем. Возникла необходимость отсчитать от определенной даты назад 5 рабочих дней, т.е. с учетом праздников и выходных. Добавила в конфигурацию производственный календарь (конфа бухгалтерия 1.6), но чую им не получится это сделать. Никто не подскажет, каким образом можно реализовать такой подсчет? Т.е. если у нас 11 января, то 5 рабочих дней будет 26 декабря. Спасибо за ответы :).
1 vde69
 
15.08.11
23:08
делал через производственный календарь, делается не сложно но работает медлено.

потом оптимизировал, сделал кеш таблицу и ее использовал, экономия примерно 4-5 секунд на запросе
2 Мимохожий Однако
 
15.08.11
23:10
Поищи в общих модулях. Наверняка уже есть готовое в конфигурации.
3 swallow05
 
15.08.11
23:12
Я сейчас просто выборку делаю из производственного календаря первый 5 дней, по условию рабочих, которые меньше данной даты, вроде получилось, всем спасибо. Вопрос закрыт :)
4 CepeLLlka
 
16.08.11
00:08
"Добавила в конфигурацию производственный календарь"

Пол:     Мужской


о_О
5 swallow05
 
16.08.11
01:21
Изменила профиль))) при регистрации видимо немного промахнулась)))
6 Steel_Wheel
 
16.08.11
01:59
ник просто ппц
7 Sammo
 
16.08.11
04:52
Вообще-то задача в теме (рабочих дней между датами) и в сообщении (нужно отнять 5 дней от даты) несколько разные.
Делаются разными запросами по производственному календарю
8 skunk
 
16.08.11
04:57
(7)и в чем разница?
9 kosts
 
16.08.11
06:06
(1) Это что за запрос такой по которому только экономия 4-5 секунд...

(3) Нужно учесть предпразднечные дни, они ведь тоже рабочие. По крайней мере в ЗУПе есть предпразднечные.
10 Мимохожий Однако
 
16.08.11
06:56
УТ11. Общий модуль.Календарные графики.
// Функция определяет количество дней, входящих в календарь, для указанного периода
//
// Параметры
//    Календарь        - календарь, который необходимо использовать, тип СправочникСсылка.Календари
//    ДатаНачала        - дата начала периода
//    ДатаОкончания    - дата окончания периода
//
// Возвращаемое значение
//    Массив        - массив дат, увеличенных на количество дней, входящих в график
//
Функция ПолучитьРазностьДатПоКалендарю(Знач Календарь, Знач ДатаНачала, Знач ДатаОкончания) Экспорт
   
   ДатаНачала        = НачалоДня(ДатаНачала);
   ДатаОкончания    = НачалоДня(ДатаОкончания);
   
   Если ДатаНачала = ДатаОкончания Тогда
       Возврат 0;
   КонецЕсли;
   
   РазныеГода = Год(ДатаНачала) <> Год(ДатаОкончания);
   
   Запрос = Новый Запрос;
   
   МассивДатНачала = Новый Массив;
   МассивДатНачала.Добавить(ДатаНачала);
   Если РазныеГода Тогда
       МассивДатНачала.Добавить(НачалоДня(КонецГода(ДатаНачала)));
   КонецЕсли;
   
   Запрос.УстановитьПараметр("Календарь",            Календарь);
   Запрос.УстановитьПараметр("МассивДатНачала",    МассивДатНачала);
   Запрос.УстановитьПараметр("ГодДатыНачала",        Год(ДатаНачала));
   
   Запрос.УстановитьПараметр("ДатаОкончания",        ДатаОкончания);
   Запрос.УстановитьПараметр("ГодДатыОкончания",    Год(ДатаОкончания));
   
   Запрос.Текст =
   "ВЫБРАТЬ
   |    КалендарныеГрафики.КоличествоДнейВГрафикеСНачалаГода КАК КоличествоДней,
   |    КалендарныеГрафики.ДатаГрафика КАК ДатаГрафика
   |ИЗ
   |    РегистрСведений.КалендарныеГрафики КАК КалендарныеГрафики
   |ГДЕ
   |    КалендарныеГрафики.Календарь = &Календарь
   |    И (КалендарныеГрафики.Год = &ГодДатыНачала
   |                И КалендарныеГрафики.ДатаГрафика В (&МассивДатНачала)
   |            ИЛИ КалендарныеГрафики.Год = &ГодДатыОкончания
   |                И КалендарныеГрафики.ДатаГрафика = &ДатаОкончания)
   |
   |УПОРЯДОЧИТЬ ПО
   |    ДатаГрафика";
   ТаблицаДней = Запрос.Выполнить().Выгрузить();
   
   Если ТаблицаДней.Количество() < ?(РазныеГода, 3, 2) Тогда
       СообщениеОбОшибке = НСтр("ru = 'Не заполнен календарь ''%1'' за период %2!'");
       ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
           СообщениеОбОшибке,
           Календарь, ПредставлениеПериода(ДатаНачала, КонецДня(ДатаОкончания)));
   КонецЕсли;
   
   КоличествоДнейДатыНачала = ТаблицаДней[0].КоличествоДней;
   КоличествоДнейДатыОкончания = ТаблицаДней[?(РазныеГода, 2, 1)].КоличествоДней + ?(РазныеГода, ТаблицаДней[1].КоличествоДней, 0);
   
   Возврат КоличествоДнейДатыОкончания - КоличествоДнейДатыНачала;
   
КонецФункции
11 vde69
 
16.08.11
08:37
вот это приведение долго работает...

   ЗапросКаледарь = Новый Запрос(
   "ВЫБРАТЬ
   |    ПроизводственныйКалендарь.ДатаКалендаря КАК ДатаКалендаря,
   |    МИНИМУМ(ПроизводственныйКалендарь.ДатаКалендаря) КАК ДатаНачалаКалендаря,
   |    СУММА(ВЫБОР
   |            КОГДА ПроизводственныйКалендарь.Пятидневка = 1
   |                ТОГДА КопияПроизводственныйКалендарь.Пятидневка
   |            ИНАЧЕ NULL
   |        КОНЕЦ) КАК ИндексПятидневка,
   |    СУММА(ВЫБОР
   |            КОГДА ПроизводственныйКалендарь.Шестидневка = 1
   |                ТОГДА КопияПроизводственныйКалендарь.Шестидневка
   |            ИНАЧЕ NULL
   |        КОНЕЦ) КАК ИндексШестидневка,
   |    СУММА(ВЫБОР
   |            КОГДА ПроизводственныйКалендарь.КалендарныеДни = 1
   |                ТОГДА КопияПроизводственныйКалендарь.КалендарныеДни
   |            ИНАЧЕ NULL
   |        КОНЕЦ) КАК ИндексКалендарныеДни,
   |    СУММА(1) КАК ИндексВсеДни
   |ИЗ
   |    РегистрСведений.РегламентированныйПроизводственныйКалендарь КАК ПроизводственныйКалендарь
   |        ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.РегламентированныйПроизводственныйКалендарь КАК КопияПроизводственныйКалендарь
   |        ПО ПроизводственныйКалендарь.ДатаКалендаря >= КопияПроизводственныйКалендарь.ДатаКалендаря
   |
   |СГРУППИРОВАТЬ ПО
   |    ПроизводственныйКалендарь.ДатаКалендаря
   |
   |УПОРЯДОЧИТЬ ПО
   |    ДатаКалендаря");
           
   Кеш = ЗапросКаледарь.Выполнить().Выгрузить();
   
   КешКалендаря = Новый Соответствие;
   КешКалендаря.Вставить("Календарь", Кеш);
   ПараметрыСеанса.КешКалендаря = Новый ХранилищеЗначения (КешКалендаря);
12 vde69
 
16.08.11
08:40
(11) кстати разность дат в SQL работает на порядок медленее чем разность чисел, по этому я и привожу весь календарь к числу дней от самого первого дня, ну а потом просто получаю ю два числа и результатом является простая разница целых чисел
13 Fragster
 
гуру
16.08.11
08:48
(11) о_О занафига само с собой соединять?

ВЫБРАТЬ
   СУММА(ПроизводственныйКалендарь.Пятидневка) КАК Дней
ИЗ
   РегистрСведений.РегламентированныйПроизводственныйКалендарь
ГДЕ
   ПроизводственныйКалендарь.ДатаКалендаря МЕЖДУ &Дата1 И &Дата2
14 vde69
 
16.08.11
08:56
(13) по тому как я получаю таблицу для каждой даты, в том числе и для выходных.

для единичного запроса (13) годится, для запроса где нужно посчитать 100 000 периодов годится (11)
15 Fragster
 
гуру
16.08.11
08:59
(14) считай разность дат в секундах, потом дели на 86400
16 Axel2009
 
16.08.11
09:21
(14) 100 000 периодов - 273 года.
17 Axel2009
 
16.08.11
09:23
(12) пруфлинк?
18 vde69
 
16.08.11
09:33
(16) пример - определение просрочки в супермаркете, по остаткам партий товаров. Или расчет количества банковских дней просрочки по договору (от момента платежа)

(17) замерял
19 Axel2009
 
16.08.11
09:34
(18) где?
20 vde69
 
16.08.11
09:35
(19) в SQL
21 dmpl
 
16.08.11
09:40
(14) Когда будет 100 тыс. периодов - сервак просто упадет по нехватке памяти. Левое соединение с условием, отличным от = завалит.

(16) Для того, чтобы завалить сервер хватит и 30-40 тыс. записей.
22 Axel2009
 
16.08.11
09:40
(18) да я знаю где это применяется. определяю среднюю просрочку (суммарная просрочка на каждый день месяца, и средняя из этого) по каждому клиенту за весь месяц по всем просроченным долгам на 5 рабочих дней. весь запрос 3 секунды
23 Axel2009
 
16.08.11
09:42
(20) как проверялось? в цикле или в запросе?
24 Axel2009
 
16.08.11
10:04
set nocount on
declare t table(i int, d datetime)
declare i int, @d datetime, @d2 datetime, i2 int
set i = 0
while i < 10000 begin
set i = i + 1
insert into t values(i, dateadd(dd, i, '19500101'))
end

set i = 0
set @d = getdate()
while i < 10000 begin
set i = i + 1
select @d2 = datediff(dd, d, getdate()) from t
end
print 'разница по дате ' + str(datediff(ss, @d, getdate()))

set i = 0
set @d = getdate()
while i < 10000 begin
set i = i + 1
select i2 = 11000 - i from t
end
print 'разница по числу ' + str(datediff(ss, @d, getdate()))

разница по дате         15
разница по числу         14

где порядки?
25 ptiz
 
16.08.11
10:27
(24) Это в рабочих днях?
26 Axel2009
 
16.08.11
10:28
(25) это разность дат, которая "работает на порядок медленнее"
2 + 2 = 3.9999999999999999999999999999999...