Работа с датами в 1С:Предприятие 8.3 — одна из самых востребованных задач, с которой сталкиваются и бухгалтеры при формировании отчетов, и программисты при разработке бизнес-логики. Казалось бы, что может быть проще, чем вычесть одну дату из другой? Но на практике даже эта операция таит множество подводных камней: от неочевидных форматов хранения данных до особенностей работы с временными зонами. В отличие от Excel, где достаточно написать =B2-A2, в 1С придется учитывать тип данных, контекст выполнения (тонкий клиент, сервер, внешняя обработка) и даже настройки региональных параметров.
Эта статья охватывает все актуальные способы вычитания дат — от базовых арифметических операций до сложных запросов с группировкой по периодам. Мы разберем типичные ошибки (например, почему результат может оказаться не целым числом), покажем, как правильно работать с секундами, минутами и месяцами, а также дадим готовые коды для копирования. Особое внимание уделим нюансам, которые не описаны в официальной документации, но регулярно возникают на практике.
Если вы ищете способ посчитать разницу между датами для расчета просрочки платежей, определения стажа сотрудника или анализа временных интервалов в отчетах — здесь вы найдете решение под вашу задачу. А программисты 1С смогут оптимизировать код, избежав распространенных ошибок при работе с Тип("Дата").
1. Базовые операции: вычитание дат как чисел
Самый простой способ получить разницу между двумя датами в 1С — воспользоваться тем, что даты internally хранятся как числа (количество дней с 1 января 1899 года). Это позволяет применять к ним стандартные арифметические операции.
Пример кода для вычитания двух дат:
Дата1 = '2026-12-31';
Дата2 = '2026-01-01';
РазницаВДнях = Дата1 - Дата2; // Результат: 365
Важно понимать, что результат будет в днях, а не в месяцах или годах. Если вам нужна разница в других единицах — придется использовать дополнительные функции.
Что делать, если результат отрицательный? Это означает, что вторая дата позже первой. Чтобы всегда получать положительное значение, используйте функцию Абс():
Разница = Абс(Дата1 - Дата2);
⚠️ Внимание: При вычитании дат в форматеДД.ММ.ГГГГ ЧЧ:ММ:ССрезультат будет дробным числом, где целая часть — дни, а дробная — время. Например,'2026-01-01 12:00:00' - '2026-01-01 00:00:00'вернет0.5(полдня).
2. Функции для работы с интервалами: Год(), Месяц(), День()
Когда нужно получить разницу не в днях, а в месяцах или годах, простого вычитания недостаточно. Здесь приходят на помощь встроенные функции:
- 📅
Год(Дата)— возвращает год - 📆
Месяц(Дата)— возвращает месяц (1-12) - 🗓️
День(Дата)— возвращает день месяца (1-31) - ⏰
Час(Дата),Минута(Дата),Секunda(Дата)— для работы с временем
Пример расчета полных лет между датами:
ДатаРождения = '1990-05-15';
ТекущаяДата = ТекущаяДата();
ВозрастВГодах = Год(ТекущаяДата) - Год(ДатаРождения) -
?(Месяц(ТекущаяДата) < Месяц(ДатаРождения) ИЛИ
(Месяц(ТекущаяДата) = Месяц(ДатаРождения) И День(ТекущаяДата) < День(ДатаРождения)), 1, 0);
Этот код учитывает, прошел ли день рождения в текущем году. Аналогично можно рассчитывать разницу в месяцах или кварталах.
Для упрощения расчетов с датами создайте в 1С общую функцию РазницаВМесяцах(Дата1, Дата2) и используйте ее во всех обработках. Это сэкономит время и уменьшит количество ошибок.
3. Использование функции ДатаВремя() и добавление интервалов
Функция ДатаВремя(Год, Месяц, День, Час, Минута, Секунда) позволяет создавать даты с точностью до секунды. Это полезно, когда нужно вычесть не только даты, но и время. Например, для расчета продолжительности звонка или времени выполнения операции.
Пример вычитания временных интервалов:
Начало = ДатаВремя(2026, 5, 10, 9, 30, 0);
Конец = ДатаВремя(2026, 5, 10, 14, 45, 30);
РазницаВСекундах = (Конец - Начало) * 86400; // 86400 секунд в одном дне
РазницаВЧасах = РазницаВСекундах / 3600;
Обратите внимание на множитель 86400 — это количество секунд в одном дне. Такой подход дает более точный результат, чем простое вычитание часов, особенно если интервал пересекает полночь.
| Единица измерения | Формула для 1С | Пример результата |
|---|---|---|
| Секунды | (Дата2 - Дата1) * 86400 |
18930 (5 часов 15 минут 30 секунд) |
| Минуты | (Дата2 - Дата1) * 1440 |
315.5 (5 часов 15.5 минут) |
| Часы | (Дата2 - Дата1) * 24 |
5.25833 (5 часов и ~15 минут) |
| Недели | (Дата2 - Дата1) / 7 |
2.142857 (15 дней) |
4. Вычитание дат в запросах 1С
При работе с большими объемами данных удобнее использовать язык запросов 1С. Здесь для вычитания дат применяется функция РАЗНОСТЬДАТ(), которая возвращает разницу в днях, месяцах или годах.
Пример запроса для расчета просрочки платежей:
ВЫБРАТЬ
Клиенты.Наименование КАК Клиент,
Договоры.ДатаОплаты КАК СрокОплаты,
ТЕКУЩАЯДАТА() КАК Сегодня,
РАЗНОСТЬДАТ("день", ТЕКУЩАЯДАТА(), Договоры.ДатаОплаты) КАК ПросрочкаВДнях
ИЗ
Документ.Договоры КАК Договоры
ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.Клиенты КАК Клиенты
ПО Договоры.Клиент = Клиенты.Ссылка
ГДЕ
Договоры.ДатаОплаты < ТЕКУЩАЯДАТА()
И Договоры.Статус = ЗНАЧЕНИЕ(Перечисление.СтатусыДоговоров.НеОплачен)
Функция РАЗНОСТЬДАТ() поддерживает следующие параметры для единицы измерения:
- 📅
"день"— разница в днях - 📆
"месяц"— разница в месяцах - 🗓️
"год"— разница в годах - ⏰
"минута","час"— для временных интервалов
⚠️ Внимание: В запросах 1С функция РАЗНОСТЬДАТ() всегда возвращает целое число, округляя дробную часть. Если вам нужна точность до часов или минут — используйте вычитание в программном коде.
5. Работа с временными зонами и летним временем
Одна из самых сложных задач при вычитании дат в 1С — учет временных зон и перехода на летнее/зимнее время. По умолчанию 1С:Предприятие хранит даты в UTC, но отображает их в локальном времени пользователя. Это может приводить к расхождениям в расчетах, особенно если сервер и клиент находятся в разных часовых поясах.
Чтобы избежать ошибок:
- Используйте функцию
ЛокальнаяДата()для приведения даты к текущему часовому поясу. - Для серверных расчетов явным образом указывайте временную зону с помощью
УстановитьЧасовойПояс(). - При хранении временных меток в базе используйте тип
ДатаВремяСOffsetом(доступен с версии 8.3.20).
Пример корректного расчета интервала с учетом временной зоны:
// Устанавливаем часовой пояс Москвы (UTC+3)
УстановитьЧасовойПояс(Новый ЧасовойПояс(180, Ложь, "МСК"));
ДатаНачала = ЛокальнаяДата('2026-03-31T01:00:00'); // Переход на летнее время
ДатаКонца = ЛокальнаяДата('2026-03-31T03:00:00');
Разница = ДатаКонца - ДатаНачала; // Вернет 2 часа, а не 1
Почему разница может быть неравна реальному времени?
При переходе на летнее/зимнее время часы переводятся на 1 час вперед или назад. Если ваш интервал включает момент перехода (например, с 1:00 до 3:00 в день перехода на летнее время), то реальная разница составит 1 час вместо 2. Функция ЛокальнаяДата() учитывает это автоматически, но при ручных расчетах легко ошибиться.
6. Типичные ошибки и как их избежать
Даже опытные разработчики 1С иногда сталкиваются с неожиданными результатами при вычитании дат. Вот самые распространенные ошибки:
Ошибка 1: Игнорирование дробной части при вычитании дат с временем.
Решение: Используйте Окр() или Цел() только когда уверены, что дробная часть не важна. Например:
// Некорректно (потеря точности):
Дни = Цел(Дата2 - Дата1);
// Корректно (сохраняем часы и минуты):
Часы = (Дата2 - Дата1) * 24;
Ошибка 2: Прямое вычитание месяцев без учета разной длины.
Решение: Для расчета разницы в месяцах используйте цикл или рекурсивную функцию:
Функция РазницаВМесяцах(Дата1, Дата2)
Месяц1 = НачалоМесяца(Дата1);
Месяц2 = НачалоМесяца(Дата2);
Разница = 0;
Если Месяц1 > Месяц2 Тогда
Возврат -РазницаВМесяцах(Дата2, Дата1);
КонецЕсли;
Пока Месяц1 < Месяц2 Цикл
Разница = Разница + 1;
Месяц1 = КонецМесяца(Месяц1) + 1;
КонецЦикла;
Возврат Разница;
КонецФункции
Ошибка 3: Использование строковых функций для работы с датами.
Решение: Никогда не преобразуйте даты в строки для расчетов! Например, СтрЗнач(Дата1) - СтрЗнач(Дата2) вернет бессмыслицу. Всегда работайте с типом Дата.
Используются ли даты в одном формате (с временем или без)?
Учтена ли временная зона для серверных расчетов?
Нужна ли точность до секунд или достаточно дней?
Проверены ли даты на корректность (не NULL, не 01.01.0001)?-->
7. Практический пример: расчет стажа сотрудника
Рассмотрим реальную задачу — расчет трудового стажа сотрудника с учетом всех нюансов. Нам нужно получить стаж в виде "X лет Y месяцев Z дней".
Исходные данные:
- 📅 Дата приема на работу:
2018-06-15 - 📆 Текущая дата:
2026-11-20
Решение с использованием встроенных функций:
Процедура РассчитатьСтаж(ДатаПриема, ДатаОтчета, СтажЛет, СтажМесяцев, СтажДней)
// Приводим даты к началу дня
ДатаПриема = НачалоДня(ДатаПриема);
ДатаОтчета = НачалоДня(ДатаОтчета);
// Рассчитываем полные годы
СтажЛет = Год(ДатаОтчета) - Год(ДатаПриема);
Если Месяц(ДатаОтчета) < Месяц(ДатаПриема) Или
(Месяц(ДатаОтчета) = Месяц(ДатаПриема) И День(ДатаОтчета) < День(ДатаПриема)) Тогда
СтажЛет = СтажЛет - 1;
КонецЕсли;
// Добавляем годы к дате приема для расчета месяцев
ДатаСГодами = Дата(Год(ДатаПриема) + СтажЛет, Месяц(ДатаПриема), День(ДатаПриема));
// Рассчитываем полные месяцы
СтажМесяцев = Месяц(ДатаОтчета) - Месяц(ДатаСГодами);
Если День(ДатаОтчета) < День(ДатаСГодами) Тогда
СтажМесяцев = СтажМесяцев - 1;
КонецЕсли;
Если СтажМесяцев < 0 Тогда
СтажМесяцев = СтажМесяцев + 12;
СтажЛет = СтажЛет - 1;
КонецЕсли;
// Рассчитываем дни
ДатаСМесяцами = Дата(Год(ДатаСГодами), Месяц(ДатаСГодами) + СтажМесяцев, День(ДатаСГодами));
СтажДней = ДатаОтчета - ДатаСМесяцами;
КонецПроцедуры
Важно: Этот алгоритм корректно обрабатывает случаи, когда день рождения (или дата приема) еще не наступил в текущем месяце, например, при расчете стажа на 20 ноября для сотрудника, принятого 15 июня.
8. Оптимизация производительности при массовых расчетах
Если вам нужно вычесть даты для тысяч записей (например, при формировании отчета по просроченным платежам), прямой перебор в цикле может тормозить систему. В таких случаях:
Способ 1: Используйте запросы с агрегатными функциями. Например:
ВЫБРАТЬ
РАЗНОСТЬДАТ("день", ТЕКУЩАЯДАТА(), Договоры.СрокОплаты) КАК Просрочка,
СУММА(Договоры.Сумма) КАК СуммаПросрочки
ИЗ
Документ.Договоры КАК Договоры
ГДЕ
Договоры.СрокОплаты < ТЕКУЩАЯДАТА()
СГРУППИРОВАТЬ ПО
РАЗНОСТЬДАТ("день", ТЕКУЩАЯДАТА(), Договоры.СрокОплаты)
Способ 2: Для сложных расчетов (например, стажа в годах/месяцах) создайте виртуальную таблицу с предварительно рассчитанными значениями и присоединяйте ее к основному запросу.
Способ 3: Если расчеты выполняются на клиенте, используйте ПоместитьВременныеДанные() для кэширования промежуточных результатов.
⚠️ Внимание: При работе с большими базами данных (100 000+ записей) избегайте функцийГод()/Месяц()в запросах — они не оптимизированы и могут тормозить выполнение. Лучше рассчитывать такие значения в программном коде после получения данных.
Для массовых расчетов разницы дат всегда отдавайте предпочтение языку запросов 1С — он работает на сервере и оптимизирован для обработки больших объемов данных.
FAQ: Ответы на частые вопросы
Можно ли вычесть из даты число (например, 5 дней)?
Да, в 1С поддерживается обратная операция: НоваяДата = ТекущаяДата() - 5; — отнимет 5 дней. Аналогично работает сложение. Для других единиц (месяцы, годы) используйте функции ДобавитьМесяц(), НачалоГода() и т.д.
Почему при вычитании двух одинаковых дат получается не ноль?
Скорее всего, одна из дат содержит время (например, '2026-01-01 00:00:00' и '2026-01-01 23:59:59'). Используйте НачалоДня(), чтобы привести обе даты к одному формату: НачалоДня(Дата1) - НачалоДня(Дата2).
Как посчитать количество рабочих дней между датами?
Для этого нужно исключить выходные и праздники. В 1С нет встроенной функции, но можно:
- Создать справочник
ПраздничныеДнис датами. - Использовать цикл для перебора дней между датами.
- Проверять каждый день на попадание в выходной (суббота/воскресенье) или праздничный день.
Готовый код для расчета рабочих дней:
Функция РабочиеДни(ДатаНачала, ДатаКонца)
Дни = 0;
ТекущаяДата = НачалоДня(ДатаНачала);
Пока ТекущаяДата <= НачалоДня(ДатаКонца) Цикл
Если НЕ (ДеньНедели(ТекущаяДата) = 6 ИЛИ ДеньНедели(ТекущаяДата) = 7) И
НЕ ПраздничныйДень(ТекущаяДата) Тогда
Дни = Дни + 1;
КонецЕсли;
ТекущаяДата = ТекущаяДата + 86400; // +1 день в секундах
КонецЦикла;
Возврат Дни;
КонецФункции
Как вычесть даты в отчете с группировкой по периодам?
Используйте конструкцию ВЫРАЗИТЬ в языке запросов. Пример для группировки по кварталам:
ВЫБРАТЬ
ВЫРАЗИТЬ(Год(Документы.Дата) КАК СТРОКА + ' Q' +
СТРОКА((Месяц(Документы.Дата) + 2) \ 3) КАК СТРОКА) КАК Квартал,
СУММА(Документы.Сумма) КАК Сумма
ИЗ
Документ.РеализацияТоваровУслуг КАК Документы
СГРУППИРОВАТЬ ПО
ВЫРАЗИТЬ(Год(Документы.Дата) КАК СТРОКА + ' Q' +
СТРОКА((Месяц(Документы.Дата) + 2) \ 3) КАК СТРОКА)
Можно ли вычесть даты в разных форматах (например, с временем и без)?
Да, но результат может быть неожиданным. 1С автоматически преобразует даты без времени к 00:00:00. Например:
'2026-01-01 12:00:00' - '2026-01-01' // Вернет 0.5 (полдня)
Чтобы избежать ошибок, всегда приводите даты к одному формату с помощью НачалоДня() или КонецДня().