Разработка и Конфигурация · 11 мин
Как от даты отнять день в 1С
Как от даты отнять день в 1С: функция ДобавитьКДате, арифметика секунд, работа в запросах и типовые ошибки. Примеры кода для встроенного языка 1С.
Задача отнять один день от даты возникает в 1С постоянно: при расчёте периодов отчётов, определении даты отгрузки, проверке сроков оплаты и формировании выборок «за вчера». Во встроенном языке 1С нет функции с названием «ОтнятьДень», поэтому новички часто ищут несуществующий метод. На практике задача решается двумя основными способами: универсальной функцией ДобавитьКДате и простой арифметикой, где дата хранится как число секунд.
Оба подхода корректны, но ведут себя по-разному на границах месяцев, при переходе через високосный год и в запросах. Ниже разобраны рабочие примеры кода, варианты для языка запросов, типичные ошибки и способы проверить результат перед тем, как использовать его в прикладной логике.
Материал применим к платформе 1С:Предприятие 8.x — синтаксис работы с датами един для «Управления торговлей», «Бухгалтерии», «Зарплаты и управления персоналом» и собственных конфигураций.
Как устроен тип «Дата» в 1С и почему это важно
В платформе 1С дата внутренне представлена как количество секунд, прошедших от начала отсчёта. Именно поэтому к дате можно прибавлять и отнимать целые числа — каждая единица соответствует одной секунде. Один день — это 86 400 секунд (60 × 60 × 24).
Из этого следуют два практических вывода. Первый: выражение Дата - 86400 технически отнимает ровно сутки. Второй: если в дате есть время (например, 14:30:00), то вычитание суток сохранит это время — вы получите вчерашний день в 14:30:00, а не начало вчерашнего дня. Это частая причина ошибок при сравнении дат в условиях и отборах.
Для отсечения времени используйте функцию НачалоДня() или КонецДня(). Например, НачалоДня(Дата - 86400) вернёт 00:00:00 вчерашнего дня, что удобно для сравнения с датами документов без учёта времени.
Способ 1: функция ДобавитьКДате с отрицательным значением
Самый надёжный и рекомендуемый способ — функция ДобавитьКДате. Она принимает три параметра: исходную дату, тип увеличения (строка «СЕКУНДА», «МИНУТА», «ЧАС», «ДЕНЬ», «МЕСЯЦ», «КВАРТАЛ», «ГОД») и величину сдвига. Для вычитания укажите отрицательное число.
ИсходнаяДата = ТекущаяДатаСеанса();
ВчерашняяДата = ДобавитьКДате(ИсходнаяДата, "ДЕНЬ", -1);
Сообщить(ВчерашняяДата);
Главное преимущество функции — корректная работа с календарной арифметикой. Если отнять день от 1 марта невисокосного года, результатом будет 28 февраля; от 1 января — 31 декабря предыдущего года. При вычитании месяцев функция также корректно обрабатывает разное количество дней в месяцах, чего простая арифметика секунд не умеет.
Обратите внимание на регистр и точное написание типа увеличения: строка должна быть одним из допустимых значений. Опечатка вроде «ДНИ» или «День» с лишними символами приведёт к ошибке выполнения.
ВчерашняяДата = ДобавитьКДате(ТекущаяДатаСеанса(), "ДЕНЬ", -1);
НачалоВчера = НачалоДня(ВчерашняяДата);
КонецВчера = КонецДня(ВчерашняяДата);Способ 2: вычитание секунд напрямую
Второй вариант — использовать тот факт, что дата является числом секунд. Выражение Дата - 86400 отнимает ровно одни сутки. Этот приём короче и часто встречается в типовых конфигурациях.
ДатаДокумента = Документ.Дата;
ПредыдущиеСутки = ДатаДокумента - 86400; // минус один день
Для читаемости кода лучше записывать выражение как произведение: Дата - 24 60 60. Тогда человеку, читающему код, сразу понятно, что вычитаются именно сутки, а не «магическое число».
Ограничение способа: он работает только с фиксированными интервалами — секундами, минутами, часами, днями и неделями. Для месяцев и лет, где длительность плавающая, арифметика секунд не подходит — используйте только ДобавитьКДате.
Сравнение способов
Универсально, читаемо, корректно на любых календарных границах. Подходит и для месяцев/лет. Чуть длиннее запись.
Коротко и быстро для суточных интервалов. Не подходит для месяцев и лет, менее очевидно при чтении кода.
Единственный вариант внутри текста запроса, когда нужно отобрать данные за смещённый период на стороне СУБД.
Как отнять день от даты в запросе 1С
В языке запросов арифметика секунд недоступна — там работает только функция ДОБАВИТЬКДАТЕ с аналогичным синтаксисом. Типичная задача — отобрать документы за вчерашний день или сравнить дату документа со смещённой датой.
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Реализация.Ссылка
|ИЗ
| Документ.РеализацияТоваровУслуг КАК Реализация
|ГДЕ
| Реализация.Дата >= &НачалоВчера
| И Реализация.Дата <= &КонецВчера";
Запрос.УстановитьПараметр("НачалоВчера", НачалоДня(ДобавитьКДате(ТекущаяДатаСеанса(), "ДЕНЬ", -1)));
Запрос.УстановитьПараметр("КонецВчера", КонецДня(ДобавитьКДате(ТекущаяДатаСеанса(), "ДЕНЬ", -1)));
Если смещение нужно выполнить прямо в тексте запроса, используйте конструкцию вида ДОБАВИТЬКДАТЕ(&Дата, ДЕНЬ, -1). Обратите внимание: в запросе тип периода пишется без кавычек — это ключевое слово, а не строка.
Практическая рекомендация: если границы периода можно вычислить на встроенном языке, делайте это до запроса и передавайте готовые значения параметрами. Так запрос проще читать, а индексы по полю даты используются эффективнее.
Работа с пустой датой и граничными случаями
Пустая дата в 1С — это '00010101000000' (1 января года 1). Если отнять день от пустой даты, результат станет отрицательным значением даты, что почти наверняка сломает дальнейшую логику или вызовет ошибку при записи в базу. Поэтому перед вычитанием проверяйте заполненность.
Если ЗначениеЗаполнено(ДатаОтгрузки) Тогда
ДатаПодготовки = ДобавитьКДате(ДатаОтгрузки, "ДЕНЬ", -1);
Иначе
ДатаПодготовки = Неопределено;
КонецЕсли;
Второй граничный случай — дата документа с границей последовательности или с временем 23:59:59. Если бизнес-логика опирается на «предыдущий календарный день», убедитесь, что вы отсекаете время через НачалоДня(), иначе сравнение дат в условиях даст неожиданный результат.
Третий нюанс — функция ТекущаяДата() на толстом клиенте возвращает время клиентского компьютера, а ТекущаяДатаСеанса() — время сервера с учётом часового пояса сеанса. В серверном коде и регламентных заданиях используйте ТекущаяДатаСеанса(), иначе «вчера» у разных пользователей может оказаться разным.
Проверка результата и отладка
Простейший способ убедиться, что вычитание сработало, — вывести обе даты через Сообщить() или посмотреть значения в отладчике. Для наглядности форматируйте дату функцией Формат() с указанием даты и времени.
Сообщить("Было: " + Формат(ИсходнаяДата, "ДЛФ=DT"));
Сообщить("Стало: " + Формат(ВчерашняяДата, "ДЛФ=DT"));
Особое внимание уделите тестированию на границах: 1 января, 1 марта високосного и невисокосного года, 1 число любого месяца. Именно здесь проявляются ошибки календарной арифметики. Если логика критична (например, расчёт сроков оплаты или блокировок), покройте эти случаи явными проверками в коде или тестовыми данными.
Как проверить результат
Получилось последнее число предыдущего месяца
Дата осталась в том же месяце или стала пустой
Время сохранилось или обрезано через НачалоДня/КонецДня — как задумано
Время «прыгает» непредсказуемо, сравнения не срабатывают
Есть проверка ЗначениеЗаполнено, пустая дата обрабатывается отдельно
Вычитание выполняется от 01.01.0001 без проверки
Используется ТекущаяДатаСеанса()
Используется ТекущаяДата() с клиентского компьютера
Практические сценарии применения
Подбор документов за вчерашний день
Классическая задача для регламентных заданий и отчётов: обработать всё, что было проведено вчера. Вычислите границы через НачалоДня и КонецДня от смещённой даты и передайте их параметрами запроса — пример приведён в разделе про запросы выше.
Расчёт срока со сдвигом назад
Если по бизнес-правилу подготовка заказа должна начаться за день до отгрузки, дата подготовки вычисляется как ДобавитьКДате(ДатаОтгрузки, "ДЕНЬ", -1). Для сроков в рабочих днях простого вычитания недостаточно — потребуется производственный календарь из регистра сведений, где учитываются выходные и праздники.
Установка периода отчёта по умолчанию
При открытии отчёта удобно подставлять период «вчера» или «последние 7 дней». Для этого в обработчике при создании формы установите дату окончания как конец вчерашнего дня, а дату начала — через ДобавитьКДате с нужным отрицательным сдвигом.
- 1Определите источник даты: реквизит объекта, ТекущаяДатаСеанса() или параметр.
- 2Проверьте заполненность даты через ЗначениеЗаполнено().
- 3Вычтите день: ДобавитьКДате(Дата, "ДЕНЬ", -1) или Дата - 86400.
- 4При необходимости отсеките время через НачалоДня() или КонецДня().
- 5Проверьте результат на граничных датах: 1 января, 1 марта, 1-е число месяца.
Частые вопросы по вычитанию дней из даты в 1С
Как отнять не один, а несколько дней от даты?
Измените третий параметр функции: ДобавитьКДате(Дата, "ДЕНЬ", -7) отнимет неделю. При арифметике секунд умножьте 86400 на нужное количество дней: Дата - 7 * 86400.
Чем отличается ТекущаяДата() от ТекущаяДатаСеанса()?
ТекущаяДата() возвращает время компьютера, где выполняется код — на клиенте это часы пользователя. ТекущаяДатаСеанса() возвращает серверное время с учётом часового пояса сеанса. В серверных процедурах и регламентных заданиях корректно использовать ТекущаяДатаСеанса().
Как отнять день в запросе, если дата хранится в таблице?
Используйте функцию языка запросов: ДОБАВИТЬКДАТЕ(Документ.Дата, ДЕНЬ, -1). Тип периода указывается без кавычек. Учтите, что вычисления над полями таблицы в условиях ГДЕ могут мешать использованию индексов — по возможности вычисляйте границы заранее и передавайте параметрами.
Что произойдёт, если отнять день от 1 января?
Функция ДобавитьКДате корректно вернёт 31 декабря предыдущего года. Арифметика секунд (Дата - 86400) также даст корректный результат, так как сутки — фиксированный интервал. Проблемы возникают только при вычитании месяцев и лет через секунды.
Как получить начало вчерашнего дня?
Комбинируйте функции: НачалоДня(ДобавитьКДате(ТекущаяДатаСеанса(), "ДЕНЬ", -1)). Результат — 00:00:00 вчерашней даты. Для конца дня аналогично используйте КонецДня() — получится 23:59:59.
Можно ли отнять рабочий день, а не календарный?
Встроенной функции для этого нет. Нужно использовать производственный календарь из регистра сведений (в типовых конфигурациях — «РегламентированныйПроизводственныйКалендарь» или аналог) и в цикле сдвигать дату назад, пропуская выходные и праздничные дни.
Что важно запомнить
День от даты в 1С отнимается через ДобавитьКДате(Дата, "ДЕНЬ", -1) или вычитанием 86400 секунд; в запросах — через ДОБАВИТЬКДАТЕ без кавычек. Всегда проверяйте заполненность даты, отсекайте время при сравнениях и тестируйте границы месяцев и года.