Разработка интерфейсов в управляемом приложении 1С требует от программиста понимания того, как программный код исполняется в различных клиентских средах. Нередки ситуации, когда функционал, идеально работающий в классическом тонком клиенте, внезапно начинает выдавать критические ошибки при запуске через веб-клиент (в браузере). С одной из таких проблем часто сталкиваются при обработке дат, вводимых пользователями на форме отчета или обработки. Ошибка «Преобразование к значению типу Дата не может быть выполнено» способна парализовать работу пользователей в веб-интерфейсе.
В этой статье мы подробно разберем, почему возникает данное исключение, проанализируем разницу в поведении платформ тонкого и веб-клиента, выясним, почему популярные «костыли» могут быть опасны для стабильности системы, и рассмотрим наиболее изящные и правильные способы решения этой задачи средствами платформы «1С:Предприятие 8».
Рассмотрим классическую ситуацию. Разработчик создал форму отчета с полями выбора периода: ДатаНач (Дата начала) и ДатаКон (Дата окончания). Для обработки изменения этих полей на клиенте был написан следующий обработчик события:
&НаКлиенте
Процедура ДатаНачПриИзменении(Элемент)
ДатаП = РазобратьДату(Элемент.ВыделенныйТекст);
КонецПроцедуры
Сама функция разбора строкового представления даты выглядела так:
Функция РазобратьДату(ДатаСтрока)
Возврат Дата(Сред(ДатаСтрока, 7, 4) + Сред(ДатаСтрока, 4, 2) + Сред(ДатаСтрока, 0, 2));
КонецФункции
При тестировании в тонком клиенте этот код работал безотказно. Но при первом же запуске в веб-клиенте (например, через Google Chrome или Яндекс.Браузер) при изменении даты система выдавала ошибку преобразования типов. Проанализируем, в чем кроются критические уязвимости данного алгоритма.
Во-первых, обратите внимание на конструкцию Сред(ДатаСтрока, 0, 2). В платформе 1С нумерация символов в строках всегда начинается с 1. Использование индекса 0 является грубой методологической ошибкой. Тонкий клиент прощал эту неточность благодаря встроенному механизму защиты: при получении индекса меньше единицы платформа автоматически приравнивает его к 1, из-за чего функция возвращала корректный день даты. Тем не менее писать такой код крайне не рекомендуется.
Во-вторых (и это главное), ошибка преобразования типов возникала из-за использования свойства ВыделенныйТекст элемента формы.
Выясним причину разного поведения свойства ВыделенныйТекст (SelectedText) в различных средах выполнения:
Элемент.ВыделенныйТекст возвращало полную строковую запись даты (например, "25.10.2023").ПриИзменении свойство ВыделенныйТекст возвращает пустую строку "".Поскольку в функцию РазобратьДату передавалась пустая строка, результатом склеивания подстрок также становилась пустая строка. Попытка выполнить конструкцию Дата("") закономерно приводила к аварийному завершению работы интерфейса.
Многие разработчики пытаются решить проблему «в лоб», заменяя свойство ВыделенныйТекст на ТекстРедактирования:
ДатаП = РазобратьДату(Элемент.ТекстРедактирования);
На первый взгляд, это решает проблему: код начинает работать и в веб-клиенте. Однако данный подход является опасным антипаттерном, который может привести к непредсказуемым ошибкам в будущем.
Дело в том, что свойство ТекстРедактирования возвращает строковое представление даты в том формате, который задан локальными региональными настройками операционной системы или браузера конкретного пользователя.
Если у одного пользователя установлена русская локаль (формат ДД.ММ.ГГГГ, например, "25.10.2023"), то у другого пользователя с англоязычной локалью формат даты в поле ввода автоматически изменится на MM/DD/YYYY (например, "10/25/2023").
Жёстко закодированная нарезка строки функциями Сред(ДатаСтрока, 7, 4) на компьютере с другой локализацией приведет либо к мгновенному падению программы, либо (что гораздо опаснее!) к незаметной записи искаженных данных, когда дни и месяцы перепутаются местами в базе данных.
Самым простым, надежным и естественным решением в управляемых формах 1С является прямой отказ от ручного разбора строк. Платформа спроектирована так, чтобы брать всю рутину по преобразованию типов на себя.
К моменту срабатывания события ПриИзменении платформа уже выполнила валидацию введенного пользователем текста, преобразовала его в полноценный тип Дата и записала значение в реквизит формы, с которым связано данное поле ввода.
Если ваше поле ввода на форме связано с реквизитом ДатаНач, вам достаточно просто обратиться напрямую к этому реквизиту:
&НаКлиенте
Процедура ДатаНачПриИзменении(Элемент)
// Платформа уже сама все преобразовала!
Если ЗначениеЗаполнено(ДатаНач) Тогда
// Выполняем логику работы с датой
ТекущийГод = Год(ДатаНач);
КонецЕсли;
КонецПроцедуры
Если вы опасаетесь, что в реквизите временно находится старое значение, вы можете принудительно прочитать текущее значение из элемента формы через его свойства, но делать это нужно правильно, без парсинга строк. Помните: ручной разбор строкового представления даты в 1С практически никогда не требуется при работе со стандартными элементами управления.
Бывают редкие сценарии, когда поле ввода на форме является произвольным текстовым полем (не связанным с типом Дата), и нам действительно необходимо преобразовать введенную пользователем строку в дату. Чтобы сделать это безопасно и не зависеть от региональных настроек конкретного компьютера или веб-браузера, следует использовать объект ОписаниеТипов.
Рассмотрим пример безопасного преобразования строки в дату:
&НаКлиенте
Функция ПреобразоватьСтрокуВДатуБезопасно(ЗначениеСтрокой)
ОписаниеДаты = Новый ОписаниеТипов("Дата");
ВозвращаемоеЗначение = ОписаниеДаты.ПривестиЗначение(ЗначениеСтрокой);
Возврат ВозвращаемоеЗначение;
КонецФункции
Метод ПривестиЗначение() объекта ОписаниеТипов самостоятельно анализирует переданную строку, определяет используемые разделители и порядок следования дня, месяца и года в соответствии с текущим сеансом пользователя. Если преобразование невозможно, метод вернет пустую дату ('00010101000000'), не вызывая аварийного завершения работы программы. Это позволяет избежать написания громоздких и нестабильных функций разбора строк.
Подводя итог нашему разбору, сформулируем основные правила, которые уберегут вас от ошибок при разработке под веб-клиент:
ВыделенныйТекст для получения значений, введенных пользователем. Это свойство предназначено исключительно для интерактивной работы с выделенными фрагментами текста.Сред, Лев, Прав для получения даты — это нарушает кроссплатформенность приложения и приводит к ошибкам локализации.ОписаниеТипов для гарантированно безопасного преобразования данных.Соблюдение этих простых принципов гарантирует стабильную и быструю работу ваших интерфейсов как в тонком клиенте, так и во всех популярных веб-браузерах.