При разработке прикладных решений в системе 1С:Предприятие нередко возникает задача смещения даты назад на заданное число дней: для формирования отчетов за прошедший период, установки фильтров в динамических списках или расчета контрольных сроков документов. Разберем подробно, как выполнить такую операцию на встроенном языке 1С, как реализовать вычитание дней в тексте запроса и как избежать распространенной ошибки преобразования типов.
В платформе 1С:Предприятие значение типа Дата хранится с точностью до секунды. Любые арифметические операции сложения и вычитания с датами производятся в секундах. Соответственно, чтобы отнять от даты нужное количество дней, необходимо умножить число дней на количество секунд в сутках (24 часа * 60 минут * 60 секунд = 86400 секунд).
Посмотрим на пример базового вычисления:
КоличествоДней = 10;
НужнаяДата = ТекущаяДата() - (КоличествоДней * 24 * 60 * 60);
Рассмотрим важные нюансы работы с датой во встроенном языке:
НачалоДня() или КонецДня():
// Получаем начало дня 10 дней назад
ДатаСреза = НачалоДня(ТекущаяДата() - 10 * 86400);
// Получаем конец дня 10 дней назад
КонечнаяДата = КонецДня(ТекущаяДата() - 10 * 86400);
ТекущаяДата() на стороне клиента возвращает время операционной системы клиентского компьютера. Для корректной работы в клиент-серверном варианте и с учетом настроек пользователя рекомендуется использовать функцию ТекущаяДатаСеанса().В языке запросов 1С арифметические действия над датами в секундах не поддерживаются напрямую, как в коде. Для изменения даты на определенный интервал предназначена специализированная функция ДОБАВИТЬКДАТЕ.
Синтаксис функции:
ДОБАВИТЬКДАТЕ(ИсходнаяДата, ТипПериода, Количество)
Чтобы вычесть дни, мы передаем отрицательное значение количества. Рассмотрим пример запроса:
ВЫБРАТЬ
ДОБАВИТЬКДАТЕ(&ТекущаяДата, ДЕНЬ, -&КоличествоДней) КАК НужнаяДата,
НАЧАЛОПЕРИОДА(ДОБАВИТЬКДАТЕ(&ТекущаяДата, ДЕНЬ, -&КоличествоДней), ДЕНЬ) КАК НачалоНужногоДня
Проанализируем особенности использования функции ДОБАВИТЬКДАТЕ в запросах:
ДЕНЬ) является зарезервированным ключевым словом языка запросов. Его нельзя передавать через параметр запроса в виде строки или переменной.NULL (например, при левом соединении таблиц), результат функции ДОБАВИТЬКДАТЕ также будет равен NULL. В таких случаях поле необходимо оборачивать в ЕСТЬNULL.НАЧАЛОПЕРИОДА с указанием типа периода ДЕНЬ.При реализации расчета на форме разработчики часто сталкиваются с ошибкой выполнения: «Преобразование к типу Число не может быть выполнено». Выясним причину ее возникновения и способы устранения.
Ошибка происходит в том случае, когда переменная, участвующая в операции умножения на 86400, не имеет числового типа. Рассмотрим типичные ситуации:
Элементы.КоличествоДней, платформа возвращает объект элемента интерфейса (ПолеФормы), а не само значение, введенное пользователем. Для получения значения необходимо обращаться напрямую к реквизиту формы: КоличествоДней или к реквизиту объекта: Объект.КоличествоДней.Неопределено или NULL), при попытке умножения возникнет исключение.Посмотрим на безопасный вариант получения значения и расчета даты на форме:
&НаКлиенте
Процедура РассчитатьДату()
// Проверяем заполненность реквизита
Если Не ЗначениеЗаполнено(КоличествоДней) Тогда
Возврат;
КонецЕсли;
// Приводим значение к типу Число для исключения ошибок
ЧислоДней = Число(КоличествоДней);
// Вычисляем результирующую дату
НужнаяДата = НачалоДня(ТекущаяДатаСеанса() - ЧислоДней * 86400);
КонецПроцедуры
Если перед вами стоит задача отнять не просто календарные, а исключительно рабочие дни с учетом праздников и выходных, простое математическое вычитание секунд не подойдет. В типовых конфигурациях на базе Библиотеки стандартных подсистем (БСП) для таких расчетов применяется общий модуль КалендарныеГрафики, позволяющий определить дату с учетом производственного календаря или графиков работы предприятия.