При разработке отчетов на платформе 1С:Предприятие 8 программисты часто сталкиваются с задачей красивого вывода дат, объединенных с произвольным текстом. Например, нам нужно вывести в одной колонке фразу вида «Родилась в январе 2018». На первый взгляд задача кажется тривиальной, но при попытке реализовать ее напрямую в запросе мы сталкиваемся с жесткими ограничениями платформы.
В этой статье мы подробно разберем, почему стандартные запросы 1С не позволяют складывать строки с датами, и рассмотрим несколько изящных и грамматически корректных способов решения этой задачи с использованием механизмов Системы компоновки данных (СКД) и встроенного языка 1С.
Посмотрим на ситуацию изнутри. В классическом SQL или других языках программирования мы можем легко привести дату к строковому типу и сложить ее с другой строкой. Однако в языке запросов 1С действуют строгие правила типизации:
+. Попытка написать выражение вроде "Год: " + Год(Период) приведет к синтаксической ошибке несовместимости типов.Формат(), которая могла бы преобразовать дату в строку нужного вида на уровне СУБД.Именно поэтому для решения нашей задачи мы должны перенести логику форматирования и объединения данных из самого запроса в механизмы компоновки (СКД) или обрабатывать данные уже при выводе.
Рассмотрим подробнее самые эффективные методы реализации этой задачи.
Если наш отчет строится на базе СКД, то самым правильным решением будет использование вкладки «Вычисляемые поля». На этом этапе компоновки данных нам становится доступен полноценный процессор выражений СКД, который умеет работать с функциями форматирования и без проблем складывает строковые типы данных.
Разберем по шагам, как настроить такое поле:
ПредставлениеПериодаРождения.
ВЫБОР
КОГДА Месяц(Период) = 1 ТОГДА "Родилась в январе"
КОГДА Месяц(Период) = 2 ТОГДА "Родилась в феврале"
КОГДА Месяц(Период) = 3 ТОГДА "Родилась в марте"
КОГДА Месяц(Период) = 4 ТОГДА "Родилась в апреле"
КОГДА Месяц(Период) = 5 ТОГДА "Родилась в мае"
КОГДА Месяц(Период) = 6 ТОГДА "Родилась в июне"
КОГДА Месяц(Период) = 7 ТОГДА "Родилась в июле"
КОГДА Месяц(Период) = 8 ТОГДА "Родилась в августе"
КОГДА Месяц(Период) = 9 ТОГДА "Родилась в сентябре"
КОГДА Месяц(Период) = 10 ТОГДА "Родилась в октябре"
КОГДА Месяц(Период) = 11 ТОГДА "Родилась в ноябре"
КОГДА Месяц(Период) = 12 ТОГДА "Родилась в декабре"
КОНЕЦ + " " + Формат(Период, "ДФ=yyyy")
Важная деталь: конструкция Формат(Период, "ДФ=yyyy") преобразует год из даты в строковое представление (например, "2018"), что позволяет избежать ошибки несовместимости типов при сложении строк. Оператор + в данном контексте отработает корректно, и мы получим именно тот результат, который требовался автору темы.
Иногда разработчики пытаются решить задачу "в лоб" через свойства оформления поля в СКД, задавая строку формата даты. Например, можно установить для поля формат:
ДФ='''Родилась'' dd MMMM yyyy ''г.'''
Этот способ отлично сработает, если нам нужно вывести полную дату с днями: система выдаст красивое значение, например, «Родилась 12 января 2018 г.».
Однако, если по условию задачи нам требуется скрыть день и вывести фразу именно в формате «Родилась в [месяце] [года]», стандартное форматирование платформы столкнется с грамматической проблемой:
ДФ='''Родилась в'' MMMM yyyy' выведет месяц исключительно в именительном падеже: «Родилась в Январь 2018». Это выглядит крайне неграмотно и непрофессионально.Именно поэтому первоначальная задумка с использованием конструкции ВЫБОР КОГДА для ручного переопределения месяцев (описанная в Способе 1) является единственно верным решением для соблюдения правил русского языка.
Проанализируем еще одну важную проблему. В исходном коде автора жестко прописано слово «Родилась». Но что делать, если в вашей базе данных среди физических лиц присутствуют и мальчики? Выводить фразу «Родилась в январе 2018» для мальчика — грубая ошибка.
Мы можем изящно решить эту задачу вообще без написания громоздкого кода, используя механизм Условного оформления в СКД:
ДатаРождения) и поле Пол.Пол Равно Значение(Перечисление.ПолФизическогоЛица.Женский).ДФ='''Родилась'' d MMMM yyyy ''г.''' (на выходе получим: *Родилась 15 января 2018 г.*).Пол Равно Значение(Перечисление.ПолФизическогоЛица.Мужской).ДФ='''Родился'' d MMMM yyyy ''г.''' (на выходе получим: *Родился 15 января 2018 г.*).Этот подход разделяет логику хранения данных и их визуального представления, что полностью соответствует стандартам разработки фирмы "1С".
Если строгая формулировка «Родилась в...» для вашего отчета не является критичной, а вам нужно просто вывести период в красивом формате (например, «Январь 2018 г.»), мы можем использовать мощную встроенную функцию ПредставлениеПериода().
Для того чтобы функция вернула название месяца и год, ей необходимо передать начало и окончание этого месяца. В вычисляемом поле СКД выражение будет выглядеть следующим образом:
"Родилась в " + НРег(ПредставлениеПериода(НачалоПериода(Период, "Месяц"), КонецПериода(Period, "Месяц")))
Разберем, как это работает: функция ПредставлениеПериода() сформирует строковое представление вида "Январь 2018 г.", а системная функция НРег() переведет первую букву месяца в строчную (нижний регистр). В итоге мы получим строку: «Родилась в январь 2018 г.». Несмотря на то, что падеж месяца останется именительным, этот способ требует гораздо меньше кода и пишется в одну строку.
Если вы формируете отчет или печатную форму не через СКД, а программно во встроенном языке 1С (например, в модуле менеджера документа или обработки), то по современным стандартам разработки и требованиям локализации БСП (Библиотеки Стандартных Подсистем) крайне не рекомендуется складывать строки через оператор +.
Вместо ручной конкатенации следует использовать функцию СтрШаблон(). Это делает код более читаемым и упрощает его дальнейшую поддержку:
ТекстПредупреждения = СтрШаблон(
НСтр("ru = '%1 в %2 %3 г.'"),
?(Выборка.Пол = Перечисления.ПолФизическогоЛица.Женский, "Родилась", "Родился"),
ПолучитьМесяцВПредложномПадеже(Выборка.Период),
Формат(Выборка.Период, "ДФ=yyyy")
);
В данном примере функция ПолучитьМесяцВПредложномПадеже() — это ваша внутренняя функция (или массив), которая возвращает название месяца на основе его номера, обеспечивая безупречную грамматику интерфейса программы.