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