Как в 1С получить нужную дату с годом из другой даты и ограничить период

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

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

Анализ типовой ошибки при преобразовании числа в дату через строку

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


МояДата = '2016-08-20';
Год = Год(МояДата);
ДатаСтрока = Строка(Год) + "0331";
Дата = КонецДня(Дата(ДатаСтрока));

При выполнении этого кода платформа выдает ошибку преобразования к типу Дата. Выясним причину такого поведения: функция Строка() для числовых значений по умолчанию применяет системные настройки форматирования с разделением групп разрядов. Число 2016 превращается в строку "2 016" с неразрывным пробелом. В результате строка "2 0160331" не может быть распознана конструктором дат 1С.

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


ДатаСтрока = Формат(Год, "ЧГ=0") + "0331";
Дата = Дата(ДатаСтрока);

Однако использование строковых операций для работы с датами считается неоптимальной практикой. В 1С есть более надежные и лаконичные механизмы.

Вариант 1. Использование конструктора даты с параметрами

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

Разберем пример:


Если Месяц(ДатаОкончания) > 3 Тогда
    ДатаОкончания = КонецДня(Дата(Год(ДатаОкончания), 3, 31));
КонецЕсли;

Обратите внимание на время: вызов Дата(Год, 3, 31) вернет дату со временем 00:00:00. Если эта дата используется как граница периода для отчетов, виртуальных таблиц или запросов к регистрам, документы за 31 марта не попадут в выборку. Поэтому обязательно используйте функцию КонецДня() либо передавайте время напрямую в конструктор:

ДатаОкончания = Дата(Год(ДатаОкончания), 3, 31, 23, 59, 59);

Вариант 2. Комбинация функций КонецМесяца и Дата

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


Если Месяц(МояДата) > 3 Тогда
    МояДата = КонецМесяца(Дата(Год(МояДата), 3, 1));
КонецЕсли;

Функция КонецМесяца() автоматически установит дату на последний день месяца и выставит время на 23:59:59.

Вариант 3. Изящное решение в одну строку через функции периодов

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

ДатаОкончания = Мин(ДатаОкончания, КонецКвартала(НачалоГода(ДатаОкончания)));

Рассмотрим, как работает эта конструкция по шагам:

  1. Функция НачалоГода(ДатаОкончания) возвращает 01.01.ГГГГ 00:00:00.
  2. Функция КонецКвартала() берет начало года (первый квартал) и возвращает 31.03.ГГГГ 23:59:59.
  3. Функция Мин() выбирает наименьшую из двух дат: если исходная дата была раньше конца марта, она останется без изменений; если позже — будет установлено 31 марта 23:59:59.

Ограничение даты в запросах 1С

Если аналогичную логику требуется реализовать внутри текста запроса к базе данных, используем условную конструкцию ВЫБОР и встроенные функции работы с датами языка запросов:


ВЫБОР
    КОГДА МЕСЯЦ(Таблица.ДатаОкончания) > 3 
        ТОГДА КОНЕЦПЕРИОДА(НАЧАЛОПЕРИОДА(Таблица.ДатаОкончания, ГОД), КВАРТАЛ)
    ИНАЧЕ Таблица.ДатаОкончания
КОНЕЦ

Совет по обработке пустых значений: перед выполнением любых преобразований проверяйте дату на заполненность с помощью ЗначениеЗаполнено(ДатаОкончания). Для пустой даты '0001-01-01' вызов функции Год() вернет 1, что может привести к неожиданным результатам в дальнейших расчетах.

← На главную