Разработка и Конфигурация · 9 мин
Как программно сравнить даты в 1С
Как программно сравнить даты в 1С: операторы сравнения, НачалоДня, добавление секунд, проверка пустой даты, сравнение в запросах и типичные ошибки разработчиков.
Сравнение дат — одна из самых частых операций при разработке на платформе 1С:Предприятие. Проверка периода действия документа, отбор записей за интервал, контроль сроков оплаты — всё это сводится к корректному сопоставлению двух значений типа «Дата». При этом у даты в 1С есть особенности: она всегда содержит время с точностью до секунды, имеет специальное «пустое» значение и ведёт себя по-разному в коде и в запросах.
Ошибки при сравнении дат коварны: код не падает, а просто возвращает неверный результат. Документ не попадает в отбор, проверка даты оплаты «молча» не срабатывает, отчёт показывает лишние строки. Поэтому важно понимать, как именно платформа хранит и сравнивает даты, и какие приёмы считаются надёжными.
Как устроен тип «Дата» в 1С
Значение типа «Дата» во встроенном языке 1С всегда содержит и календарную дату, и время с точностью до секунды. Даже если вы видите в реквизите только «15.03.2026», внутри хранится «15.03.2026 0:00:00». Именно поэтому сравнение двух «одинаковых» дат может вернуть «Ложь»: у одной время 0:00:00, у другой — 14:23:47.
Литерал даты в коде записывается в апострофах в формате ГГГГММДД, при необходимости с добавлением времени: '20260315' или '20260315143000'. Альтернатива — функция Дата(2026, 3, 15). Пустое значение даты — это Дата(1, 1, 1), то есть 01.01.0001 0:00:00.
Базовые операторы сравнения дат
Для значений типа «Дата» работают все стандартные операторы сравнения: равно (=), не равно (<>), меньше, больше, меньше или равно, больше или равно. Сравнение выполняется с учётом времени: чем позже момент, тем «больше» дата.
Если Документ.ДатаОплаты < ТекущаяДата() Тогда
Сообщить("Срок оплаты истёк");
КонецЕсли;
Такой код корректен, когда сравниваются именно моменты времени. Проблема возникает, когда бизнес-смысл — «в пределах одного дня». Например, условие ДатаДокумента = ТекущаяДата() почти никогда не выполнится, потому что у текущей даты есть часы, минуты и секунды, а у даты документа обычно полночь.
Сравнение дат без учёта времени
Чтобы сравнить даты «по дню», оба значения приводят к началу дня функцией НачалоДня(). Она отсекает время, возвращая 0:00:00 указанной даты:
Если НачалоДня(Дата1) = НачалоДня(Дата2) Тогда
// Даты относятся к одному календарному дню
КонецЕсли;
Для проверки попадания момента в конкретный день удобна пара НачалоДня() и КонецДня(). Конец дня — это 23:59:59, поэтому условие «дата внутри дня» записывается как двойное сравнение:
Если ПроверяемаяДата >= НачалоДня(День)
И ПроверяемаяДата <= КонецДня(День) Тогда
// Момент попадает в указанный день
КонецЕсли;
Аналогично работают функции НачалоМесяца(), КонецМесяца(), НачалоКвартала(), КонецГода() — они позволяют сравнивать даты на уровне периода без ручного вычисления границ.
Проверка даты на пустое значение
Пустая дата не равна NULL и не равна нулю — это вполне конкретное значение 01.01.0001. Поэтому проверка выглядит как сравнение с литералом или функцией:
Если Документ.ДатаОплаты = Дата(1, 1, 1) Тогда
// Дата оплаты не заполнена
КонецЕсли;
Если Документ.ДатаОплаты = '00010101' Тогда
// То же самое через литерал
КонецЕсли;
Обратный вариант — проверка на заполненность через неравенство: ДатаОплаты <> Дата(1,1,1). В запросах пустая дата сравнивается с ДАТАВРЕМЯ(1,1,1), а если реквизит составного типа и может содержать NULL, потребуется дополнительная проверка ЕСТЬ NULL или функция ЕСТЬNULL().
Сравнение дат в запросах
В языке запросов 1С даты сравниваются теми же операторами, но параметры передаются как значения типа «Дата», а литералы записываются функцией ДАТАВРЕМЯ(год, месяц, день, часы, минуты, секунды). Типичный отбор за период выглядит так:
ВЫБРАТЬ
Реализация.Ссылка
ИЗ
Документ.РеализацияТоваровУслуг КАК Реализация
ГДЕ
Реализация.Дата >= &НачалоПериода
И Реализация.Дата <= &КонецПериода
При установке параметров важно передать границы корректно: начало — через НачалоДня(НачалоПериода), конец — через КонецДня(КонецПериода). Иначе документы, проведённые в течение последнего дня периода после полуночи, не попадут в выборку.
Для виртуальных таблиц регистров (остатки, обороты) границы периода лучше передавать в параметры виртуальной таблицы, а не в секцию ГДЕ — это заметно снижает объём обрабатываемых данных и ускоряет запрос.
- 1Определите границы: НачалоПериода = НачалоДня(ДатаНачала), КонецПериода = КонецДня(ДатаОкончания)
- 2Передайте обе границы в запрос через УстановитьПараметр()
- 3В тексте запроса используйте условие Дата >= &НачалоПериода И Дата <= &КонецПериода
- 4Проверьте результат на документе, проведённом в последние минуты конечного дня
Арифметика дат и функции сдвига
К дате можно прибавлять и вычитать число — это секунды. Например, Дата + 86400 сдвигает момент на сутки вперёд. Разность двух дат тоже даёт число секунд, из которого вычисляют дни: (Дата2 - Дата1) / 86400. Результат может быть дробным, если время у дат разное.
Для сдвига на месяцы и годы простое прибавление секунд не подходит из-за разной длины месяцев. Используйте функцию ДобавитьМесяц(Дата, КоличествоМесяцев) — она корректно обрабатывает переходы через год и короткие месяцы. Для сравнения «сколько полных месяцев между датами» часто комбинируют РазностьДат() в запросах с единицей измерения МЕСЯЦ, ДЕНЬ или СЕКУНДА.
РазностьСекунд = ДатаОкончания - ДатаНачала;
РазностьДней = Цел((НачалоДня(ДатаОкончания) - НачалоДня(ДатаНачала)) / 86400);
ЧерезМесяц = ДобавитьМесяц(ТекущаяДата(), 1);Проверка результата и отладка
Чтобы убедиться, что сравнение работает как задумано, выведите обе даты с полным временем через Формат(Дата, "ДЛФ=DT") или смотрите значения в табло отладчика. Если время различается — значит, нужна нормализация через НачалоДня().
Полезный приём — тестирование на граничных значениях: документ ровно в 0:00:00, документ в 23:59:59 последнего дня периода, пустая дата, даты в разных месяцах и годах. Если логика устойчива на этих точках, она почти наверняка корректна для всех промежуточных значений.
Как проверить корректность сравнения
Попадает в выборку независимо от времени проведения
Попадает только при времени 0:00:00
НачалоДня(Дата1) = НачалоДня(Дата2) возвращает Истина
Прямое сравнение дат возвращает Ложь из-за времени
Сравнение с Дата(1,1,1) возвращает Истина
Условие не срабатывает, проверка на пустоту не работает
FAQ
Чем отличается ТекущаяДата() от ТекущаяДатаСеанса()?
ТекущаяДата() возвращает дату компьютера, на котором выполняется код, а ТекущаяДатаСеанса() — дату сеанса с учётом часового пояса сеанса. В клиент-серверном режиме для сравнений с датами документов надёжнее использовать ТекущаяДатаСеанса(), чтобы избежать расхождений между часовыми поясами клиента и сервера.
Как сравнить только месяцы и годы двух дат?
Приведите обе даты к началу месяца: НачалоМесяца(Дата1) = НачалоМесяца(Дата2). Для сравнения по году используйте функцию Год(Дата) и сравнивайте полученные числа.
Можно ли сравнивать даты, преобразованные в строку?
Технически можно, но результат будет строковым сравнением, а не хронологическим. Строка «01.02.2026» окажется «меньше» строки «31.01.2026». Сравнивайте даты как значения типа «Дата», а в строку преобразуйте только для вывода пользователю.
Как в запросе найти записи с незаполненной датой?
Используйте условие Реквизит = ДАТАВРЕМЯ(1,1,1). Если поле составного типа и может содержать NULL, добавьте проверку Реквизит ЕСТЬ NULL или объедините оба условия через ИЛИ.
Почему условие «Дата = КонецДня(Период)» не находит документ?
Потому что равенство требует совпадения до секунды: документ должен быть проведён ровно в 23:59:59. Для попадания в день используйте диапазон: Дата >= НачалоДня(Период) И Дата <= КонецДня(Период).
Что важно запомнить
Дата в 1С всегда содержит время, поэтому для сравнения «по дню» применяйте НачалоДня() и КонецДня(). Пустая дата — это Дата(1,1,1), в запросах — ДАТАВРЕМЯ(1,1,1). Границы периодов передавайте в запрос уже нормализованными, а результат проверяйте на граничных значениях: полночь, 23:59:59 и пустая дата.