Как исправить ошибку «Преобразование к значению типу Дата не может быть выполнено» в веб-клиенте 1С

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

Разработка интерфейсов в управляемом приложении 1С требует от программиста понимания того, как программный код исполняется в различных клиентских средах. Нередки ситуации, когда функционал, идеально работающий в классическом тонком клиенте, внезапно начинает выдавать критические ошибки при запуске через веб-клиент (в браузере). С одной из таких проблем часто сталкиваются при обработке дат, вводимых пользователями на форме отчета или обработки. Ошибка «Преобразование к значению типу Дата не может быть выполнено» способна парализовать работу пользователей в веб-интерфейсе.

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

Анализ исходной проблемы и разбор некорректного кода

Рассмотрим классическую ситуацию. Разработчик создал форму отчета с полями выбора периода: ДатаНач (Дата начала) и ДатаКон (Дата окончания). Для обработки изменения этих полей на клиенте был написан следующий обработчик события:


&НаКлиенте
Процедура ДатаНачПриИзменении(Элемент)
    ДатаП = РазобратьДату(Элемент.ВыделенныйТекст); 
КонецПроцедуры

Сама функция разбора строкового представления даты выглядела так:


Функция РазобратьДату(ДатаСтрока)
    Возврат Дата(Сред(ДатаСтрока, 7, 4) + Сред(ДатаСтрока, 4, 2) + Сред(ДатаСтрока, 0, 2));
КонецФункции

При тестировании в тонком клиенте этот код работал безотказно. Но при первом же запуске в веб-клиенте (например, через Google Chrome или Яндекс.Браузер) при изменении даты система выдавала ошибку преобразования типов. Проанализируем, в чем кроются критические уязвимости данного алгоритма.

Во-первых, обратите внимание на конструкцию Сред(ДатаСтрока, 0, 2). В платформе 1С нумерация символов в строках всегда начинается с 1. Использование индекса 0 является грубой методологической ошибкой. Тонкий клиент прощал эту неточность благодаря встроенному механизму защиты: при получении индекса меньше единицы платформа автоматически приравнивает его к 1, из-за чего функция возвращала корректный день даты. Тем не менее писать такой код крайне не рекомендуется.

Во-вторых (и это главное), ошибка преобразования типов возникала из-за использования свойства ВыделенныйТекст элемента формы.

Почему ВыделенныйТекст возвращает пустоту в Веб-клиенте?

Выясним причину разного поведения свойства ВыделенныйТекст (SelectedText) в различных средах выполнения:

  1. В Тонком клиенте: Приложение работает напрямую под управлением операционной системы (Windows/Linux). Механизмы отрисовки окон и фокуса ввода приводят к тому, что при закрытии интерактивного календаря или завершении редактирования поля весь текст в поле ввода на короткое мгновение выделяется программно. В результате свойство Элемент.ВыделенныйТекст возвращало полную строковую запись даты (например, "25.10.2023").
  2. В Веб-клиенте: Приложение работает внутри веб-браузера под управлением движка JavaScript. При выборе даты из календаря или потере фокуса ввода браузер мгновенно снимает выделение (selection) с текстового поля. Соответственно, в момент вызова обработчика ПриИзменении свойство ВыделенныйТекст возвращает пустую строку "".

Поскольку в функцию РазобратьДату передавалась пустая строка, результатом склеивания подстрок также становилась пустая строка. Попытка выполнить конструкцию Дата("") закономерно приводила к аварийному завершению работы интерфейса.

Опасности использования свойства ТекстРедактирования

Многие разработчики пытаются решить проблему «в лоб», заменяя свойство ВыделенныйТекст на ТекстРедактирования:

ДатаП = РазобратьДату(Элемент.ТекстРедактирования);

На первый взгляд, это решает проблему: код начинает работать и в веб-клиенте. Однако данный подход является опасным антипаттерном, который может привести к непредсказуемым ошибкам в будущем.

Дело в том, что свойство ТекстРедактирования возвращает строковое представление даты в том формате, который задан локальными региональными настройками операционной системы или браузера конкретного пользователя. Если у одного пользователя установлена русская локаль (формат ДД.ММ.ГГГГ, например, "25.10.2023"), то у другого пользователя с англоязычной локалью формат даты в поле ввода автоматически изменится на MM/DD/YYYY (например, "10/25/2023").

Жёстко закодированная нарезка строки функциями Сред(ДатаСтрока, 7, 4) на компьютере с другой локализацией приведет либо к мгновенному падению программы, либо (что гораздо опаснее!) к незаметной записи искаженных данных, когда дни и месяцы перепутаются местами в базе данных.

Правильное решение №1: Использование связанного реквизита формы

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

К моменту срабатывания события ПриИзменении платформа уже выполнила валидацию введенного пользователем текста, преобразовала его в полноценный тип Дата и записала значение в реквизит формы, с которым связано данное поле ввода.

Если ваше поле ввода на форме связано с реквизитом ДатаНач, вам достаточно просто обратиться напрямую к этому реквизиту:


&НаКлиенте
Процедура ДатаНачПриИзменении(Элемент)
    
    // Платформа уже сама все преобразовала!
    Если ЗначениеЗаполнено(ДатаНач) Тогда
        // Выполняем логику работы с датой
        ТекущийГод = Год(ДатаНач);
    КонецЕсли;
    
КонецПроцедуры

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

Правильное решение №2: Использование объекта ОписаниеТипов

Бывают редкие сценарии, когда поле ввода на форме является произвольным текстовым полем (не связанным с типом Дата), и нам действительно необходимо преобразовать введенную пользователем строку в дату. Чтобы сделать это безопасно и не зависеть от региональных настроек конкретного компьютера или веб-браузера, следует использовать объект ОписаниеТипов.

Рассмотрим пример безопасного преобразования строки в дату:


&НаКлиенте
Функция ПреобразоватьСтрокуВДатуБезопасно(ЗначениеСтрокой)
    
    ОписаниеДаты = Новый ОписаниеТипов("Дата");
    ВозвращаемоеЗначение = ОписаниеДаты.ПривестиЗначение(ЗначениеСтрокой);
    
    Возврат ВозвращаемоеЗначение;
    
КонецФункции

Метод ПривестиЗначение() объекта ОписаниеТипов самостоятельно анализирует переданную строку, определяет используемые разделители и порядок следования дня, месяца и года в соответствии с текущим сеансом пользователя. Если преобразование невозможно, метод вернет пустую дату ('00010101000000'), не вызывая аварийного завершения работы программы. Это позволяет избежать написания громоздких и нестабильных функций разбора строк.

Резюме и правила хорошего тона при работе с датами

Подводя итог нашему разбору, сформулируем основные правила, которые уберегут вас от ошибок при разработке под веб-клиент:

Соблюдение этих простых принципов гарантирует стабильную и быструю работу ваших интерфейсов как в тонком клиенте, так и во всех популярных веб-браузерах.

← На главную