1с получить количество рабочих дней

Обновлено: 05.07.2024

1. делением на продолжительность рабочего дня не подходит, т.к. каждый день разное количество часов,
2. Запросом собрать фактически отработанные периоды, а потом выяснять в какие дни были не нулевые показания часов - ужасно не "красиво"

конфа то какая? Самопал? В ЗУПе есть еще ресурс - "количество отработанных дней"
ЗаполнениеДокументов.ЧислоРабочихДней(ДатаНачало, ДатаОкончание) в egg
(0) Есть такая задачка на спеца по платформе: решается созданием 2х регистров расчета, и соответсвенно у РС ГрафикиРаботы - 2 ресурса - первый в днях, второй в часах.
(7) миздец, очередная нетленка. смелые люди - пишут расчет и в ЗУП не глядят.

(5) к сожалению УПП у меня нет и быстро скачать возможности нет.
(8) Вести дополнительный регистр только для того, что бы считать количество дней? Хм. это можно обдумать. Спасибо.
(9) в ЗУПе я не в ЗУБ ногой :(, не архитектуры не знаю и времени в настоящий момент нет разбирать тысячестроковые коды. Я думал, что мой вопрос прост и алгоритм решения здесь подскажут (сам на форуме ни чего не нашел).

Получаеться что запрос это единственное решение без увеличения объектов метаданных?

(11) написано же, еще один ресурс делаешь и заполняешь.

>>Получаеться что запрос это единственное решение без увеличения объектов метаданных?

а потом тебе в по базе за 3 месяца такие данные нужны будут? Очередно запрос сочинять?

>>Вести дополнительный регистр только для того, что бы считать количество дней?

нахер он не нужен.

(12) С ресурсом не совсем понятно :

Ресурс - ресурс где?

если в Регистре расчетов, так у меня они там уже есть Дней и часов.
вопрос в том, как корректней заполнить ресурс Дней?

если в регистре сведений "Графики" тогда вопрос, как его обрабатывать?

(13) в регистре расчетов естественно.

>>вопрос в том, как корректней заполнить ресурс Дней?

этого никто кроме вас не знает, раз количество часов каждый день разное

Rom Написал:
-------------------------------------------------------
> Подскажите, как посчитать количество РАБОЧИХ дней
> между 2мя датами?
> Из помощника, понял что нужно использовать:
> Дней(дата1, дата2); и УчитыватьПраздники(); но как
> их в модуль списока справочника вставить, чтобы
> считал?
> Праздниками считаются все красные даты? и выходные
> тоже?

По-моему, в типовых д.б. так называемые календари, где уже отмечены и выходные и праздники - покопай в этом направлении.

У меня под рукой только рарусCRM но там календари неиспользуют :(
дайте ссылку где можно про календари почитать, а то в моей книжке про них нислова не сказано.

Процедура РабДни()
перем Дни;
Календ = СоздатьОбъект(Календари.Служащие);
Дни = Календ.Дней( ДатаУвольнения, ДатаПриема);
Сообщить(Дни);
КонецПроцедуры

Календ = СоздатьОбъект(Календари.Служащие);
: Неудачная попытка создания объекта

Rom Написал:
-------------------------------------------------------
> Процедура РабДни()
> перем Дни;
> Календ = СоздатьОбъект(Календари.Служащие);
> Дни = Календ.Дней( ДатаУвольнения,
> ДатаПриема);
> Сообщить(Дни);
> КонецПроцедуры
>
> пишет ERR
>
> Календ = СоздатьОбъект(Календари.Служащие);
> > уль(3)>: Неудачная попытка создания объекта
>
> почему?
Во-первых, сразу бросается в глаза:
Календ = СоздатьОбъект(Календари.Служащие);
надо хотя бы уж
Календ = СоздатьОбъект("Календарь.Служащие");

В справке 1С по календарям не густо. Достань к-нить типовуху и посмотри, как там сделано.

Цитата:
Объект Календарь в системе 1С:Предприятие предназначен для вычисления временных интервалов на основании произвольных временных графиков. Этот объект может использоваться, например, для учета графика работы предпри­ятия, графика работы внешних организаций, графика учета рабочего времени тех или иных работников предприятия и пр.

Календарь представляет собой объект, который устанавливает для каждой календарной даты некоторое числовое значение, которое может интерпретиро­ваться при работе программы тем или иным образом. Например, в календаре, представляющем собой график работы организации или предприятия, каждому рабочему дню может соответствовать единица, а каждому выходному — ноль. В календаре учета рабочего времени сотрудников предприятия, каждой дате ка­лендаря может соответствовать число — продолжительность рабочего дня в часах и т. д.

В глобальном контексте программы 1С:Предприятие есть атрибут "Календари". Этот объект в качестве своих атрибутов имеет значения объек­тов конкретных видов календарей, заданных в конфигурации. Кроме того, этот объект имеет метод ПолучитьАтрибут, который позволяет получить доступ к объекту календаря конкретного вида по его имени. Т.е. допустимы следующие синтаксические конструкции:

Календари.Служащие.Дней(ТекДата, ТекДата + 5);

Календари.ПолучитьАтрибут("Служащие").Дней(ТекДата, ТекДата + 5);

Праздники в системе 1С:Предприятие представляет собой объект похожий на календарь, но он заполняется выборочно (не все даты подряд) и в нем могут вводиться и удаляться строки для определенных дат. Данный объект исполь­зуются как набор исключений при заполнении календарей (см. метод календа­ря УчитыватьПраздники).

Работа с производственными календарями, рабочими графиками часто встречается в практике разработки. Большинство задач можно свести к двум: 1) Добавить к дате (отнять от даты) некоторое количество рабочих дней и 2) найти разницу в рабочих днях между двумя датами. Несмотря на кажущуюся простоту, в этих задачах достаточно подводных камней, как методических, так и технологических. Естественно эта тема не была обойдена вниманием разработчиков типовых конфигураций и членов нашего сообщества. Простой поиск дает несколько результатов:

На мой взгляд, предлагаемые решения обладают теми или иными недостатками. В их числе:

  • сложность полученных запросов: применение временных таблиц, использование группировок больших таблиц, получаемых в результате соединения
  • не все решения хорошо работает с некоторыми входными данными, например в качестве входных параметров-дат могут быть использованы выходные дни
  • некоторые решения предполагают дополнительную обработку программным кодом промежуточных данных, полученных в результате запроса
  • часто решается узкая задача, т.е. решение не универсально.

Предлагаю свой вариант решения.

Постановка задачи:

Предположим, на предприятии ведется учет выполняемых работ. Каждая работа выполняется целое число дней, всегда начинается в начале дня, а заканчивается через несколько дней в конце дня. Продолжительность работ может быть от 1 дня, до нескольких лет (важность условия этого будет упомянута ниже). Необходимо иметь инструмент, позволяющий выполнять расчеты дат начала, окончания работ, продолжительностей работ, временных промежутков между работами. Все расчеты выполнять в рабочих днях. Решение должно позволять использование его в запросах.

В чем могут быть "подводные камни" при решении? Например токарь работает по стандартному рабочему графику - пятидневке. 01 апреля 2019 он начинает изготавливать деталь №1, тратит на ее изготовление 5 дней, и начинает изготавливать следующую деталь №2. Когда он закончит изготовление детали №1? Когда начнет изготавливать деталь №2? Казалось бы в обоих случаях ответ: через 5 рабочих дней после 01 апреля, т.е. к 01.04.2019 надо прибавить 5 рабочих дней. Но в первом случае ответ - 05.04.2019, а во втором - 08.04.2019.

Решение:

Решение поставленной задачи неожиданно получилось довольно простым.

Для учета рабочих графиков (производственных календарей) используем вспомогательный регистр сведений:


РабочийГрафик - ссылка на справочник "РабочиеГрафики" - если на предприятии используется несколько графиков (пятидневка, пятидневка с праздниками, семидневка и т.п.)

Дата - дата графика (без времени)

ЭтоРабочийДень - флаг рабочий/нерабочий день

КолВоДнейСНачалаПериода - Число рабочих дней, прошедших до начала даты записи, начиная с определенной, наперед заданной даты. В моем примере используется 01.01.2000.

Регистр необходимо заполнить на весь период, в пределах которого будут производится расчеты.


Теперь для нахождения разницы дат нам надо в регистре найти два числа, соответствующие этим датам и определить их разницу. Для добавления к дате некоторого числа рабочих дней, надо в регистре найти соответствующее дате число, добавить к нему число рабочих дней, и по результату найти в регистре соответствующую дату рабочего дня. Осталось учесть упомянутые выше сложности и получим следующее:

Примеры использования

Как видим запросы получаются довольно простыми, не используются ни временные таблицы, ни группировки с агрегатными функциями, ни постобработка. Ничего не мешает производить расчет в запросе для нескольких записей. В прилагаемом файле реализован пример отчета по выполненным работам: дана дата начала, предполагаемая плановая продолжительность работы и фактическая дата завершения, определяется плановая дата завершения и отставание факта от плана.


Может возникнуть вопрос: оправдано ли с точки зрения производительности использование дополнительного регистра такой структуры, ведь при изменении флага рабочего/выходного дня надо пересчитывать все записи с большей датой? Я считаю, что вполне. Во-первых, изменение производственного календаря происходит обычно не чаще одного раза в месяц, а полный пересчет и сохранение набора записей за 100 лет(

40000 записей) по выбранному графику занимает считанные секунды. А во-вторых, выгода от использования быстрого массового расчета как правило с лихвой перекроет все время, потраченное на предварительную подготовку.

А что же БСП?

Опытный разработчик, использующий БСП, может сказать: "Так ведь в БСП реализовано почти что то же самое!". Да, действительно в БСП есть аналогичный регистр:


Есть также программный интерфейс модулей "ГрафикиРаботы", "КалендарныеГрафики" с функциями "РазностьДатПоКалендарю", "ДатыПоГрафику" и т.п. Но если присмотреться, то можно увидеть, что в регистре имеется измерение "Год". То есть в этом регистре отсчет количества дней идет с начала каждого года. Когда мы работаем с датами в пределах одного года, то подход при расчете совпадает с рассмотренным. Но если даты попадают в разные года, а особенно если рассматривается промежуток в несколько лет, то алгоритм получается весьма сложным. Все интересующиеся могут самостоятельно сравнить объем программного кода в библиотеке и в предложенном решении. Скорее всего, разработчики БСП стремились к упрощению процедуры заполнения - каждый год рабочего графика заполняется отдельно и не зависит от других. Но в результате мы получаем существенное усложнение алгоритмов при решении практических задач. Я бы рекомендовал использовать регистры БСП как источник для заполнения регистра "РабочиеДни", а все дальнейшие операции производить уже с ним.

UPD 25.06.2019:

Для конфигураций с БСП добавлено заполнение регистра на основе данных из типовых объектов - регистра КалендарныеГрафики и справочника Календари. В процессе обработки заполняется регистр за период с 2000 г. по примерно 2109 г. - 40000 дней.

К статье приложена информационная база, в которой реализован описанный функционал, примеры отчетов, а также процедура заполнения и пересчета регистра.

Подсчитываем дни с помощью регистра сведений РегламентированныйПроизводственныйКалендарь.

* Стоит условие что дата окончания должна попадать на рабочий день.
* Начальная дата не проверяется на то, что должна быть рабочим днем.
* Начальная дата за рабочий день не считается.
* Нет проверок что календарь не заполнен, это можно сделать отдельно.

ВЫБРАТЬ
Даты.ДатаНачала КАК ДатаНачала,
Даты.ДатаОкончания КАК ДатаОкончания,
КОЛИЧЕСТВО(РПК.ДатаКалендаря) - 1 КАК КоличествоРабочихДней
ИЗ
(ВЫБРАТЬ
ПодсчетРабочихДней.ДатаНачала КАК ДатаНачала,
ПодсчетРабочихДней.ДатаОкончания КАК ДатаОкончания
ИЗ
(ВЫБРАТЬ
Календарь1.ДатаКалендаря КАК ДатаНачала,
Календарь2.ДатаКалендаря КАК ДатаОкончания
ИЗ
РегистрСведений.РегламентированныйПроизводственныйКалендарь КАК Календарь1,
(ВЫБРАТЬ
Календарь2.ДатаКалендаря КАК ДатаКалендаря
ИЗ
РегистрСведений.РегламентированныйПроизводственныйКалендарь КАК Календарь2
ГДЕ
(Календарь2.ДатаКалендаря > &Дата1
И Календарь2.ДатаКалендаря < &Дата2)
И Календарь2.ВидДня = ЗНАЧЕНИЕ(Перечисление.ВидыДнейПроизводственногоКалендаря.Рабочий)) КАК Календарь2
ГДЕ
Календарь1.ДатаКалендаря >= &Дата1
И Календарь1.ДатаКалендаря <= &Дата2
И Календарь1.ДатаКалендаря < Календарь2.ДатаКалендаря) КАК ПодсчетРабочихДней) КАК Даты,
РегистрСведений.РегламентированныйПроизводственныйКалендарь КАК РПК
ГДЕ
РПК.ДатаКалендаря МЕЖДУ Даты.ДатаНачала И Даты.ДатаОкончания
И РПК.ВидДня = ЗНАЧЕНИЕ(Перечисление.ВидыДнейПроизводственногоКалендаря.Рабочий)

СГРУППИРОВАТЬ ПО
Даты.ДатаНачала,
Даты.ДатаОкончания

УПОРЯДОЧИТЬ ПО
ДатаНачала,
ДатаОкончания

(3) Дело в том что есть еще другой запрос в котором соответственно есть дата начальная и число рабочих дней и нужно получить дату окончания.

Этот запрос не поможет, так как даты это параметры. А мой можно прицепить к другому запросу и получить дату окончания исходя из даты начала и количества рабочих дней.

(2) Нет, просто искал готовое решение и не нашел, выложил может кому пригодится.

В моем случае есть бизнес процесс который начинается с определенной даты, а закончится должен через сколько то рабочих дней и какой датой он должен окончится нужно вычислить.

Читайте также: