Работа с датами в 1С:Предприятие — одна из самых частых задач, с которыми сталкиваются и бухгалтеры при формировании отчетов, и программисты при написании обработок. Казалось бы, что может быть проще, чем отнять несколько дней от текущей даты? Но даже здесь есть подводные камни: неучет времени, ошибки при переходе через месяц или год, проблемы с нерабочими днями. Эта статья поможет разобраться во всех нюансах вычитания дней в 1С 8.3 и 8.2 — от базовых функций до профессиональных приемов для сложных расчетов.
Мы рассмотрим не только стандартные методы вроде Дата() + (-1), но и малоизвестные трюки с НачалоДня(), работой через ДобавитьМесяц() для корректного перехода через границы месяцев, а также автоматизацию вычитания рабочих дней с учетом праздников. Особое внимание уделим типичным ошибкам, из-за которых даты "съезжают" на сутки или вообще становятся невалидными. Готовые примеры кода вы сможете сразу использовать в своих конфигурациях.
Если вы никогда раньше не работали с датами в 1С, начните с первого раздела — там объяснены основы, которые пригодятся даже для простых отчетов. Опытные разработчики могут сразу перейти к разделам про вычитание рабочих дней или расчеты с учетом времени, где разобраны нетривиальные кейсы. Не забывайте, что поведение функций может отличаться в разных версиях платформы — всегда тестируйте код на своей базе!
1. Базовый метод: вычитание дней через арифметические операции
Самый простой способ отнять дни от даты в 1С — использовать арифметические операции с типом Дата. Платформа автоматически преобразует числа в дни, поэтому достаточно написать:
ТекущаяДата = ТекущаяДата();
ДатаМинус5Дней = ТекущаяДата - 5;
Этот код вернет дату, которая была 5 дней назад от сегодняшнего числа. Важно понимать, что 1С здесь работает с полными сутками, игнорируя время. Например, если сегодня 10.05.2026 15:30:00, то результат будет 05.05.2026 00:00:00 — время сбросится на начало дня.
Арифметический метод удобен своей лаконичностью, но имеет ограничения:
- ⚠️ Не учитывает рабочие/выходные дни (просто отнимает календарные сутки)
- ⏰ Сбрасывает время до
00:00:00, что может быть критично для временных отчетов - 📅 Не корректирует даты при переходе через месяц/год (но это делает платформа автоматически)
Для большинства бухгалтерских задач (например, расчет сроков оплаты по договору) этого метода достаточно. Но если вам нужно сохранить время или учитывать только рабочие дни — читайте следующие разделы.
Чтобы быстро проверить результат вычитания, используйте отладочную печать: Сообщить(ДатаМинус5Дней);. Это сэкономит время на поиск ошибок в коде.
2. Функция НачалоДня(): почему даты "съезжают" на сутки
Одна из самых распространенных ошибок при работе с датами в 1С — игнорирование функции НачалоДня(). Дело в том, что платформа хранит дату и время в одном поле, и если вы не обнулите временную часть, результаты расчетов могут оказаться неожиданными.
Рассмотрим пример:
ТекущаяДатаСВременем = '20260510153000'; // 10 мая 2026, 15:30
ДатаМинус1День = ТекущаяДатаСВременем - 1;
Казалось бы, результат должен быть 09.05.2026. Но на самом деле мы получим 09.05.2026 15:30:00 — платформа вычла ровно 24 часа, а не один календарный день. Чтобы избежать этого, всегда обнуляйте время:
ДатаМинус1День = НачалоДня(ТекущаяДатаСВременем) - 1;
Теперь результат будет корректным: 09.05.2026 00:00:00. Эта особенность важна для:
- 📊 Отчетов с группировкой по дням (чтобы не попадать в "вчерашние" данные)
- 💰 Расчетов пени по дням просрочки (где важна точная дата, а не время)
- 📦 Логистических задач (сроки доставки считаются в полных днях)
Что будет если не использовать НачалоДня() в отчетах?
При построении отчетов с группировкой по дням (например, продажи по дням) даты с временем могут попадать в неправильные группы. Например, запись от 10.05.2026 23:59 при вычитании 1 часа попадет в группировку 09.05.2026, искажая статистику.
3. Вычитание рабочих дней: учитываем выходные и праздники
В бизнес-задачах часто требуется вычесть не календарные, а именно рабочие дни (исключая субботу, воскресенье и праздники). Для этого в 1С нет встроенной функции, поэтому придется написать свой алгоритм или использовать внешние обработки.
Вот базовый пример кода для вычитания рабочих дней (без учета праздников):
Функция ВычестьРабочиеДни(ИсходнаяДата, КоличествоДней)
Результат = ИсходнаяДата;
ТекущаяДата = ИсходнаяДата;
Для Сч = 1 По КоличествоДней Цикл
ТекущаяДата = ТекущаяДата - 1;
Пока ДеньНедели(ТекущаяДата) = 6 Или ДеньНедели(ТекущаяДата) = 7 Цикл // 6=суббота, 7=воскресенье
ТекущаяДата = ТекущаяДата - 1;
КонецЦикла;
Результат = ТекущаяДата;
КонецЦикла;
Возврат Результат;
КонецФункции
Для учета праздников нужно создать справочник с датами праздников и модифицировать цикл:
Если НайтиПоНаименованию(Справочники.Праздники, Формат(ТекущаяДата, "ДФ=dd.MM.yyyy")) <> Неопределено Тогда
ТекущаяДата = ТекущаяДата - 1;
КонецЕсли;
Готовые решения для рабочих дней:
- 📁 Библиотека стандартных подсистем (БСП) содержит функции для работы с календарем
- 🔧 Обработка "Календарь.epf" от 1С (доступна на ИТС)
- 🌐 Онлайн-сервисы для получения производственного календаря (можно интегрировать через HTTP-запросы)
Создать справочник "Праздники"|Заполнить датами официальных праздников|Проверить региональные особенности (например, переносы выходных)|Протестировать функцию на граничных случаях (пятница → понедельник)-->
Важно: производственный календарь в России меняется ежегодно! Перед использованием функции обязательно обновляйте список праздников (обычно публикуется правительством в ноябре-декабре предыдущего года).
4. Вычитание дней через ДобавитьМесяц(): когда это нужно
На первый взгляд, функция ДобавитьМесяц() не имеет отношения к вычитанию дней. Однако она незаменима в двух случаях:
- Когда нужно вычесть дни с учетом конца месяца (например, отнять 3 дня от 31 января)
- Когда требуется сохранить последний день месяца при расчетах
Пример проблемы: если от 31.01.2026 отнять 3 дня арифметически, получим 28.01.2026. Но если нам нужно сохранить логику "последний день месяца", то результат должен быть 31.12.2026. Решение:
ИсходнаяДата = '20260131';
ДатаМинус3Дня = КонецМесяца(ДобавитьМесяц(ИсходнаяДата, -1)) - (3 - 1); // 31.12.2026
Таблица сравнения методов для граничных дат:
| Исходная дата | Арифметический метод | Через ДобавитьМесяц() | Ожидаемый результат |
|---|---|---|---|
| 31.01.2026 | 28.01.2026 | 31.12.2026 | 31.12.2026 |
| 28.02.2026 | 25.02.2026 | 31.01.2026 | 31.01.2026 |
| 30.04.2026 | 27.04.2026 | 31.03.2026 | 31.03.2026 |
Этот метод актуален для:
- 📅 Расчета сроков действия договоров (если привязаны к концу месяца)
- 💸 Начисления зарплаты за последние дни месяца
- 📊 Формирования отчетов с группировкой по "закрытию месяца"
Функция ДобавитьМесяц() сохраняет семантику "последнего дня месяца", что критично для финансовых расчетов, где важна точность до дня.
5. Работа с периодом: вычитание дней из начала/конца
В 1С часто используются не отдельные даты, а периоды (интервалы с началом и концом). При вычитании дней из такого объекта нужно учитывать, какую именно границу вы модифицируете.
Пример кода для работы с периодами:
Период = НачалоДня('20260501') + КонецДня('20260510');
НовыйПериодНачало = НачалоПериода(Период) - 2; // Отнимаем 2 дня от начала
НовыйПериодКонец = КонецПериода(Период) - 2; // Отнимаем 2 дня от конца
Типичные ошибки при работе с периодами:
- ❌ Путаница между
НачалоПериода()иКонецПериода()— первая функция возвращает дату начала, вторая — дату окончания - ❌ Забывают обнулять время с помощью
НачалоДня()/КонецДня(), из-за чего период "размывается" - ❌ Пытаются вычесть дни напрямую из переменной типа
Период(нужно работать с границами отдельно)
Для визуализации разницы между модификацией начала и конца периода:
| Действие | Исходный период | Результат |
|---|---|---|
| Отнять 1 день от начала | 01.05.2026 — 10.05.2026 | 30.04.2026 — 10.05.2026 |
| Отнять 1 день от конца | 01.05.2026 — 10.05.2026 | 01.05.2026 — 09.05.2026 |
| Отнять 1 день от обеих границ | 01.05.2026 — 10.05.2026 | 30.04.2026 — 09.05.2026 |
Периоды активно используются в:
- 📈 Отчетах с диапазоном дат (например, "продажи за период")
- 🔄 Регламентных заданиях (расписание выполнения по датам)
- 📂 Хранении исторических данных (версионность документов)
Период = НачалоДня(ТекущаяДата() - N) + КонецДня(ТекущаяДата() - 1);
Это создаст интервал длиной в N дней, заканчивающийся вчера.-->
6. Продвинутые техники: вычитание дней с учетом времени
Если в вашей задаче важно не только число, но и точное время (например, для логистических систем или систем мониторинга), стандартные методы не подойдут. Здесь нужно работать с секундами или использовать объекты МоментВремени.
Пример вычитания 24 часов (ровно одни сутки) с сохранением времени:
ДатаСВременем = '20260510153000'; // 10 мая, 15:30
ДатаМинус24Часа = ДатаСВременем - 86400; // 86400 секунд = 24 часа
Для более точных расчетов (например, вычитание 1 рабочего дня в 8 часов) можно использовать:
РабочийДеньВСекундах = 8 * 3600; // 8 часов
ДатаМинусРабочийДень = ДатаСВременем - РабочийДеньВСекундах;
Особенности работы с временем:
- ⏱️ В 1С время хранится в секундах с начала суток (00:00:00)
- 🌍 Учитывайте часовой пояс, если работаете с распределенными системами
- ⚡ Для высокоточных расчетов используйте
МоментВремени()вместо типаДата
Пример с МоментВремени():
Момент = МоментВремени(ТекущаяДата());
НовыйМомент = Момент - 86400; // Вычитаем ровно сутки
ДатаРезультат = Дата(НовыйМомент);
Когда нужно использовать МоментВремени вместо Дата?
Объект МоментВремени нужен в системах реального времени (мониторинг, логистика), где важна точность до секунды. Например, для расчета времени доставки с учетом часовых поясов или для синхронизации данных между филиалами в разных регионах.
7. Типичные ошибки и как их избежать
Даже опытные разработчики 1С иногда допускают ошибки при работе с датами. Вот самые распространенные ловушки и способы их обхода:
⚠️ Внимание: Если вы вычитаете дни из даты в форматеГодМесяцДень(например,20260510), а не используете типДата, платформа не сможет корректно обработать переход через месяц/год. Всегда преобразуйте строки в даты с помощьюДата(СтрокаДата).
Топ-5 ошибок и решения:
| Ошибка | Причина | Решение |
|---|---|---|
| Дата становится невалидной (например, 32 января) | Прямая манипуляция со строками вместо типа Дата | Используйте Дата() для преобразования |
| Результаты отличаются на сервере и клиенте | Разные настройки региональных стандартов | Явно устанавливайте формат даты |
Вычитание дней из Неопределено | Не проверена исходная дата на заполненность | Добавляйте проверку Если Дата = Неопределено Тогда... |
| "Съезд" даты на 1 день в отчетах | Не учтено время (например, 23:59 попадает в предыдущий день) | Применяйте НачалоДня() |
| Неправильный расчет рабочих дней | Не учтены региональные праздники или переносы | Используйте актуальный производственный календарь |
Для отладки проблем с датами используйте эти приемы:
- 🔍 Выводите промежуточные значения в отладочное окно:
Сообщить(ТипЗнч(ВашаДата)); - 📋 Проверяйте формат хранения даты:
Сообщить(Формат(Дата, "ДФ=yyyyMMdd HH:mm:ss")); - 🛠️ Тестируйте граничные случаи: переход через месяц, високосные годы, даты около праздников
90% ошибок с датами в 1С возникают из-за неявного приведения типов. Всегда явно преобразуйте строки в даты и наоборот, не полагаясь на автоматическое преобразование.
⚠️ Внимание: В версиях 1С:Предприятие 8.3.20+ изменилось поведение функции ДеньНедели() для дат до 1900 года. Если вы работаете с историческими данными, проверьте результаты этой функции в вашей версии платформы.
FAQ: Частые вопросы по вычитанию дней в 1С
Как вычесть дни из даты в запросе 1С?
В языке запросов 1С для вычитания дней используйте функцию ДОБАВИТЬКДАТЕ() с отрицательным значением:
ВЫБРАТЬ
ДОБАВИТЬКДАТЕ(ТекущаяДата(), ДЕНЬ, -5) КАК ДатаМинус5Дней
ИЗ
Справочник.ЛюбойСправочник КАК ЛюбойСправочник
Обратите внимание, что в запросах не работает арифметика дат как в встроенном языке.
Почему при вычитании 1 дня из 1 марта получаю 28 февраля, а не 29?
Это связано с тем, что 1С корректно обрабатывает переход через границы месяцев, но не учитывает високосные годы при "обратном" расчете. Чтобы получить 29 февраля, используйте:
ДатаРезультат = КонецМесяца(ДобавитьМесяц('20260301', -1)); // Вернет 28.02.2026 или 29.02.2026 в зависимости от года
Как вычесть дни из даты в форме 1С (например, в реквизите документа)?summary>
Для модификации даты прямо в форме:
- Создайте команду на форме с обработчиком
- В обработчике используйте код:
Объект.ДатаДокумента = НачалоДня(Объект.ДатаДокумента) - КоличествоДней;
- Обновите форму:
ОбновитьФорму();
Для удобства пользователей можно добавить кнопки "+1 день" и "-1 день" рядом с полем даты.
Объект.ДатаДокумента = НачалоДня(Объект.ДатаДокумента) - КоличествоДней;
ОбновитьФорму();Можно ли вычесть дни из даты в отчете на СКД?
Да, в Системе компоновки данных для этого:
- Откройте настройки поля даты
- В выражении используйте:
ДОБАВИТЬКДАТЕ([ВашеПоле], ДЕНЬ, -N) - Либо создайте вычисляемый ресурс с аналогичной формулой
Пример для параметра отчета:
Параметры.ДатаНачала = ДОБАВИТЬКДАТЕ(ТекущаяДата(), ДЕНЬ, -7);
Как учитывать праздничные дни при вычитании?
Для учета праздников:
- Создайте справочник "ПраздничныеДни" с реквизитом
Дата(типДата) - Заполните его датами из производственного календаря
- Модифицируйте функцию вычитания:
Пока НайтиПоПолю(Справочники.ПраздничныеДни, "Дата", ТекущаяДата) <> Неопределено ЦиклТекущаяДата = ТекущаяДата - 1;
КонецЦикла;
Для автоматизации можно загружать календарь из внешних источников (например, с сайта правительства РФ).