Разработка и Конфигурация · 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;
Проверка порядка дат
Перед вычитанием полезно проверить, какая дата больше, особенно если данные приходят из документов, введённых пользователем. Обычное сравнение «больше/меньше» для дат работает корректно.
Если ДатаОкончания < ДатаНачала Тогда
// поменять местами или сообщить об ошибке
КонецЕсли;
РазницаВДнях = (НачалоДня(Дата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Определите контекст: код модуля или запрос
- 2Для кода вычтите даты и разделите на 86400 для дней
- 3Для запроса используйте РАЗНОСТЬДАТ с нужной единицей
- 4Проверьте порядок дат и обработайте пустые значения
- 5Проверьте результат на заведомо известном примере
Пустые даты и типичные ошибки
Пустая дата в 1С — это 01.01.0001 00:00:00. Если вычесть её из обычной даты, получится огромное число секунд, которое в днях даст десятки тысяч. Такой результат ломает отчёты и расчёты, поэтому перед вычитанием проверяйте заполненность обеих дат функцией ЗначениеЗаполнено() или сравнением с '00010101'.
Вторая частая ошибка — неявное преобразование при делении. Деление целых чисел в 1С даёт дробный результат автоматически, но при дальнейшем присвоении в реквизит с целочисленным типом дробная часть отсекается без округления. Если нужно округление по правилам, применяйте Окр() явно.
Третья ошибка — использование разницы в днях для расчёта месячной задолженности или стажа. Календарные месяцы разной длины делают такой пересчёт неточным: 30 дней — это не всегда месяц. Для юридически значимых периодов считайте в единицах, которые требует регламент.
Как проверить правильность результата
Самый надёжный способ проверки — прогнать расчёт на заведомо известных парах дат. Например, разница между 01.01 и 31.12 одного невисокосного года должна дать 364 дня; между 01.03 и 01.03 следующего года — 365 или 366 дней в зависимости от високосности.
Для запросов проверяйте результат в консоли запросов на реальных данных: отберите несколько документов, посчитайте разницу вручную по календарю и сравните с выводом РАЗНОСТЬДАТ. Особое внимание уделите парам на границах месяцев и лет — именно там проявляется семантика «пересечённых границ».
Если расчёт используется в регламентированных отчётах или расчёте зарплаты, сверьте результат с данными типовой конфигурации на том же периоде. Расхождение — признак того, что выбран не тот способ вычисления.
Как проверить результат
Ровно 1 день (86400 секунд)
Дробное число или 0 — проверьте время и порядок дат
1 (пересечена граница месяца)
0 — возможно, перепутаны даты или единица измерения
Ошибка обработана, расчёт пропущен
Результат в десятки тысяч дней
Учтён 29-й день февраля
Постоянная ошибка в 1 день на високосных годах
Частые вопросы
Как получить разницу между датами в днях в запросе 1С?
Используйте функцию РАЗНОСТЬДАТ(Дата1; Дата2; ДЕНЬ). Она вернёт целое число дней между датами; если первая дата позже второй, результат будет отрицательным. Арифметическое вычитание дат в языке запросов не поддерживается.
Почему вычитание дат в коде даёт большое число?
Оператор «минус» между датами возвращает разницу в секундах, а не в днях. Разделите результат на 86400, чтобы получить дни, на 3600 — часы, на 60 — минуты.
Как отнять от даты заданное количество дней?
В коде вычтите из даты произведение числа дней на 86400: Дата - 7 * 86400. Для месяцев используйте ДобавитьМесяц(Дата; -N). В запросе применяйте ДОБАВИТЬКДАТЕ с отрицательным значением.
Что вернёт вычитание, если одна из дат пустая?
Пустая дата равна 01.01.0001, поэтому разница получится огромной — сотни тысяч дней. Перед вычитанием проверяйте обе даты через ЗначениеЗаполнено() или сравнение с пустой датой.
Как правильно посчитать полные месяцы между датами?
РАЗНОСТЬДАТ с единицей МЕСЯЦ считает пересечённые границы месяцев, а не полные. Для полных месяцев в коде вычислите разницу месяцев и вычтите 1, если день окончания меньше дня начала. Для кадровых расчётов берите готовые функции типовой конфигурации.
Учитывается ли время при вычитании дат?
Да, даты в 1С хранятся с точностью до секунды, и время участвует в вычитании. Если время не нужно, приведите обе даты к началу дня функцией НачалоДня() перед вычитанием.
Что важно запомнить
В коде вычитание дат даёт секунды — делите на 86400 для дней. В запросе работает только РАЗНОСТЬДАТ с указанием единицы, считающая границы периодов. Всегда проверяйте заполненность дат, порядок операндов и тестируйте расчёт на границах месяцев и високосных годов.