К статье
Практический материал

Разработка и Конфигурация · 10 мин

Как вычесть дату в 1С: все способы вычисления разницы между датами

Как вычесть дату в 1С: функция РАЗНОСТЬДАТ в запросе, вычитание дат в коде, разница в днях, месяцах и секундах. Примеры, ошибки и проверка результата.

Вычитание дат в 1С — одна из самых частых задач при разработке отчётов, расчёте стажа, сроков оплаты, просрочки задолженности и длительности операций. Проблема в том, что встроенный язык 1С не возвращает разницу между датами в днях или месяцах напрямую: обычное вычитание двух дат даёт результат в секундах, а для запросов нужна отдельная функция РАЗНОСТЬДАТ.

Способ вычитания зависит от контекста: в модуле объекта или форме работает арифметика с типом «Дата», в запросе — функция РАЗНОСТЬДАТ, а в типовых конфигурациях есть готовые процедуры общих модулей, например ОбщегоНазначения или ЗарплатаКадрыОбщегоНазначения. Выбор неправильного способа приводит к ошибкам: результат в секундах вместо дней, потеря дробной части при делении, неверный учёт високосных лет.

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

Как 1С хранит даты и почему вычитание даёт секунды

Значение типа «Дата» в 1С хранится с точностью до секунды и внутренне представляет собой количество секунд от начальной точки отсчёта. Поэтому оператор «минус» между двумя датами возвращает число — разницу в секундах, а не в днях. Это поведение зафиксировано в синтакс-помощнике и одинаково работает во всех версиях платформы 8.х.

РазницаВСекундах = ДатаОкончания - ДатаНачала; // число, секунды

Чтобы получить разницу в днях, результат делят на количество секунд в сутках — 86400. Если даты содержат время, дробная часть покажет неполные сутки. Например, разница между 10.03 12:00 и 12.03 18:00 даст 2,25 дня. Если нужно целое число дней, применяйте функцию Цел() или Окр() в зависимости от логики округления.

ДнейМежду = Цел((ДатаОкончания - ДатаНачала) / 86400);

Вычитание дат в коде: дни, часы и минуты

Базовый приём — вычесть меньшую дату из большей и перевести секунды в нужную единицу. Для часов делите на 3600, для минут — на 60. Порядок операндов важен: если вычесть большую дату из меньшей, получится отрицательное число, что иногда удобно для определения просрочки (отрицательное значение — срок ещё не наступил).

Разница в днях без учёта времени

Если время не имеет значения, надёжнее сначала отбросить его функцией НачалоДня(), а потом вычитать. Это исключает ситуацию, когда две даты в пределах одних календарных суток дают дробный результат из-за разного времени.

Дней = (НачалоДня(Дата2) - НачалоДня(Дата1)) / 86400;

Проверка порядка дат

Перед вычитанием полезно проверить, какая дата больше, особенно если данные приходят из документов, введённых пользователем. Обычное сравнение «больше/меньше» для дат работает корректно.

Если ДатаОкончания < ДатаНачала Тогда

// поменять местами или сообщить об ошибке

КонецЕсли;

bsl
РазницаВДнях = (НачалоДня(Дата2) - НачалоДня(Дата1)) / 86400;

Вычитание дат в запросе: функция РАЗНОСТЬДАТ

В языке запросов 1С арифметическое вычитание дат недоступно. Для расчёта разницы используется встроенная функция РАЗНОСТЬДАТ с тремя параметрами: первая дата, вторая дата и единица измерения. Результат — целое число единиц, уместившихся между датами.

РАЗНОСТЬДАТ(&ДатаНачала, &ДатаОкончания, ДЕНЬ) КАК ДнейПросрочки

Допустимые единицы измерения: СЕКУНДА, МИНУТА, ЧАС, ДЕНЬ, МЕСЯЦ, КВАРТАЛ, ГОД. Важная особенность: функция считает количество полных границ единицы между датами. Например, РАЗНОСТЬДАТ по месяцам между 31.01 и 01.02 вернёт 1, хотя прошли считанные часы, — пересечена одна граница месяца.

Если первая дата больше второй, функция вернёт отрицательное значение. Это удобно для расчёта просрочки: положительное число — дней прошло, отрицательное — дней осталось до срока.

Разница в месяцах и годах

Вычитание в месяцах и годах сложнее, чем в днях, потому что месяцы имеют разную длину, а годы бывают високосными. Делить секунды на усреднённое число дней в месяце (30,44) — грубое приближение, недопустимое в расчётах заработной платы, процентов и стажа.

В запросе для месяцев и лет используйте РАЗНОСТЬДАТ с единицами МЕСЯЦ и ГОД, понимая семантику «пересечённых границ». В коде для полных месяцев обычно пишут функцию: считают разницу месяцев, затем корректируют, если день окончания меньше дня начала.

Месяцев = (Год(Дата2) - Год(Дата1)) * 12 + Месяц(Дата2) - Месяц(Дата1);

Если День(Дата2) < День(Дата1) Тогда

Месяцев = Месяцев - 1;

КонецЕсли;

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

Сравнение вариантов

Вычитание в коде

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

РАЗНОСТЬДАТ в запросе

Оптимально для отчётов и отборов, работает на сервере СУБД, но считает границы периодов, а не полные интервалы.

Готовые функции типовой конфигурации

Правильный выбор для стажа, возраста и кадровых расчётов; ограничение — доступны только в типовых решениях.

Обратная задача: прибавить или отнять дни от даты

Частая смежная задача — не найти разницу, а получить новую дату, отстоящую от исходной на заданное число дней, месяцев или лет. В коде дни прибавляют прямым сложением секунд, а для месяцев и лет используют функцию ДобавитьМесяц().

НоваяДата = ИсходнаяДата + 7 * 86400;          // плюс 7 дней

НоваяДата = ДобавитьМесяц(ИсходнаяДата, -3); // минус 3 месяца

В запросе для сдвига даты применяется функция ДОБАВИТЬКДАТЕ с аналогичными единицами измерения. Отрицательное значение второго параметра сдвигает дату назад.

ДОБАВИТЬКДАТЕ(Документ.Дата, ДЕНЬ, -14) КАК ДатаНачалаПросрочки

ДобавитьМесяц корректно обрабатывает концы месяцев: при добавлении месяца к 31.01 результатом будет последний день февраля. Это отличает её от самодельных конструкций с пересчётом дней.

Порядок действий
  1. 1
    Определите контекст: код модуля или запрос
  2. 2
    Для кода вычтите даты и разделите на 86400 для дней
  3. 3
    Для запроса используйте РАЗНОСТЬДАТ с нужной единицей
  4. 4
    Проверьте порядок дат и обработайте пустые значения
  5. 5
    Проверьте результат на заведомо известном примере

Пустые даты и типичные ошибки

Пустая дата в 1С — это 01.01.0001 00:00:00. Если вычесть её из обычной даты, получится огромное число секунд, которое в днях даст десятки тысяч. Такой результат ломает отчёты и расчёты, поэтому перед вычитанием проверяйте заполненность обеих дат функцией ЗначениеЗаполнено() или сравнением с '00010101'.

Вторая частая ошибка — неявное преобразование при делении. Деление целых чисел в 1С даёт дробный результат автоматически, но при дальнейшем присвоении в реквизит с целочисленным типом дробная часть отсекается без округления. Если нужно округление по правилам, применяйте Окр() явно.

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

Типичные ошибки
01
Вычитание пустой даты даёт огромное число дней и искажает отчёт — проверяйте заполненность
02
Использование РАЗНОСТЬДАТ в МЕСЯЦ для полных месяцев — функция считает границы, а не полные периоды
03
Деление секунд на 86400 без НачалоДня при датах с временем даёт дробные дни
04
Перепутанный порядок операндов даёт отрицательную разницу и сбивает дальнейшие условия

Как проверить правильность результата

Самый надёжный способ проверки — прогнать расчёт на заведомо известных парах дат. Например, разница между 01.01 и 31.12 одного невисокосного года должна дать 364 дня; между 01.03 и 01.03 следующего года — 365 или 366 дней в зависимости от високосности.

Для запросов проверяйте результат в консоли запросов на реальных данных: отберите несколько документов, посчитайте разницу вручную по календарю и сравните с выводом РАЗНОСТЬДАТ. Особое внимание уделите парам на границах месяцев и лет — именно там проявляется семантика «пересечённых границ».

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

Контрольные точки

Как проверить результат

Разница между 01.01 и 02.01 одного года
Норма

Ровно 1 день (86400 секунд)

Тревожный признак

Дробное число или 0 — проверьте время и порядок дат

РАЗНОСТЬДАТ между 31.01 и 01.02 в месяцах
Норма

1 (пересечена граница месяца)

Тревожный признак

0 — возможно, перепутаны даты или единица измерения

Вычитание с пустой датой
Норма

Ошибка обработана, расчёт пропущен

Тревожный признак

Результат в десятки тысяч дней

Разница через високосный февраль
Норма

Учтён 29-й день февраля

Тревожный признак

Постоянная ошибка в 1 день на високосных годах

Частые вопросы

Как получить разницу между датами в днях в запросе 1С?

Используйте функцию РАЗНОСТЬДАТ(Дата1; Дата2; ДЕНЬ). Она вернёт целое число дней между датами; если первая дата позже второй, результат будет отрицательным. Арифметическое вычитание дат в языке запросов не поддерживается.

Почему вычитание дат в коде даёт большое число?

Оператор «минус» между датами возвращает разницу в секундах, а не в днях. Разделите результат на 86400, чтобы получить дни, на 3600 — часы, на 60 — минуты.

Как отнять от даты заданное количество дней?

В коде вычтите из даты произведение числа дней на 86400: Дата - 7 * 86400. Для месяцев используйте ДобавитьМесяц(Дата; -N). В запросе применяйте ДОБАВИТЬКДАТЕ с отрицательным значением.

Что вернёт вычитание, если одна из дат пустая?

Пустая дата равна 01.01.0001, поэтому разница получится огромной — сотни тысяч дней. Перед вычитанием проверяйте обе даты через ЗначениеЗаполнено() или сравнение с пустой датой.

Как правильно посчитать полные месяцы между датами?

РАЗНОСТЬДАТ с единицей МЕСЯЦ считает пересечённые границы месяцев, а не полные. Для полных месяцев в коде вычислите разницу месяцев и вычтите 1, если день окончания меньше дня начала. Для кадровых расчётов берите готовые функции типовой конфигурации.

Учитывается ли время при вычитании дат?

Да, даты в 1С хранятся с точностью до секунды, и время участвует в вычитании. Если время не нужно, приведите обе даты к началу дня функцией НачалоДня() перед вычитанием.

Итог

Что важно запомнить

В коде вычитание дат даёт секунды — делите на 86400 для дней. В запросе работает только РАЗНОСТЬДАТ с указанием единицы, считающая границы периодов. Всегда проверяйте заполненность дат, порядок операндов и тестируйте расчёт на границах месяцев и високосных годов.