В разработке на платформе 1С часто возникает задача, когда необходимо обеспечить ввод даты в строго определенном формате, например, дд.ММ.гггг. Стандартный подход — использовать поле с типом данных Дата, где все механизмы форматирования и выбора уже встроены. Однако бывают ситуации, когда по требованиям задачи (например, для интеграции с другой системой или для хранения специфических данных) необходимо использовать именно строковое поле. В этом случае стандартные свойства поля формы, такие как Формат или Маска, не дают нужного результата. Разберемся, как решить эту проблему с помощью программной обработки событий формы.
Проанализируем ситуацию: у нас есть реквизит формы или объекта с типом Строка. Мы хотим, чтобы пользователь вводил в него дату, и, независимо от того, как он ее ввел (например, "5.1.23" или "05,01,2023"), система автоматически приводила ее к единому формату "05.01.2023".
Самый надежный и управляемый способ решения этой задачи — использовать событие ПриИзменении для поля ввода на управляемой форме. Логика этого подхода проста: мы позволяем пользователю ввести любое значение, а сразу после того, как он закончит редактирование и поле потеряет фокус, мы перехватываем это событие, анализируем введенный текст и, если это возможно, преобразуем его в дату и форматируем обратно в строку в нужном нам виде.
Рассмотрим по шагам, как это реализовать.
ПриИзменении и нажмите на иконку с лупой, чтобы создать обработчик этого события на клиенте.Система создаст пустую процедуру-обработчик. Теперь наша задача — наполнить ее кодом, который будет выполнять преобразование.
Начнем с простого варианта, который предполагает, что пользователь всегда вводит корректную дату. Этот код пытается преобразовать введенную строку в дату, а затем форматирует ее обратно в строку нужного вида.
Предположим, что наше поле на форме привязано к реквизиту объекта с именем МоеПолеДатаСтрокой.
&НаКлиенте
Процедура МоеПолеДатаСтрокойПриИзменении(Элемент)
// Проверяем, что поле не пустое
Если НЕ ЗначениеЗаполнено(Объект.МоеПолеДатаСтрокой) Тогда
Возврат;
КонецЕсли;
// Пытаемся преобразовать введенный текст в дату
ПреобразованнаяДата = Дата(Объект.МоеПолеДатаСтрокой);
// Форматируем полученную дату в нужный строковый формат и записываем обратно в поле
Объект.МоеПолеДатаСтрокой = Формат(ПреобразованнаяДата, "ДФ=dd.MM.yyyy");
КонецПроцедуры
Разберем этот код:
&НаКлиенте — директива компиляции, указывающая, что код будет выполняться на стороне клиента, что необходимо для быстрой реакции на действия пользователя в интерфейсе.Процедура МоеПолеДатаСтрокойПриИзменении(Элемент) — это и есть наш обработчик события.Если НЕ ЗначениеЗаполнено(...) — простая проверка, чтобы избежать ошибок, если пользователь очистил поле.ПреобразованнаяДата = Дата(Объект.МоеПолеДатаСтрокой); — ключевая строка. Здесь мы используем конструктор типа Дата(), который пытается "понять" введенный пользователем текст и превратить его в системный тип даты. Он достаточно "умный" и распознает множество форматов, например, "1.2.23", "01/02/2023", "2 фев 23" и т.д.Объект.МоеПолеДатаСтрокой = Формат(ПреобразованнаяДата, "ДФ=dd.MM.yyyy"); — здесь мы используем функцию Формат(), чтобы из полученной на предыдущем шаге даты снова сделать строку, но уже в строго заданном формате. Параметр "ДФ=dd.MM.yyyy" (или "ДатаФормат") как раз и определяет этот вид.Этот метод хорошо работает, но у него есть существенный недостаток: если пользователь введет текст, который система не сможет распознать как дату (например, "привет" или "12.34.5678"), произойдет ошибка времени выполнения, и работа пользователя будет прервана. Чтобы сделать интерфейс более дружелюбным, нужно обрабатывать такие ситуации.
Чтобы избежать ошибок и корректно реагировать на неверный ввод, обернем наш код в конструкцию Попытка...Исключение. Этот подход является более профессиональным и предпочтительным.
&НаКлиенте
Процедура МоеПолеДатаСтрокойПриИзменении(Элемент)
// Проверяем, что поле не пустое
Если НЕ ЗначениеЗаполнено(Объект.МоеПолеДатаСтрокой) Тогда
Возврат;
КонецЕсли;
Попытка
// Пытаемся преобразовать введенный текст в дату
ПреобразованнаяДата = Дата(Объект.МоеПолеДатаСтрокой);
// Если преобразование удалось, форматируем результат
Объект.МоеПолеДатаСтрокой = Формат(ПреобразованнаяДата, "ДФ=dd.MM.yyyy");
Исключение
// Если преобразование не удалось, сообщаем пользователю об ошибке
// и очищаем поле, чтобы он мог ввести значение заново.
ОписаниеОшибки = "Введено некорректное значение даты. Пожалуйста, введите дату в формате ДД.ММ.ГГГГ.";
ПоказатьПредупреждение(, ОписаниеОшибки); // или Сообщить()
Объект.МоеПолеДатаСтрокой = ""; // Очищаем некорректный ввод
КонецПопытки;
КонецПроцедуры
Что нового в этом коде:
Попытка ... КонецПопытки; — эта конструкция позволяет выполнить код в блоке Попытка. Если во время его выполнения происходит какая-либо ошибка (в нашем случае — невозможность преобразовать строку в дату), выполнение не прерывается, а переходит в блок Исключение.Исключение — этот блок выполняется только в случае ошибки. Здесь мы выполняем два действия:
ПоказатьПредупреждение(). Это более современный и заметный способ, чем старая функция Сообщить().Объект.МоеПолеДатаСтрокой = ""), чтобы пользователь не оставил в нем некорректные данные и был вынужден исправить свой ввод.Такой подход обеспечивает плавный и понятный пользовательский опыт: система не "падает" с ошибкой, а вежливо подсказывает, что нужно исправить.
Важно понимать, почему стандартные свойства элемента формы не помогли в исходной задаче.
Mask) предназначено для посимвольного контроля ввода. Оно отлично подходит для номеров телефонов, ИНН, кодов, где каждый символ имеет определенный тип (цифра, буква). Для даты оно не подходит, так как не может проверить логическую корректность (например, 32-е число в месяце или 13-й месяц). Маска 99.99.9999 позволит ввести "99.99.9999", что не является датой.Format) для полей ввода работает только с типизированными данными, такими как Дата или Число. Оно указывает системе, как отображать уже существующее значение. Для поля с типом Строка это свойство игнорируется, потому что система не знает, как интерпретировать содержимое строки для форматирования.Именно поэтому для строковых полей, в которых мы хотим хранить данные в определенном формате, единственным надежным решением является программная обработка событий, таких как ПриИзменении.
В заключение, при работе с датами всегда старайтесь использовать реквизиты с типом Дата. Это самый правильный и надежный путь. Но если по каким-то причинам это невозможно, рассмотренный метод с обработкой события ПриИзменении и конструкцией Попытка-Исключение является лучшей практикой для обеспечения корректности и удобства ввода данных в строковые поля.