Разработка и Конфигурация · 10 мин
Как из даты вычесть дату в 1С
Как вычесть одну дату из другой в 1С: язык запросов, РазностьДат, функции встроенного языка, расчёт разницы в днях, месяцах и годах с примерами кода.
Вычитание дат — одна из самых частых задач при разработке и доработке конфигураций 1С: посчитать стаж сотрудника, определить просрочку платежа, вычислить возраст товара на складе или срок до окончания договора. Встроенный язык 1С и язык запросов предлагают несколько разных инструментов для этого, и выбор конкретного зависит от того, где выполняется расчёт и в каких единицах нужен результат.
Главная сложность в том, что даты нельзя вычитать «как числа» и сразу получить разницу в месяцах или годах. Результат вычитания двух дат во встроенном языке — это число секунд, а в запросах используется специальная функция РАЗНОСТЬДАТ с указанием единицы измерения. Кроме того, существует обратная задача — вычесть из даты заданный интервал (например, получить дату «30 дней назад»), и для неё применяется функция ДобавитьКДате с отрицательным значением.
Ниже разобраны все рабочие способы: вычитание дат в коде, в запросах, расчёт полных лет и месяцев, получение прошлой даты и типичные ошибки, которые приводят к неверным результатам в отчётах.
Как устроен тип «Дата» и что возвращает вычитание
В 1С значение типа «Дата» внутренне хранится как количество секунд, прошедших от начала отсчёта. Поэтому операция вычитания двух дат встроенным оператором «минус» допустима и возвращает число — разницу в секундах. Это базовый механизм, на котором строятся все остальные расчёты.
ДатаНачала = '20260110000000';
ДатаОкончания = '20260125000000';
РазницаВСекундах = ДатаОкончания - ДатаНачала; // 1296000
РазницаВДнях = РазницаВСекундах / 86400; // 15
Константа 86400 — это количество секунд в сутках (60 × 60 × 24). Деление на неё переводит результат в дни. Аналогично можно получить часы (деление на 3600) и минуты (деление на 60). Важно помнить: если даты содержат время, результат в днях будет дробным, и для получения целого числа дней нужно явно отбрасывать дробную часть через Цел() или предварительно обрезать время функцией НачалоДня().
Вычитание дат в запросах: функция РАЗНОСТЬДАТ
Когда расчёт выполняется в запросе — например, для отчёта о просроченной задолженности или динамического списка — используется функция языка запросов РАЗНОСТЬДАТ. Она принимает три параметра: начальную дату, конечную дату и единицу измерения результата.
ВЫБРАТЬ
Заказ.Ссылка КАК Заказ,
РАЗНОСТЬДАТ(Заказ.ДатаОтгрузки, &ТекущаяДата, ДЕНЬ) КАК ДнейПросрочки
ИЗ
Документ.ЗаказПокупателя КАК Заказ
В качестве третьего параметра допустимы значения: СЕКУНДА, МИНУТА, ЧАС, ДЕНЬ, МЕСЯЦ, КВАРТАЛ, ГОД. Функция считает количество полных единиц между датами: например, РАЗНОСТЬДАТ с единицей МЕСЯЦ между 31 января и 1 февраля вернёт 1, хотя прошли фактически сутки. Это особенность календарного подсчёта границ периодов, и её нужно учитывать при расчётах просрочек.
Если первая дата больше второй, результат будет отрицательным. Это удобно для универсальных запросов, но если нужен модуль разницы, используйте конструкцию ВЫБОР с проверкой условия.
Расчёт полных лет и месяцев: возраст и стаж
РАЗНОСТЬДАТ с единицей ГОД считает количество календарных границ годов между датами, а не полные прожитые годы. Для задач вроде «возраст сотрудника» или «стаж в годах» это часто не подходит: человеку, родившемуся 31 декабря, 1 января запрос припишет лишний год. Поэтому для кадровых расчётов применяют комбинированный подход.
Типовой приём — вычислить разницу в месяцах, разделить на 12 с отбрасыванием остатка, а затем скорректировать результат, если день рождения в текущем году ещё не наступил. В типовых конфигурациях (ЗУП, ERP) для этого существуют готовые функции общих модулей, например механизмы расчёта стажа — перед написанием собственного кода проверьте наличие типовой функции в вашей конфигурации.
Функция ПолныхЛет(ДатаРождения, НаДату)
Лет = Год(НаДату) - Год(ДатаРождения);
Если Месяц(НаДату) < Месяц(ДатаРождения)
Или (Месяц(НаДату) = Месяц(ДатаРождения)
И День(НаДату) < День(ДатаРождения)) Тогда
Лет = Лет - 1;
КонецЕсли;
Возврат Лет;
КонецФункции
Как вычесть из даты интервал: ДобавитьКДате
Обратная задача — получить дату, которая наступила за N дней, месяцев или лет до заданной. Для этого есть функция ДобавитьКДате(Дата, ТипИнтервала, Количество), где количество передаётся с отрицательным знаком. Во встроенном языке тип интервала указывается через перечисление ТипЕдиницыИзмеренияИнтервалаДаты.
МесяцНазад = ДобавитьКДате(ТекущаяДатаСеанса(),
ТипЕдиницыИзмеренияИнтервалаДаты.Месяц, -1);
НеделюНазад = ТекущаяДатаСеанса() - 7 * 86400;
Для вычитания целых дней допустим и простой арифметический способ: Дата - 7 * 86400. Но для месяцев, кварталов и лет арифметика в секундах не работает — у этих периодов разная длительность. Здесь обязательна ДобавитьКДате: она корректно обрабатывает переходы через границы месяцев и високосные годы. Например, вычитание месяца из 31 марта даст конец февраля, а не несуществующую дату.
В запросах аналогичную роль выполняет функция ДОБАВИТЬКДАТЕ(Дата, МЕСЯЦ, -1) с той же логикой отрицательного количества.
Сравнение способов вычитания дат
Подходит в коде для разницы в секундах, днях, часах. Не работает для месяцев и лет — их длительность непостоянна.
Подходит для отчётов и динамических списков, считает в любых единицах. Учитывайте: считает календарные границы, а не полные периоды.
Подходит для получения прошлой даты на заданный интервал, корректно обрабатывает месяцы и високосные годы. Не возвращает разницу между датами.
Частые ошибки при вычитании дат
Первая типичная ошибка — забыть про время в составе даты. Если сравниваются ДатаДокумента (с временем) и начало дня текущей даты, разница в днях после деления на 86400 окажется дробной, а при приведении к целому может дать результат на день меньше ожидаемого. Перед расчётом приводите обе даты к одной точности через НачалоДня().
Вторая ошибка — использование ТекущаяДата() на сервере в толстом клиенте с учётом часового пояса сеанса. В клиент-серверном режиме дата сервера может отличаться от даты пользователя. Для прикладных расчётов корректнее использовать ТекущаяДатаСеанса(), которая учитывает часовой пояс сеанса.
Третья ошибка — вычитание месяцев арифметикой в секундах с коэффициентом 30 × 86400. Такой подход накапливает погрешность: за год ошибка составит несколько дней. Для месяцев и лет — только ДобавитьКДате или РАЗНОСТЬДАТ.
Проверка результата и граничные случаи
После внедрения расчёта проверьте его на граничных данных: даты на стыке месяцев (31 января — 1 февраля), високосный февраль (28–29 февраля), даты с разным временем внутри одних суток, пустые даты. Пустая дата в 1С равна '00010101000000', и вычитание из неё реальной даты даст огромное отрицательное число — такие случаи нужно отсекать проверкой ЗначениеЗаполнено(Дата) до расчёта.
Также проверьте поведение при равных датах (результат должен быть 0, а не ошибка) и при обратном порядке дат (отрицательный результат или корректная обработка через ВЫБОР). Если расчёт используется в регламентном задании, убедитесь, что оно выполняется в нужном часовом поясе информационной базы.
Как проверить результат
Ровно 1 день или 86400 секунд
Дробное число дней или 0 — вероятно, мешает время в составе даты
Конец февраля (28 или 29 число)
Несуществующая дата или сдвиг на март — используется арифметика в секундах
Расчёт пропускается или возвращает контролируемое значение
Огромное отрицательное число попадает в отчёт
Полных лет на один меньше, чем календарная разница годов
Возраст завышен — использована РАЗНОСТЬДАТ с единицей ГОД без корректировки
Практический порядок действий
Выбор инструмента сводится к трём вопросам: где выполняется расчёт (код или запрос), в каких единицах нужен результат и что является входными данными — две даты или дата и интервал. Дальнейшие действия детерминированы.
- 1Определите место расчёта: встроенный язык или запрос
- 2Если нужна разница двух дат в коде — вычтите их оператором «минус» и разделите на 86400 для дней, предварительно применив НачалоДня()
- 3Если расчёт в запросе — используйте РАЗНОСТЬДАТ с нужной единицей измерения
- 4Если нужно получить прошлую дату — вызовите ДобавитьКДате с отрицательным количеством
- 5Проверьте расчёт на граничных датах: стык месяцев, високосный год, пустые даты
Перед написанием собственной функции расчёта стажа или возраста поищите готовую в общих модулях конфигурации (например, модули со словами «Даты», «Стаж», «ЗарплатаКадры» в имени). В типовых решениях такие функции уже учитывают тонкости календаря и локализации.
Частые вопросы
Как получить разницу между датами в днях без запроса?
Вычтите одну дату из другой и разделите результат на 86400: РазницаДней = (НачалоДня(Дата2) - НачалоДня(Дата1)) / 86400. Применение НачалоДня к обеим датам гарантирует целый результат без влияния времени.
Почему РАЗНОСТЬДАТ в месяцах даёт неожиданный результат?
Функция считает количество календарных границ месяцев между датами, а не полные 30-дневные периоды. Между 31 января и 1 февраля она вернёт 1 месяц. Если нужны «полные» месяцы, комбинируйте расчёт с проверкой дня месяца.
Как вычесть из даты 3 месяца в запросе?
Используйте функцию ДОБАВИТЬКДАТЕ(ВашаДата, МЕСЯЦ, -3). Отрицательное третье значение сдвигает дату назад, при этом корректно обрабатываются переходы через границы года и разная длина месяцев.
Что будет, если вычесть дату из пустой даты?
Пустая дата равна 01.01.0001, поэтому результатом станет огромное отрицательное число секунд. Перед расчётом проверяйте даты функцией ЗначениеЗаполнено() или условием Дата <> Дата(1,1,1).
Чем ТекущаяДатаСеанса лучше ТекущаяДата при расчётах?
ТекущаяДатаСеанса возвращает дату с учётом часового пояса сеанса пользователя, а ТекущаяДата на сервере — дату сервера. В распределённых по часовым поясам базах расчёт просрочек по серверной дате может давать ошибку в сутки.
Можно ли вычитать даты в СКД без запроса?
Да, в вычисляемых полях СКД доступна функция РазностьДат(Дата1, Дата2, "День") языка выражений компоновки. Единица измерения передаётся строкой: "Секунда", "Минута", "Час", "День", "Месяц", "Год".
Что важно запомнить
Вычитание дат оператором «минус» даёт секунды — для дней делите на 86400, предварительно обрезав время. В запросах и СКД используйте РАЗНОСТЬДАТ, помня, что она считает календарные границы периодов. Для получения прошлой даты применяйте ДобавитьКДате с отрицательным значением — только так корректно работают месяцы и годы. Всегда проверяйте пустые даты и граничные случаи перед выводом результата в отчёт.