При разработке прикладных решений часто возникает задача хранения интервалов времени, которые пользователи привыкли видеть в удобном для них формате: "5 дней", "2 недели" или "3 месяца". Сложность заключается в том, что с точки зрения базы данных удобнее хранить число, а с точки зрения бизнес-логики и интерфейса — структуру из величины и единицы измерения. Рассмотрим подробно, как правильно реализовать такой механизм в 1С, сохранив баланс между удобством пользователя и гибкостью кода.
Разберем самый надежный и распространенный в типовых конфигурациях (таких как 1С:ERP или 1С:ЗУП) способ. Мы создаем два отдельных реквизита в объекте (документе или справочнике):
СрокЗначение (Тип: Число) — хранит количественную составляющую.СрокЕдиницаИзмерения (Тип: ПеречислениеСсылка.Периодичность) — хранит тип периода (День, Неделя, Месяц, Год).Почему это важно? Проанализируем ситуацию с календарной точностью. Месяц — это переменная величина (в нем может быть от 28 до 31 дня). Если мы будем хранить всё просто в днях, то при расчете даты окончания срока от 1 февраля мы получим результат, отличный от расчета в месяцах. Используя два реквизита, мы можем применять встроенную функцию 1С для точных расчетов:
КонечнаяДата = ДобавитьМесяц(НачальнаяДата, СрокЗначение); // Если выбраны месяцы
// или
КонечнаяДата = НачальнаяДата + (СрокЗначение * 24 * 60 * 60); // Если выбраны дни
Для вывода на форму в этом случае можно использовать одну колонку, программно формируя представление в событии ПриВыводеДанных или через вычисляемое поле. Проанализируем пример формирования строки:
Функция ПолучитьПредставлениеСрока(Значение, Единица) Экспорт
Возврат Строка(Значение) + " " + НСтр("ru = '" + Строка(Единица) + "'");
КонецФункции
Рассмотрим альтернативный вариант, предложенный в обсуждении: хранение срока в одной колонке в минимально возможных единицах (например, в днях или часах). Этот метод удобен для сортировки и быстрой математической обработки данных в запросах.
Алгоритм реализации:
СрокВХранилище (тип Число).Рассмотрим пример алгоритма, который разбивает общее количество дней на "человекочитаемые" периоды:
Процедура РассчитатьПериодыНаФорме(ОбщееКолВоДней)
Лет = Цел(ОбщееКолВоДней / 365);
ОстатокДней = ОбщееКолВоДней % 365;
Месяцев = Цел(ОстатокДней / 30);
Дней = ОстатокДней % 30;
Сообщить("Срок хранения: " + Лет + " л., " + Месяцев + " мес., " + Дней + " дн.");
КонецПроцедуры
Важный нюанс: Данный метод имеет высокую погрешность при работе с месяцами и годами, поэтому его лучше использовать только в тех случаях, когда срок носит справочный характер и не влияет на финансовые взаиморасчеты.
Если нам не хочется загромождать форму двумя колонками, мы можем применить интерфейсные хитрости. Выясним, как сделать ввод данных максимально лаконичным.
Создадим на форме строковый реквизит (или числовой с кнопкой выбора). Рассмотрим пошагово настройку такого поля:
ПриИзменении), программно добавляйте к заголовку или в само поле текстовую метку.Пример кода для обработки ввода, где пользователь может написать просто число, а единица выберется по умолчанию:
&НаКлиенте
Процедура СрокПриИзменении(Элемент)
Если Объект.СрокЕдиница = ПредопределенноеЗначение("Перечисление.Периодичность.ПустаяСсылка") Тогда
Объект.СрокЕдиница = ПредопределенноеЗначение("Перечисление.Периодичность.День");
КонецЕсли;
ОбновитьПредставлениеСрока();
КонецПроцедуры
В современных конфигурациях часто используется подсистема "Контактная информация" или "Работа с почтовыми сообщениями", где уже реализованы механизмы выбора интервалов. Проанализируем, как можно заимствовать этот опыт.
Вместо произвольного ввода можно использовать СписокВыбора. В "Значении" элемента списка мы храним количество секунд или дней (для программной логики), а в "Представлении" — понятный текст ("1 неделя", "2 недели" и т.д.). Это исключает ошибки ввода и упрощает интерфейс.
Если задача стоит в отображении данных в списке документов, а хранятся они в двух реквизитах, лучше всего использовать возможности Произвольного запроса в динамическом списке. Посмотрим, как составить такой запрос:
ВЫБРАТЬ
Док.Ссылка,
ВЫБОР
КОГДА Док.СрокЕдиница = ЗНАЧЕНИЕ(Перечисление.Периодичность.День)
ТОГДА ПРЕДСТАВЛЕНИЕ(Док.СрокЗначение) + " дн."
КОГДА Док.СрокЕдиница = ЗНАЧЕНИЕ(Перечисление.Периодичность.Неделя)
ТОГДА ПРЕДСТАВЛЕНИЕ(Док.СрокЗначение) + " нед."
ИНАЧЕ ПРЕДСТАВЛЕНИЕ(Док.СрокЗначение) + " мес."
КОНЕЦ КАК СрокПредставление
ИЗ
Документ.ВашДокумент КАК Док
Преимущества этого подхода:
Проанализировав все варианты, мы рекомендуем следующее: всегда храните данные в двух реквизитах (число и тип периода), если планируете использовать их в расчетах дат или отчетах. Для визуального удобства используйте программное объединение этих данных в одну строку на форме или вычисляемые поля в списках. Это обеспечит и гибкость разработки, и удобство эксплуатации системы.