Почему не работает условие при сравнении дат в 1С и как правильно проверять праздники?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

Начинающие разработчики часто сталкиваются с ситуацией, когда логические блоки Если... ИначеЕсли ведут себя не так, как ожидалось, особенно при работе с датами. В этой статье мы подробно разберем, почему возникают такие ошибки, как работает тип данных Дата в 1С и как правильно реализовать проверку праздничных дат при начале работы системы.

Разбор типичных ошибок в исходном коде

Рассмотрим исходную ситуацию. У нас есть код, который должен выводить поздравление с праздником. Однако второе условие ИначеЕсли никогда не выполняется. Проанализируем причины:

  1. Проблема времени в датах. В 1С тип Дата всегда содержит и дату, и время. Если вы вызываете ТекущаяДата(), вы получаете, например, 07.10.2022 14:30:15. Если вы сравниваете ее с датой, созданной через Дата(2022, 10, 7) (где время по умолчанию 00:00:00), условие будет ложным, так как секунды не совпадут.
  2. Логическая невозможность условия. Во втором блоке кода используется проверка: ТекущаяДата = Дата(ТекущаяДата()) + 86400. Это выражение пытается доказать, что текущий момент времени равен самому себе плюс одни сутки (86400 секунд). Такое условие всегда будет ложным (Ложь), так как X не может быть равен X + 1.
  3. Порядок выполнения условий. В конструкции Если... ИначеЕсли... КонецЕсли система проверяет условия по порядку. Как только найдено первое истинное условие, остальные блоки полностью игнорируются. Если первое условие Если ТекущаяДата = Сегодня сработает, то блок «Завтра» даже не будет рассматриваться.
  4. Инициализация переменных. Переменная ДатаПраздника во втором условии используется для сравнения, но ее значение задается только внутри первого блока Если. Если первый блок не выполнился, переменная будет иметь значение Неопределено или пустую дату, что приведет к ошибке логики.

Решение №1: Использование функции НачалоДня()

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


Процедура ПриНачалеРаботыСистемы() 
    
    ТекущийМомент = ТекущаяДата();
    Сегодня = НачалоДня(ТекущийМомент);
    
    // Праздники
    Праздник1 = Дата(2022, 10, 7);
    Праздник2 = Дата(2022, 10, 8);
    
    НазваниеПраздника = "";
    
    Если Сегодня = Праздник1 Тогда
        НазваниеПраздника = "Международный день 1";
    ИначеЕсли Сегодня = Праздник2 Тогда
        НазваниеПраздника = "Международный день 2";
    КонецЕсли;
    
    Если ЗначениеЗаполнено(НазваниеПраздника) Тогда
        ТекстПредупреждения = СтрШаблон("Поздравляю, сегодня %1", НазваниеПраздника); 
        Сообщить(ТекстПредупреждения);
    КонецЕсли;
    
КонецПроцедуры

В этом примере мы привели текущее время к НачалоДня, что позволило нам выполнять точное сравнение с календарными датами праздников.

Решение №2: Масштабируемый подход с использованием Таблицы Значений

Если праздников много, писать бесконечные ИначеЕсли — плохая практика. Проанализируем более профессиональный подход: использование коллекции данных. Мы можем создать таблицу, где будут храниться даты и названия праздников, а затем просто перебирать её в цикле.


// Создаем таблицу праздников
Праздники = Новый ТаблицаЗначений;
Праздники.Колонки.Добавить("Дата", Новый ОписаниеТипов("Дата"));
Праздники.Колонки.Добавить("Наименование", Новый ОписаниеТипов("Строка"));

// Заполняем данными
НовыйПраздник = Праздники.Добавить();
НовыйПраздник.Дата = Дата(2022, 10, 7);
НовыйПраздник.Наименование = "Международный день 1";

НовыйПраздник = Праздники.Добавить();
НовыйПраздник.Дата = Дата(2022, 10, 8);
НовыйПраздник.Наименование = "Международный день 2";

// Проверяем текущую дату
Сегодня = НачалоДня(ТекущаяДата());

Для Каждого СтрокаПраздника Из Праздники Цикл
    Если НачалоДня(СтрокаПраздника.Дата) = Сегодня Тогда
        Сообщить("Поздравляю! Сегодня " + СтрокаПраздника.Наименование);
    КонецЕсли;
КонецЦикла;

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

Важные технические нюансы работы с датами

При разработке подобных механизмов стоит учитывать несколько профессиональных стандартов платформы 1С:

1. Часовые пояса. Функция ТекущаяДата() возвращает время сервера. В клиент-серверном варианте сервер может находиться в Москве, а пользователь в Хабаровске. Чтобы поздравление приходило вовремя именно пользователю, рекомендуется использовать ТекущаяДатаСеанса().

2. Форматирование строк. В исходном коде использовался СтрШаблон. Помните, что при выводе даты пользователю лучше использовать функцию Формат(), чтобы дата выглядела красиво, например, «7 октября 2022 года», а не «07.10.2022 0:00:00».

3. Использование Производственных календарей. В типовых конфигурациях (БП, ЗУП, УТ) уже есть встроенные справочники праздников — «Производственные календари». Вместо того чтобы прописывать даты в коде (хардкод), лучше делать запрос к регистру сведений ДанныеПроизводственногоКалендаря. Это позволит программе автоматически узнавать о праздниках и переносах выходных без изменения кода.

Выясним причину: почему ИначеЕсли может быть опасным?

Рассмотрим ситуацию, когда условия перекрывают друг друга. Проанализируем логику:


Если Число > 5 Тогда
    Сообщить("Больше 5");
ИначеЕсли Число > 10 Тогда
    Сообщить("Больше 10");
КонецЕсли;

Если Число равно 15, программа выведет только «Больше 5», так как это условие стоит первым и оно истинно. До проверки «Больше 10» дело просто не дойдет. В случае с праздниками, если вы проверяете «Сегодня праздник» и «Завтра праздник», всегда используйте отдельные блоки Если... КонецЕсли для каждого случая, если хотите, чтобы система могла вывести оба сообщения одновременно.

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

← На главную