Работа с датами в 1С:Предприятие — одна из самых востребованных задач при разработке отчётов, обработок и бизнес-логики. Казалось бы, что может быть проще, чем сравнить две даты? Но на практике даже опытные программисты сталкиваются с нюансами: учёт рабочих дней, временные зоны, формат хранения, особенности сравнения с пустыми значениями. Эта статья не просто перечислит способы сравнения — она раскроет подводные камни, которые приводят к ошибкам в коде, и покажет оптимальные решения для типовых задач.

Мы разберём всё: от элементарных операторов = и > до сложных алгоритмов с использованием Календарей и РабочихДней. Особое внимание уделим разнице между сравнением дат в запросах и встроенном языке, а также типичным ошибкам, из-за которых отчёты показывают неверные данные. Если вы когда-нибудь получали сообщение «Тип не совпадает (Дата, Неопределённое)» — здесь вы найдёте решение.

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

Начнём с азов. В 1С 8.3/8.2 даты сравниваются так же, как и числа, но с учётом их внутреннего представления. Платформа хранит даты в формате ДД.ММ.ГГГГ ЧЧ:ММ:СС, даже если время не указано явно. Это означает, что:

  • 📅 Дата1 = Дата2 — полное совпадение даты и времени (если время не указано, оно равно 00:00:00).
  • 🕒 Дата1 > Дата2 — сравниваются даты вместе с временем, поэтому '01.01.2023 23:59' > '02.01.2023 00:00' вернёт Ложь.
  • 🗓️ Дата1 >= НачалоДня(Дата2) — проверка, что Дата1 попадает в день Дата2 (включая его начало).

Пример кода для проверки, что текущая дата позже 1 января 2023 года:

Если ТекущаяДата() > '01.01.2023' Тогда

Сообщить("2023 год уже наступил!");

КонецЕсли;

Важно! Если в дате не указано время, платформа подставляет 00:00:00. Это часто приводит к ошибкам при сравнении дат с временем. Например, '01.01.2023' = '01.01.2023 00:00:00' вернёт Истина, а '01.01.2023' = '01.01.2023 12:00:00'Ложь.

💡

Всегда используйте функции НачалоДня(), КонецДня() или ДатаВремя(), если нужно игнорировать время при сравнении.

2. Сравнение дат без учёта времени

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

  • 🌅 НачалоДня(Дата) — возвращает дату с временем 00:00:00.
  • 🌇 КонецДня(Дата) — возвращает дату с временем 23:59:59.
  • 📊 Дата1 >= НачалоДня(Дата2) И Дата1 <= КонецДня(Дата2) — проверка попадания в один день.

Пример: проверка, что документ создан сегодня:

Если ДатаДокумента >= НачалоДня(ТекущаяДата()) И ДатаДокумента <= КонецДня(ТекущаяДата()) Тогда

Сообщить("Документ создан сегодня!");

КонецЕсли;

Альтернативный способ — приведение к типу Дата (без времени):

Если Дата(Дата1) = Дата(Дата2) Тогда

// Даты совпадают без учёта времени

КонецЕсли;

📊 Какой способ сравнения дат без времени используете вы?
НачалоДня()/КонецДня()
Функция Дата()
Сравниваю строки
Другой вариант

3. Сравнение дат в запросах 1С

В языке запросов сравнение дат имеет свои особенности. Здесь нельзя использовать функции вроде НачалоДня() напрямую — нужно применять конструкции языка запросов или вычисляемые поля.

Примеры:

Задача Код в запросе Пояснение
Выбрать документы за сегодня ГДЕ ДатаДокумента >= &НачалоДня И ДатаДокумента <= &КонецДня Параметры &НачалоДня и &КонецДня передаются из встроенного языка.
Выбрать документы за текущий месяц ГДЕ ДатаДокумента >= НачалоМесяца(&ТекущаяДата) И ДатаДокумента <= КонецМесяца(&ТекущаяДата) Используются функции языка запросов.
Сравнить даты без времени ГДЕ ДЕНЬ(ДатаДокумента) = ДЕНЬ(&СравниваемаяДата) И МЕСЯЦ(ДатаДокумента) = МЕСЯЦ(&СравниваемаяДата) Неэффективный способ, но работает без дополнительных параметров.

Критическая ошибка: если в запросе сравнивать даты напрямую (ГДЕ ДатаДокумента = &ПараметрДата), то запись с временем 12:00:00 не попадёт в выборку, если в параметре время не указано (00:00:00).

Почему не работает сравнение дат в отчёте?

Если в отчёте данные группируются по дате, но некоторые записи "пропадают", проверьте:

1. Формат хранения даты в регистре (возможно, там есть миллисекунды).

2. Наличие временной зоны в базе (актуально для распределённых информационных систем).

3. Использование функции ТолькоДата() в вычисляемых полях отчёта.

4. Работа с пустыми датами и неопределёнными значениями

В дата может быть не только заполненной, но и пустой (Неопределённое). Attempt to compare a date with an undefined value leads to a runtime error. Чтобы избежать ошибок, используйте функции проверки:

  • 🚫 ЗначениеЗаполнено(Дата) — проверяет, что дата не пустая.
  • ТипЗнч(Дата) = Тип("Дата") — проверяет, что переменная содержит дату (а не строку или число).
  • ⚠️ Дата = '00010101' — проверка на "нулевую" дату (1 января 1 года), которая иногда используется как замена пустому значению.

Пример безопасного сравнения:

Если ЗначениеЗаполнено(ДатаДокумента) И ДатаДокумента >= НачалоДня(ТекущаяДата()) Тогда

// Обработка даты

Иначе

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

КонецЕсли;

⚠️ Внимание: В некоторых конфигурациях (например, 1С:ЗУП) "пустые" даты могут храниться как '00010101'. Перед сравнением проверяйте это значение явно, если база мигрировалась из старых версий.

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

Для бизнес-логики часто нужно учитывать только рабочие дни (исключая выходные и праздники). В это реализуется через:

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

Пример: проверка, что дата является рабочим днём:

Календарь = Календари.ПроизводственныйКалендарь();

Если НЕ Календарь.ЭтоРабочийДень(ДатаПроверки) Тогда

Сообщить("Этот день выходной или праздничный!");

КонецЕсли;

Для сравнения двух дат с учётом только рабочих дней:

КоличествоДней = РабочиеДниМежду(Дата1, Дата2, Календари.ПроизводственныйКалендарь());

Если КоличествоДней > 5 Тогда

Сообщить("Между датами больше 5 рабочих дней!");

КонецЕсли;

⚠️ Внимание: В распределённых базах (с территориально удалёнными подразделениями) календари могут отличаться. Всегда уточняйте, какой календарь используется в конкретном расчёте.

Использовать объект Календарь|Проверить региональные праздники|Учесть сменный график работы (если есть)|Тестировать на граничных датах (например, 31 декабря)

-->

6. Сравнение дат с временными зонами

В распределённых информационных системах или при интеграции с внешними сервисами даты могут храниться в разных временных зонах. 1С:Предприятие поддерживает работу с временными зонами через:

  • 🌍 ЧасовойПояс — объект для хранения информации о временной зоне.
  • ВремяВЧасовомПоясе() — преобразует дату в указанную временную зону.
  • 🔄 ТекущаяВременнаяЗона() — возвращает временную зону текущего сеанса.

Пример: сравнение дат в разных временных зонах:

// Дата в московском времени

ДатаМСК = '01.01.2023 12:00:00';

ЧасовойПоясМСК = ЧасовойПояс.МСК;

// Дата в екатеринбургском времени (+2 часа)

ДатаЕКБ = ВремяВЧасовомПоясе(ДатаМСК, ЧасовойПояс.ЕКБ);

// Сравнение

Если ДатаЕКБ = '01.01.2023 14:00:00' Тогда

Сообщить("Время корректно преобразовано!");

КонецЕсли;

Важно! В облачных решениях (например, 1С:Fresh) временная зона сервера может отличаться от локальной. Всегда уточняйте настройки временной зоны в параметрах информационной базы.

7. Оптимизация сравнения дат в больших выборках

При работе с большими объёмами данных (например, в отчётах по миллиону документов) сравнение дат может тормозить систему. Оптимизируйте код следующими способами:

  • Индексируйте поля с датами в регистрах и справочниках.
  • 📈 Используйте виртуальные таблицы (например, РегистрСведений.ОстаткиИОбороты) с предварительной агрегацией по датам.
  • 🔍 В запросах применяйте ИНДЕКСИРОВАТЬ ПО для полей с датами.
  • 🗑️ Избегайте функций вроде ДЕНЬ(), МЕСЯЦ() в условиях ГДЕ — они блокируют использование индексов.

Пример оптимизированного запроса:

ВЫБРАТЬ

ДатаДокумента КАК Дата,

СУММА(Сумма) КАК Итого

ИЗ

Документ.РеализацияТоваровУслуг

ГДЕ

ДатаДокумента >= &НачалоПериода

И ДатаДокумента <= &КонецПериода

СГРУППИРОВАТЬ ПО

ДатаДокумента

ИНДЕКСИРОВАТЬ ПО

ДатаДокумента

💡

Для ускорения отчётов по датам всегда используйте индексы и избегайте функций над полями в условиях ГДЕ.

8. Типичные ошибки и как их избежать

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

Ошибка Причина Решение
Сравнение даты со строкой Оператор = между Дата и Строка вызывает ошибку. Используйте Дата(СтрокаДата) для преобразования.
Игнорирование времени Сравнение '01.01.2023' = '01.01.2023 12:00:00' вернёт Ложь. Применяйте НачалоДня() или Дата().
Пустые даты в агрегатных функциях МАКСИМУМ(Дата) вернёт Неопределённое, если есть пустые значения. Используйте ВЫБОР КОГДА ЗначениеЗаполнено(Дата) ТОГДА Дата КОНЕЦ.
Неверный учёт временных зон Дата в UTC и локальная дата могут отличаться на несколько часов. Явно указывайте временную зону при сравнении.

Пример обработки пустых дат в запросе:

ВЫБРАТЬ

ВЫБОР

КОГДА ЗначениеЗаполнено(ДатаДокумента)

ТОГДА ДатаДокумента

ИНАЧЕ '00010101'

КОНЕЦ КАК Дата,

Сумма

ИЗ

Документ.ПоступлениеТоваров

⚠️ Внимание: В некоторых версиях 1С:Предприятие 8.2 функция ЗначениеЗаполнено() в запросах работает иначе, чем во встроенном языке. Тестируйте запросы на целевой платформе.

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

Как сравнить дату с сегодняшним днём без учёта времени?

Используйте конструкцию:

Если ДатаДокумента >= НачалоДня(ТекущаяДата()) И ДатаДокумента <= КонецДня(ТекущаяДата()) Тогда

// Дата сегодня

КонецЕсли;

Или сокращённо:

Если Дата(ДатаДокумента) = ТекущаяДата() Тогда
Почему запрос не находит документы за текущий день?

Скорее всего, в запросе сравниваются даты с временем. Например, если в базе дата хранится как '05.05.2023 14:30:00', а в параметре передаётся '05.05.2023' (т.е. '05.05.2023 00:00:00'), то запись не попадёт в выборку.

Решение: передавайте в запрос НачалоДня() и КонецДня().

Как узнать количество дней между двумя датами?

Используйте функцию ДнейМежду():

КоличествоДней = ДнейМежду(Дата1, Дата2);

Если нужно учитывать только рабочие дни:

КоличествоДней = РабочиеДниМежду(Дата1, Дата2, Календари.ПроизводственныйКалендарь());
Можно ли сравнивать даты из разных информационных баз?

Да, но учитывайте:

  1. Временные зоны баз могут отличаться.
  2. Формат хранения дат (с миллисекундами или без) может влиять на сравнение.
  3. В распределённых базах используйте УниверсальнаяДатаВремя() для корректного обмена.
Как сравнить дату с датой в формате ISO (YYYY-MM-DD)?

Преобразуйте строку в дату с помощью Дата() или ПарситьДата() (в новых версиях):

ДатаИзISO = Дата(Год, Месяц, День, 0, 0, 0); // Год, Месяц, День — числа, извлечённые из строки

Или для строки формата "2023-05-15":

ДатаИзISO = Дата(Число(Лев(СтрокаДата, 4)), Число(Сред(СтрокаДата, 6, 2)), Число(Сред(СтрокаДата, 9, 2)));