Разрабатывая некий функционал в 1С, бывает, необходимо посчитать количество рабочих дней после какой-то даты.
В этой статье примеры кода и запросы в которых считается количество рабочих дней:
Код, при вычислении определяет только по дню недели, викидывая выходные. Праздники не учитывает!
Код 1C v 8.х Функция РабочихДнейСДаты(НачДата,КолвоДней) Экспорт
Перем РабочихДней, ОбычныхДней, ДеньНедели;
РабочихДней = 0; ОбычныхДней = 0;
Пока РабочихДней < Число(КолвоДней) Цикл
ОбычныхДней = ОбычныхДней+ 1;
// определим день недели
ДеньНедели=ДеньНедели(НачДата+(ОбычныхДней*86400));
// если не выходной, то прошел еще один рабочий день
Если ДеньНедели < 6 Тогда
РабочихДней=РабочихДней+1;
КонецЕсли;
КонецЦикла;
Возврат (НачДата + (РабочихДней*86400));
КонецФункции
// Пример использования
ТриДняОтОбработки = РабочихДнейСДаты(нДатаОбработки,3);
Если РабочаяДата>ТриДняОтОбработки Тогда
Предупреждение("Прошло больше 3-х дней после обработки заказа. Цены не актуальны!
|Отправьте заказ на новую обработку! ");
Иначе
// ... неки код
КонецЕсли;
В запросе, с использованием производственного календаря и учетом всех праздников:
Код 1C v 8.х ВЫБРАТЬ
РегламентированныйПроизводственныйКалендарь.ДатаКалендаря КАК Дата
ПОМЕСТИТЬ Даты
ИЗ
РегистрСведений.РегламентированныйПроизводственныйКалендарь КАК РегламентированныйПроизводственныйКалендарь
ГДЕ
РегламентированныйПроизводственныйКалендарь.ДатаКалендаря В(&ВходящиеДаты)
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
Даты.Дата,
КОЛИЧЕСТВО(РАЗЛИЧНЫЕ РегламентированныйПроизводственныйКалендарь.ДатаКалендаря) КАК КоличествоРабочихДней,
МАКСИМУМ(РегламентированныйПроизводственныйКалендарь.ДатаКалендаря) КАК ДатаКалендаря,
РегламентированныйПроизводственныйКалендарь1.ДатаКалендаря КАК ДатаКалендаряДляГруппировки
ИЗ
РегистрСведений.РегламентированныйПроизводственныйКалендарь КАК РегламентированныйПроизводственныйКалендарь
ВНУТРЕННЕЕ СОЕДИНЕНИЕ Даты КАК Даты
ПО (Даты.Дата <= РегламентированныйПроизводственныйКалендарь.ДатаКалендаря)
И (ДОБАВИТЬКДАТЕ(Даты.Дата, ДЕНЬ,ГлубинаДней) > РегламентированныйПроизводственныйКалендарь.ДатаКалендаря)
ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.РегламентированныйПроизводственныйКалендарь КАК РегламентированныйПроизводственныйКалендарь1
ПО РегламентированныйПроизводственныйКалендарь.ДатаКалендаря <= РегламентированныйПроизводственныйКалендарь1.ДатаКалендаря
ГДЕ
(РегламентированныйПроизводственныйКалендарь.ВидДня = ЗНАЧЕНИЕ(Перечисление.ВидыДнейПроизводственногоКалендаря.Предпраздничный)
ИЛИ РегламентированныйПроизводственныйКалендарь.ВидДня = ЗНАЧЕНИЕ(Перечисление.ВидыДнейПроизводственногоКалендаря.Рабочий))
СГРУППИРОВАТЬ ПО
РегламентированныйПроизводственныйКалендарь1.ДатаКалендаря,
Даты.Дата
ИМЕЮЩИЕ
МАКСИМУМ(РегламентированныйПроизводственныйКалендарь.ДатаКалендаря) = РегламентированныйПроизводственныйКалендарь1.ДатаКалендаря
И КОЛИЧЕСТВО(РАЗЛИЧНЫЕ РегламентированныйПроизводственныйКалендарь.ДатаКалендаря) =РабочихДней
Еще один вариант, в котором допустим, что:
1) Регистр сведений Календарь имеет структуру (Измерения={ДатаКалендаря}, Ресурсы={ВидДня}), а перечисление ВидыДня задано как {Рабочий, Предпразничный} и праздничные дни в календаре отсутствуют.
2) В документе Реализация заданы поля Дата и ОтсрочкаДней. Тогда:
Код 1C v 8.х Выбрать
Р.Ссылка, Р.Дата,
минимум(isnull(К.ДатаКалендаря, добавитькдате(Р.Дата, день, Р.ОтсрочкаДней))) как ДатаКредита
из Документ.Реализация как Р
левое соединение РегистрСведений.Календарь как К
по добавитькдате(Р.Дата, день, Р.ОтсрочкаДней) <= К.ДатаКалендаря
сгруппировать по
Р.Ссылка, Р.Дата
Собственно, если календарь содержит и праздничные дни, то можно добавить секцию ГДЕ, и там отобрать только рабочие дни. В секции ГДЕ можно отобрать и интересующий календарь, если ведется несколько календарей.
В данном примере показано как в 7-ке выбрать документы поступления товаров за определенный период и обработать их, установив дату и номер счета-фактуры.
Код 1C v 7.x Процедура Сформировать()
ДокПрием = СоздатьОбъект("Документ.ПоступлениеТоваров");
ДокПрием.ВыбратьДокументы(НачДата, КонДата);
Пока ДокПрием.ПолучитьДокумент()=1 Цикл
текдлина = СтрДлина(СокрЛП(ДокПрием.НомерСчетаФактуры));
если текдлина>1 Тогда
Сообщить("Уже заполнено - "+строка(текдлина)+" * "+ДокПрием.НомерСчетаФактуры);
Иначе
ДатаСчФ = лев(ДокПрием.ДатаНомерСчетаФактуры,10);
ДатаСчетаФактуры = Дата(Сред(ДатаСчФ,7,4),Сред(ДатаСчФ,4,2),Лев(ДатаСчФ,2)); //31.03.2015
НомерСчетаФактуры = СокрЛП(Сред(ДокПрием.ДатаНомерСчетаФактуры, 11, 50));
ДокПрием.ДатаСчетаФактуры = ДатаСчетаФактуры;
ДокПрием.НомерСчетаФактуры = НомерСчетаФактуры;
ДокПрием.ДатаНомерСчетаФактуры = СокрЛП(НомерСчетаФактуры) + ";" + Формат(ДатаСчетаФактуры,"Д ДДММГГГГ");
Сообщить(" - " +НомерСчетаФактуры+" / "+строка(ДатаСчетаФактуры));
ДокПрием.Записать();
Конецесли;
КонецЦикла;
КонецПроцедуры
Код 1C v 8.2 УП КолМин = 0;
НачДата = Дата1;
Пока НачДата < Дата2 Цикл
// Запускаем цикл с шагом в 1 мин
НачДата = НачДата + 60;
//Пребразуем дату в строку
СтрТекДата = Формат(НачДата, "ДФ=yyyyMMddHHmm");
//часы и минуты преобразуем в число, берем правые 4 знака строки и делаем их числом
// т.е. 08:00 будет равно 800 и тд....
ТекВремя = Число(Прав(СтрТекДата,4));
// в цикле сравниваем на больше - меньше и накпливаем минуты если условие верно
// 800 в данном случае время - 08:00
// 2200 в данном случае время - 22:00
Если (ТекВремя > 800) и (ТекВремя <= 2200) Тогда
//накапливаем минуты
КолМин = КолМин + 1;
КонецЕсли;
КонецЦикла;
//получим количество часов из интервала с исключением промежутка с 22:00 по 08:00
Сообщить(КолМин/60);
Была поставлена задача посчитать время простоя автомобиля в часах за интервал, но при этом исключить ночное время, придумал такое решение...
Может комуто пригодится
Код 1C v 8.2 УП &НаКлиенте
Процедура УдалитьДокумент(Команда)
// Вставить содержимое обработчика.
УдалитьДокументНаСервере(0);
КонецПроцедуры
&НаСервере
Процедура УдалитьДокументНаСервере(ПометкаУдаления)
// Вставить содержимое обработчика.
Перем УдаляемыйДокумент;
УдаляемыйДокумент =Документы.РасходнаяНакладная.НайтиПоНомеру("000000004");
Если ПометкаУдаления = 1 Тогда
УдаляемыйДокумент.ПолучитьОбъект().УстановитьПометкуУдаления(Истина);
Иначе
УдаляемыйДокумент.ПолучитьОбъект().Удалить();
КонецЕсли;
КонецПроцедуры
Код 1C v 8.х //Установить пометку удаления документа
ТС=ЭлементыФормы.Список.ТекущиеДанные;
ТД=Документы.РеализацияТоваровУслуг.НайтиПоНомеру(ТС.Номер, ТС.Дата);
Если ТД.Пустая() Тогда
Сообщить("Документ по номеру <такому то> не найден");
возврат;
КонецЕсли;
ТД.ПолучитьОбъект().УстановитьПометкуУдаления(Истина);
Код 1C v 8.х // Непосредственное удаление документов
Запрос = Новый Запрос("ВЫБРАТЬ
| Заказы.Ссылка
|ИЗ
| Документ.Заказы КАК Заказы
|ГДЕ
| Заказы.ПометкаУдаления = ИСТИНА");
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
ОбъектДокумент = Выборка.Ссылка.ПолучитьОбъект();
ОбъектДокумент.Удалить();
КонецЦикла;
Код 1C v 7.x Д = СоздатьОбъект("Документ");
Д.ВыбратьДокументы(НачДата,КонДата);
Пока Д.ПолучитьДокумент() = 1 Цикл
Сообщить(Д.ТекущийДокумент());
Состояние(Д.ДатаДок);
Д.Удалить();
КонецЦикла;
Код 1C v 8.х Процедура ДействияФормыВыгрузить(Кнопка)
Запись=Новый ЗаписьXML;
Запись.ОткрытьФайл("c:\document.xml");
Запись.ЗаписатьОбъявлениеXML();
Запись.ЗаписатьНачалоЭлемента("Корневой");
Запись.ЗаписатьАтрибут("Доумент", "ПринятиеКУчтетуОС");
Запись.ЗаписатьКомментарий("Краткая информация о принятых к учету ОС");
//Выборка=Документы.ПринятиеКУчетуОС.Выбрать(); //это выгрузка всех документов в базе
// а нам нужно за определенный период:
Выборка=Документы.ПринятиеКУчетуОС.Выбрать(НачДата,КонДата);
Пока Выборка.Следующий()Цикл
Запись.ЗаписатьНачалоЭлемента("Элемент");
Запись.ЗаписатьАтрибут("Номер", Строка(Выборка.Номер));
Запись.ЗаписатьАтрибут("Дата", Строка(Выборка.Дата));
Запись.ЗаписатьАтрибут("Организация", Строка(Выборка.Организация));
Запись.ЗаписатьАтрибут("Склад", Строка(Выборка.Склад));
Запись.ЗаписатьАтрибут("ПодразделениеОрганизации", Строка(Выборка.ПодразделениеОрганизации));
Запись.ЗаписатьАтрибут("МОЛ", Строка(Выборка.МОЛБУ));
Запись.ЗаписатьАтрибут("Оборудование", Строка(Выборка.Номенклатура));
Запись.ЗаписатьАтрибут("ОбъектСтроительства", Строка(Выборка.ОбъектСтроительства));
Запись.ЗаписатьАтрибут("ПервоначальнаяСтоимость", Строка(Выборка.ПервоначальнаяСтоимостьНУ));
Запись.ЗаписатьКонецЭлемента();
КонецЦикла;
Запись.ЗаписатьКонецЭлемента();
Запись.Закрыть();
КонецПроцедуры
Код 1C v 8.х // Получает разность календарных дат указанного вида. В случае ошибки возвращает -1
Функция ПолучитьРазностьДат(рНачДата,рКонДата,рВидРазности="ДЕНЬ") Экспорт
Если не ЗначениеЗаполнено(рНачДата) или не ЗначениеЗаполнено(рКонДата) Тогда Возврат -1 КонецЕсли;
Если рНачДата=рКонДата Тогда Возврат 0 КонецЕсли;
строСтандПер="СЕКУНДА МИНУТА ЧАС ДЕНЬ НЕДЕЛЯ ДЕКАДА МЕСЯЦ КВАРТАЛ ГОД";
Если Найти(строСтандПер,рВидРазности)=0 Тогда рВидРазности="ДЕНЬ" КонецЕсли;
тз="ВЫБРАТЬ РАЗНОСТЬДАТ(&НачДата,&КонДата,"+СокрЛП(рВидРазности)+")+1 КАК ПериодовВремени";
з=Новый Запрос(тз);
Если рВидРазности="СЕКУНДА" или рВидРазности="МИНУТА" или рВидРазности="ЧАС" Тогда
// ставим, как есть, с учётом времени
Если рНачДата>рКонДата Тогда // всё наоборот
рПервая=рКонДата; рВторая=рНачДата; коэф=-1;
Иначе
рПервая=рНачДата; рВторая=рКонДата; коэф=1;
КонецЕсли;
Иначе
// ставим от начала дня
Если рНачДата>рКонДата Тогда // всё наоборот
рПервая=НачалоДня(рКонДата); рВторая=НачалоДня(рНачДата); коэф=-1;
Иначе
рПервая=НачалоДня(рНачДата); рВторая=НачалоДня(рКонДата); коэф=1;
КонецЕсли;
КонецЕсли;
Попытка
з.УстановитьПараметр("НачДата",рПервая);
з.УстановитьПараметр("КонДата",рВторая);
рРезультат=з.Выполнить().Выгрузить(ОбходРезультатаЗапроса.Прямой).Получить(0).ПериодовВремени;
Если ТипЗнч(рРезультат)<>Тип("Число") Тогда Возврат -1 Иначе Возврат коэф*рРезультат КонецЕсли;
Исключение
Возврат -1
КонецПопытки;
КонецФункции
Функция ДобавитьКДате(рДата,рРазность,рВидРазности="ДЕНЬ") Экспорт
Если рРазность=0 Тогда Возврат рДата КонецЕсли;
строСтандПер="СЕКУНДА МИНУТА ЧАС ДЕНЬ НЕДЕЛЯ ДЕКАДА МЕСЯЦ КВАРТАЛ ГОД";
Если Найти(строСтандПер,рВидРазности)=0 Тогда рВидРазности="ДЕНЬ" КонецЕсли;
тз="ВЫБРАТЬ ДОБАВИТЬКДАТЕ(&УслДата,"+СокрЛП(рВидРазности)+",&УслРазность) КАК РезДата";
з=Новый Запрос(тз);
з.УстановитьПараметр("УслДата",рДата);
з.УстановитьПараметр("УслРазность",рРазность);
рРезультат=з.Выполнить().Выгрузить(ОбходРезультатаЗапроса.Прямой).Получить(0).РезДата;
Если ТипЗнч(рРезультат)<>Тип("Дата") Тогда Возврат Дата(1,1,1) Иначе Возврат рРезультат КонецЕсли;
КонецФункции
Функция ГраницаПериода(рДата,рВидПериода="ДЕНЬ",рВидГраницы) Экспорт
строСтандПер="СЕКУНДА МИНУТА ЧАС ДЕНЬ НЕДЕЛЯ ДЕКАДА МЕСЯЦ КВАРТАЛ ГОД";
Если Найти(строСтандПер,рВидПериода)=0 Тогда рВидПериода="ДЕНЬ" КонецЕсли;
Если Найти(ВРег(рВидГраницы),"НАЧ")<>0 Тогда
рГраница="НАЧАЛОПЕРИОДА";
ИначеЕсли Найти(ВРег(рВидГраницы),"КОН")<>0 Тогда
рГраница="КОНЕЦПЕРИОДА";
Иначе
Возврат рДата;
КонецЕсли;
тз="ВЫБРАТЬ "+рГраница+"(&УслДата,"+СокрЛП(рВидПериода)+") КАК РезДата";
з=Новый Запрос(тз);
з.УстановитьПараметр("УслДата",рДата);
рРезультат=з.Выполнить().Выгрузить(ОбходРезультатаЗапроса.Прямой).Получить(0).РезДата;
Если ТипЗнч(рРезультат)<>Тип("Дата") Тогда Возврат Дата(1,1,1) Иначе Возврат рРезультат КонецЕсли;
КонецФункции
Пример 1 :
Код 1C v 8.х
//Взаиморасчеты за период, хотя, это лучше выбирать запросом , он в примере 3
Отбор = Новый Структура("Организация", Организация);
НаборЗаписей = РегистрыНакопления.ВзаиморасчетыСРаботникамиОрганизаций.Выбрать(ПериодРегистрации, КонецМесяца(ПериодРегистрации), Отбор);
Пока Выборка.Следующий() Цикл
// код обработки например:
Сум=Сум+Выборка.СуммаВзаиморасчетов;
КонецЦикла;
Пример 2 :
Код 1C v 8.х
// Посчитаем, сколько отгружено с начала года
УчетНоменклатуры = РегистрыНакопления.УчетНоменклатуры;
ОтборПоТовару = Новый Структура("Номенклатура");
ОтборПоТовару.Номенклатура = ВыбТовар;
НачДата = НачалоГода(ТекущаяДата());
КонДата = ТекущаяДата();
Выборка = УчетНоменклатуры.Выбрать(НачДата,КонДата,ОтборПоТовару);
Расход =0;
Пока Выборка.Следующий() Цикл
Если Выборка.ВидДвижения = ВидДвиженияНакопления.Расход Тогда
Расход = Расход + Выборка.Количество;
КонецЕсли;
КонецЦикла;
Предупреждение("Отгружено с начала года """ + СокрЛП(ВыбТовар) + """ = "+ Расход + " шт.");
Пример 3 :
Код 1C v 8.х
Запрос=новый Запрос;
Запрос.Текст="
|ВЫБРАТЬ
| ВзаиморасчетыСРаботникамиОрганизаций.СуммаВзаиморасчетов,
| ВзаиморасчетыСРаботникамиОрганизаций.СуммаВUSD,
| ВзаиморасчетыСРаботникамиОрганизаций.Физлицо
|ИЗ
| РегистрНакопления.ВзаиморасчетыСРаботникамиОрганизаций КАК ВзаиморасчетыСРаботникамиОрганизаций
|ГДЕ
| ВзаиморасчетыСРаботникамиОрганизаций.Физлицо = &Физлицо
| И ВзаиморасчетыСРаботникамиОрганизаций.ПериодВзаиморасчетов = &ПериодВзаиморасчетов
| И ВзаиморасчетыСРаботникамиОрганизаций.Организация = &Организация
| И ВзаиморасчетыСРаботникамиОрганизаций.ХарактерВыплаты = &ХарактерВыплаты
|";
Запрос.УстановитьПараметр("Организация",Организация);
Запрос.УстановитьПараметр("ПериодВзаиморасчетов",ПериодРегистрации);
Запрос.УстановитьПараметр("Физлицо",ТекущаяСтрока.Физлицо);
Запрос.УстановитьПараметр("ХарактерВыплаты",Перечисления.ХарактерВыплатыЗарплаты.ПлановыйАванс);
Результат = Запрос.Выполнить();
Результат = Результат.Выбрать();
Пока Результат.Следующий() Цикл
// код обработки например:
СумАванс=СумАванс+Результат.СуммаВзаиморасчетов;
КонецЦикла;