В процессе разработки часто возникает задача преобразования числовых данных в человекочитаемый вид. Одной из классических задач является конвертация числа от 1 до 7 в соответствующий день недели (Понедельник — Воскресенье). Несмотря на кажущуюся простоту, реализовать это можно разными способами: от простого перебора условий до изящных математических формул и настроек интерфейса. В данной статье мы подробно разберем, как правильно реализовать этот функционал, и решим проблему передачи данных между клиентом и сервером.
Разберем ситуацию, с которой столкнулся автор темы. Попытка создать Соответствие в процедуре ПриИзменении на клиенте и последующее желание использовать его на сервере — это типичная ошибка понимания области видимости переменных. Переменная, созданная внутри одной процедуры, «умирает» сразу после завершения выполнения этой процедуры. Чтобы данные были доступны в другом месте, они должны быть либо реквизитом формы, либо передаваться как параметры.
Однако в нашей задаче передавать целое Соответствие на сервер избыточно. На сервер достаточно передать только само число (значение реквизита), а логику определения названия дня выполнить уже там. Или, что еще лучше, использовать механизмы платформы, которые вообще избавляют от необходимости писать сложные обработчики.
Это самый очевидный и понятный для начинающего разработчика способ. Мы просто проверяем значение реквизита и выводим нужную строку. Проанализируем пример кода, который можно разместить в обработчике нажатия кнопки:
&НаКлиенте
Процедура КнопкаНажатие(Команда)
Если Объект.ЧисловойРеквизит = 1 Тогда
Сообщить("Понедельник");
ИначеЕсли Объект.ЧисловойРеквизит = 2 Тогда
Сообщить("Вторник");
ИначеЕсли Объект.ЧисловойРеквизит = 3 Тогда
Сообщить("Среда");
ИначеЕсли Объект.ЧисловойРеквизит = 4 Тогда
Сообщить("Четверг");
ИначеЕсли Объект.ЧисловойРеквизит = 5 Тогда
Сообщить("Пятница");
ИначеЕсли Объект.ЧисловойРеквизит = 6 Тогда
Сообщить("Суббота");
ИначеЕсли Объект.ЧисловойРеквизит = 7 Тогда
Сообщить("Воскресенье");
КонецЕсли;
КонецПроцедуры
Плюсы: Максимальная наглядность. Минусы: Код получается громоздким («простыня»), его трудно поддерживать и локализовать (если потребуется перевод на другой язык).
Рассмотрим более элегантный способ, основанный на особенностях работы с датами в 1С. В системе дата 01.01.0001 является понедельником. Мы можем прибавить к этой базовой дате нужное количество секунд и получить дату, соответствующую искомому дню недели, а затем извлечь название дня с помощью функции Формат().
Разберем формулу подробнее. В одном дне 86 400 секунд (24 * 60 * 60). Если наш реквизит содержит 1 (Понедельник), то прибавив 0 секунд к дате 01.01.0001, мы получим ту же дату. Если 2 (Вторник) — прибавим 86 400 секунд.
&НаСервереБезКонтекста
Функция ПолучитьНазваниеДня(НомерДня)
// Базовая дата (01.01.0001) — это Понедельник
БазоваяДата = '00010101';
НужнаяДата = БазоваяДата + (НомерДня - 1) * 86400;
Возврат Формат(НужнаяДата, "ДФ=дддд");
КонецФункции
&НаКлиенте
Процедура КнопкаНажатие(Команда)
НазваниеДня = ПолучитьНазваниеДня(Объект.ЧисловойРеквизит);
Сообщить(НазваниеДня);
КонецПроцедуры
Важное уточнение: Для обеспечения корректной работы в многоязычных средах, рекомендуется явно указывать локаль в функции форматирования: Формат(Дата, "ДФ=дддд", "L=ru_RU"). Это гарантирует, что система вернет "Понедельник", даже если у пользователя установлена английская Windows.
Зачастую лучшим решением является не обработка введенного числа, а ограничение выбора пользователя. Мы можем настроить поле ввода так, чтобы пользователь выбирал название дня из списка, а в базу сохранялось соответствующее число. Проанализируем, как это сделать:
В этом случае код для вывода сообщения будет максимально коротким, так как нам нужно просто получить представление выбранного элемента:
&НаКлиенте
Процедура КнопкаНажатие(Команда)
// Если список заполнен в свойствах элемента формы
ЭлементСписка = Элементы.ЧисловойРеквизит.СписокВыбора.НайтиПоЗначению(Объект.ЧисловойРеквизит);
Если ЭлементСписка <> Неопределено Тогда
Сообщить(ЭлементСписка.Представление);
КонецЕсли;
КонецПроцедуры
Если нам все же нужно программное преобразование, выясним, как сделать это эффективно без использования Если. Мы можем инициализировать массив названий один раз при создании формы и обращаться к нему по индексу. Это работает быстрее, чем вызов функции Формат().
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
// Создаем массив названий дней в реквизите формы (тип: Произвольный)
// Важно: в массиве индексы начинаются с 0
ДниНеделиМассив = СтрРазделить("Понедельник,Вторник,Среда,Четверг,Пятница,Суббота,Воскресенье", ",");
КонецПроцедуры
&НаКлиенте
Процедура КнопкаНажатие(Команда)
Если Объект.ЧисловойРеквизит >= 1 И Объект.ЧисловойРеквизит <= 7 Тогда
// Обращаемся по индексу (число - 1)
Сообщить(ДниНеделиМассив[Объект.ЧисловойРеквизит - 1]);
КонецЕсли;
КонецПроцедуры
Вместо того чтобы заставлять пользователя нажимать на кнопку для получения сообщения, проанализируем ситуацию с динамическим обновлением. Мы можем выводить название дня сразу после ввода числа. Для этого:
НадписьДеньНедели).ПриИзменении числового реквизита пропишите код обновления этой надписи.
&НаКлиенте
Процедура ЧисловойРеквизитПриИзменении(Элемент)
Попытка
Название = ПолучитьНазваниеДня(Объект.ЧисловойРеквизит); // Используем функцию из Решения 2
Элементы.НадписьДеньНедели.Заголовок = Название;
Исключение
Элементы.НадписьДеньНедели.Заголовок = "Неверный ввод";
КонецПопытки;
КонецПроцедуры
Мы рассмотрели несколько подходов к решению задачи. Для простых разовых проверок отлично подходит математический метод с Формат(). Если же ваша цель — удобство пользователя при вводе данных, то лучше всего использовать СписокВыбора на форме. Помните о правилах передачи данных: не пытайтесь передавать сложные структуры типа Соответствие между клиентом и сервером без необходимости, используйте реквизиты формы или передавайте простые типы данных (числа, строки) в качестве параметров функций.