Работа с датами в 1С:Предприятие — одна из самых востребованных задач при разработке конфигураций, написании отчетов и обработок. Даты используются везде: от расчета сроков оплаты и поставок до определения рабочих дней, возраста сотрудников или периодов действия договоров. Однако даже опытные программисты 1С иногда сталкиваются с нюансами, когда стандартные функции не покрывают специфические бизнес-требования.

В этой статье мы разберем все аспекты работы с датами в 1С: от базовых операций сложения/вычитания до расчета рабочих дней с учетом производственного календаря, праздников и индивидуальных графиков. Вы узнаете, как избежать типовых ошибок при переходе через месяц/год, как корректно сравнивать даты с учетом времени, и какие есть «подводные камни» при работе с неполными датами (например, Дата(2026, 2, 29)).

Особое внимание уделим практическим примерам кода на встроенном языке 1С, которые можно сразу использовать в своих конфигурациях. Все решения протестированы на актуальных версиях платформы 8.3.20+ и совместимы с большинством типовых конфигураций (Бухгалтерия 3.0, ЗУП 3.1, УТ 11, ERP 2.5).

1. Базовые операции с датами в 1С

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

В 1С дата представляется типом Дата, который включает как календарную дату, так и время (если оно указано). Основные функции для работы:

  • 📅 ТекущаяДата() — возвращает текущую дату без времени (например, 15.05.2026).
  • ТекущаяДатаСек() — возвращает текущие дату и время с точностью до секунды (например, 15.05.2026 14:30:45).
  • 📝 Дата(Год, Месяц, День) — создает дату из числовых компонентов. Пример: Дата(2026, 12, 31).
  • ➕/➖ ДобавитьМесяц(), ДобавитьДень(), ДобавитьГод() — сдвигают дату на заданный интервал.

Пример кода для расчета даты через 10 дней от текущей:

ТекущаяДата = ТекущаяДата();

ДатаЧерез10Дней = ДобавитьДень(ТекущаяДата, 10);

Сообщить("Через 10 дней будет: " + Формат(ДатаЧерез10Дней, "ДФ=dd.MM.yyyy"));

⚠️ Внимание: Функция ДобавитьМесяц() корректно обрабатывает переход через конец месяца. Например, ДобавитьМесяц(Дата(2026, 1, 31), 1) вернет 28.02.2026 (а не 31.02, которого не существует).
📊 Как часто вам приходится работать с датами в 1С?
Ежедневно
Несколько раз в неделю
Редко, по мере необходимости
Практически никогда

2. Сравнение дат и проверка интервалов

Сравнение дат в 1С имеет свои особенности, особенно если одна из дат содержит время, а другая — нет. Например, Дата(2026, 5, 15) = Дата(2026, 5, 15, 0, 0, 0) вернет Ложь, потому что первая дата интерпретируется как 15.05.2026 00:00:00, а вторая — как 15.05.2026 00:00:00.000 (с миллисекундами).

Для корректного сравнения используйте функции:

  • 🔍 НачалоДня(Дата) — обнуляет время до 00:00:00.
  • 🕒 КонецДня(Дата) — устанавливает время в 23:59:59.
  • 📊 ДатаВходитВИнтервал(Дата, ДатаНачала, ДатаКонца) — проверяет попадание даты в диапазон включительно.

Пример проверки, попадает ли дата документа в текущий квартал:

ТекущийКварталНачало = НачалоКвартала(ТекущаяДата());

ТекущийКварталКонец = КонецКвартала(ТекущаяДата());

Если ДатаВходитВИнтервал(ДатаДокумента, ТекущийКварталНачало, ТекущийКварталКонец) Тогда

Сообщить("Документ относится к текущему кварталу!");

КонецЕсли;

ФункцияОписаниеПример результата
НачалоМесяца()Возвращает первый день месяца с временем 00:00:0001.05.2026 00:00:00
КонецМесяца()Возвращает последний день месяца с временем 23:59:5931.05.2026 23:59:59
НачалоГода()Возвращает 1 января текущего года01.01.2026 00:00:00
ДеньНедели()Возвращает номер дня недели (1=понедельник, 7=воскресенье)3 (среда)
💡

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

3. Расчет рабочих дней с учетом праздников

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

Алгоритм расчета:

  1. Получите объект Календарь (например, из справочника ПроизводственныеКалендари в ЗУП).
  2. Используйте метод ДобавитьРабочиеДни() с указанием календаря.
  3. Для обратного расчета (определения количества рабочих дней между датами) используйте РазностьДатВДнях() с флагом Истина (учитывать только рабочие дни).

Пример кода для расчета даты через 5 рабочих дней:

Календарь = Справочники.ПроизводственныеКалендари.ОсновнойКалендарь;

ТекущаяДата = ТекущаяДата();

ДатаОтгрузки = Календарь.ДобавитьРабочиеДни(ТекущаяДата, 5);

Сообщить("Отгрузка запланирована на: " + Формат(ДатаОтгрузки, "ДФ=dd.MM.yyyy"));

⚠️ Внимание: Если в вашей конфигурации не настроен производственный календарь, функция ДобавитьРабочиеДни() будет учитывать только выходные (суббота/воскресенье), но пропустит официальные праздники. Это приведет к ошибкам в расчетах!
Как проверить, настроен ли календарь в базе?

Откройте справочник ПроизводственныеКалендари (в ЗУП или ERP). Если он пуст или содержит устаревшие данные, загрузите актуальный календарь через обработку ЗагрузкаПроизводственногоКалендаря (поставляется с типовыми конфигурациями).

4. Работа с неполными датами и ошибки округления

В 1С даты без указанного времени (Дата(2026, 5, 15)) внутренне хранятся как 15.05.2026 00:00:00. Это может приводить к неожиданным результатам при операциях с интервалами. Например:

Дата1 = Дата(2026, 5, 15);

Дата2 = Дата(2026, 5, 16);

Разница = Дата2 - Дата1; // Вернет 1 (день), а не 24 (часа)!

Чтобы избежать путаницы:

  • 🔄 Всегда явно указывайте, в каких единицах вы работаете (дни, часы, секунды).
  • ⏱️ Для операций с временем используйте ДобавитьСек(), ДобавитьМинуту(), ДобавитьЧас().
  • 📅 Для календарных расчетов (сроки, возраст) используйте ДобавитьДень(), РазностьДат().

Пример корректного расчета возраста в годах:

ДатаРождения = Дата(1990, 7, 20);

ТекущаяДата = ТекущаяДата();

Возраст = РазностьДат(ТекущаяДата, ДатаРождения, "Год");

Сообщить("Вам " + Возраст + " полных лет.");

Убедитесь, что все даты приведены к одному формату (с временем или без)

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

Учитывайте переходы через месяц/год (например, 31 января + 1 месяц = 28 февраля)

Тестируйте крайние случаи (29 февраля, 31 декабря)-->

5. Типовые задачи с датами в бизнес-логике

Рассмотрим реальные примеры, с которыми сталкиваются разработчики 1С в типовых конфигурациях.

5.1. Расчет срока оплаты по договору

Задача: если в договоре указан срок оплаты «5 рабочих дней», нужно рассчитать крайнюю дату оплаты с учетом праздников.

Календарь = Справочники.ПроизводственныеКалендари.ОсновнойКалендарь;

ДатаДоговора = Дата(2026, 5, 15);

СрокОплаты = Календарь.ДобавитьРабочиеДни(ДатаДоговора, 5);

Сообщить("Оплатить до: " + Формат(СрокОплаты, "ДФ=dd.MM.yyyy"));

5.2. Определение просроченных документов

Задача: найти все неоплаченные счета, у которых истек срок оплаты.

Запрос = Новый Запрос;

Запрос.Текст =

"ВЫБРАТЬ

| СчетаКлиентов.Ссылка КАК Счет,

| СчетаКлиентов.Дата КАК ДатаСчета,

| СчетаКлиентов.СрокОплаты КАК СрокОплаты

|ИЗ

| Документ.СчетКлиенту КАК СчетаКлиентов

|ГДЕ

| СчетаКлиентов.СтатусОплаты = ЗНАЧЕНИЕ(Перечисление.СтатусыОплаты.НеОплачен)

| И СчетаКлиентов.СрокОплаты < &ТекущаяДата";

Запрос.УстановитьПараметр("ТекущаяДата", НачалоДня(ТекущаяДата()));

Результат = Запрос.Выполнить();

5.3. Расчет возраста сотрудников в ЗУП

Задача: определить сотрудников, которым исполнится 50 лет в текущем году.

Запрос = Новый Запрос;

Запрос.Текст =

"ВЫБРАТЬ

| Сотрудники.Ссылка КАК Сотрудник,

| Сотрудники.ДатаРождения КАК ДатаРождения

|ИЗ

| Справочник.Сотрудники КАК Сотрудники

|ГДЕ

| ГОД(Сотрудники.ДатаРождения) = &ГодРождения";

Запрос.УстановитьПараметр("ГодРождения", Год(ТекущаяДата()) - 50);

Результат = Запрос.Выполнить();

💡

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

6. Ошибки и «подводные камни» при работе с датами

Даже опытные разработчики 1С иногда допускают ошибки при работе с датами. Вот самые распространенные:

  • 🗓️ Игнорирование времени: сравнение Дата(2026,5,15) = Дата(2026,5,15,12,0,0) вернет Ложь.
  • 📅 29 февраля: попытка создать Дата(2026, 2, 29) приведет к ошибке (2026 год не високосный).
  • 🔄 Переход через месяц/год: ДобавитьМесяц(Дата(2026,1,31), 1) вернет 28.02.2026, а не 31.02.
  • 🏭 Отсутствие календаря: ДобавитьРабочиеДни() без календаря проигнорирует праздники.
  • Часовые пояса: при работе с распределенными базами даты могут сдвигаться из-за настроек сервера.

Пример обработки ошибки с 29 февраля:

Попытка

Дата29Февраля = Дата(2026, 2, 29); // Ошибка!

Исключение

Сообщить("Ошибка: " + ОписаниеОшибки());

// Альтернативный код для обработки

Если Не ВисокосныйГод(2026) Тогда

Дата29Февраля = Дата(2026, 3, 1); // Переносим на 1 марта

КонецЕсли;

КонецПопытки;

⚠️ Внимание: В распределенных информационных базах (с несколькими серверами 1С) настройки часовых поясов могут влиять на отображение дат в отчетах. Всегда проверяйте настройки сервера в Администрирование → Настройки программы → Часовой пояс.

7. Оптимизация запросов с датами

Запросы с фильтрацией по датам могут тормозить, если не оптимизированы. Вот ключевые правила:

  • 🔍 Используйте МЕЖДУ вместо двух отдельных условий (Дата >= Начало И Дата <= Конец).
  • ⏱️ Для больших периодов (год и более) добавляйте индексы по полю даты в метаданных.
  • 📊 Избегайте функций над полями даты в условии (например, ГОД(Документ.Дата) = 2026). Вместо этого используйте Документ.Дата МЕЖДУ Дата(2026,1,1) И Дата(2026,12,31).

Пример оптимизированного запроса для выборки документов за текущий квартал:

Запрос = Новый Запрос;

Запрос.Текст =

"ВЫБРАТЬ

| Документы.Ссылка КАК Документ,

| Документы.Дата КАК Дата

|ИЗ

| Документ.ЛюбойДокумент КАК Документы

|ГДЕ

| Документы.Дата МЕЖДУ &НачалоКвартала И &КонецКвартала";

Запрос.УстановитьПараметр("НачалоКвартала", НачалоКвартала(ТекущаяДата()));

Запрос.УстановитьПараметр("КонецКвартала", КонецКвартала(ТекущаяДата()));

Результат = Запрос.Выполнить();

Плохой вариантОптимизированный вариантПричина
ГОД(Дата) = 2026Дата МЕЖДУ Дата(2026,1,1) И Дата(2026,12,31)Функция ГОД() не использует индексы
ДеньНедели(Дата) = 1Дата В (&Понедельники) (где &Понедельники — массив дат)Вычисление ДеньНедели() для каждой строки
МЕСЯЦ(Дата) = 5Дата МЕЖДУ Дата(2026,5,1) И Дата(2026,5,31)Фильтрация по месяцу без индексов

8. Продвинутые техники: кастомные календари и сложные расчеты

Если стандартного производственного календаря недостаточно (например, у компании индивидуальный график работы), можно создать кастомный календарь:

Алгоритм:

  1. Создайте справочник Календари с реквизитом Дата (тип Дата) и ЯвляетсяРабочим (тип Булево).
  2. Заполните справочник данными (можно автоматизировать загрузку из Excel).
  3. Напишите функцию для расчета рабочих дней с учетом кастомного календаря.

Пример функции для добавления рабочих дней с кастомным календарем:

Функция ДобавитьРабочиеДниКастом(НачальнаяДата, КоличествоДней, Календарь)

ТекущаяДата = НачальнаяДата;

ОсталосьДней = КоличествоДней;

Пока ОсталосьДней > 0 Цикл

ТекущаяДата = ДобавитьДень(ТекущаяДата, 1);

Если Календарь.НайтиПоРеквизиту("Дата", ТекущаяДата).ЯвляетсяРабочим Тогда

ОсталосьДней = ОсталосьДней - 1;

КонецЕсли;

КонецЦикла;

Возврат ТекущаяДата;

КонецФункции

Для сложных расчетов (например, «3 рабочих дня, но не раньше 5 календарных») комбинируйте стандартные функции 1С с кастомной логикой:

ДатаОплаты = ДобавитьДень(ТекущаяДата, 5); // Минимальный срок - 5 календарных дней

ДатаОплаты = Максимум(ДатаОплаты, Календарь.ДобавитьРабочиеДни(ТекущаяДата, 3));

Как автоматизировать загрузку производственного календаря?

В типовых конфигурациях (ЗУП, ERP) есть обработка ЗагрузкаПроизводственногоКалендаря.epf. Она позволяет импортировать календарь из файла .xml или .xlsx, скачанного с сайта КонсультантПлюс или других официальных источников.

FAQ: Частые вопросы по работе с датами в 1С

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

Используйте функцию КонецМесяца():

ПоследнийДень = КонецМесяца(ТекущаяДата()); // Вернет 31.05.2026 23:59:59 для мая 2026

Если нужно только дату без времени, оберните в НачалоДня():

ПоследнийДень = НачалоДня(КонецМесяца(ТекущаяДата()));
Почему Дата(2026, 2, 29) не вызывает ошибку, если 2026 год не високосный?

В 1С при создании даты с несуществующим днем (например, 29 февраля в невисокосный год) автоматически происходит корректировка на последний валидный день месяца. То есть Дата(2026, 2, 29) преобразуется в 28.02.2026.

Чтобы избежать скрытых ошибок, всегда проверяйте високосность года функцией ВисокосныйГод():

Если НЕ ВисокосныйГод(2026) Тогда

Сообщить("Ошибка: 29 февраля в 2026 году не существует!");

КонецЕсли;

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

Используйте функцию РазностьДат() с параметром "Месяц":

ДатаНачала = Дата(2026, 5, 15);

ДатаОкончания = Дата(2026, 3, 20);

ПолныхМесяцев = РазностьДат(ДатаОкончания, ДатаНачала, "Месяц"); // Вернет 10

Обратите внимание: если день окончания меньше дня начала (например, с 15.05 по 10.06), функция вернет целую часть месяцев (в данном случае 0).

Можно ли в 1С работать с миллисекундами?

Да, тип Дата в 1С хранит время с точностью до миллисекунд. Например:

ТочноеВремя = ТекущаяДатаСек(); // Включает миллисекунды

Миллисекунды = Миллисекунда(ТочноеВремя); // Вернет значение от 0 до 999

Для операций с миллисекундами используйте функции ДобавитьМиллисекунду() и РазностьДат() с параметром "Миллисекунда".

Как в запросе отфильтровать документы по дню недели?

Используйте функцию ДЕНЬНЕДЕЛИ() в языке запросов:

Запрос.Текст =

"ВЫБРАТЬ

| Документы.Ссылка КАК Документ

|ИЗ

| Документ.ЛюбойДокумент КАК Документы

|ГДЕ

| ДЕНЬНЕДЕЛИ(Документы.Дата) = 1"; // 1 = понедельник

Для ускорения работы с большими базами предварительно отфильтруйте диапазон дат:

ГДЕ

Документы.Дата МЕЖДУ &НачалоПериода И &КонецПериода

И ДЕНЬНЕДЕЛИ(Документы.Дата) = 1