Как в 1С автоматически рассчитать количество дней в месяце по выбранной дате и исправить ошибку преобразования?

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

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

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

Почему использование перечисления (Месяцы) — это тупиковый путь?

Начинающие разработчики часто пытаются решить задачу «в лоб»: создают перечисление Перечисление.Месяцы (Январь, Февраль, Март...) и пытаются прописать логику программно:


Если ВыбранныйМесяц = Перечисления.Месяцы.Январь Тогда
    ДнейВМесяце = 31;
ИначеЕсли ВыбранныйМесяц = Перечисления.Месяцы.Февраль Тогда
    // А как определить, високосный ли год? 28 или 29 дней?
КонецЕсли;

Такой подход имеет три критических недостатка:

  1. Проблема високосного года: Февраль может содержать как 28, так и 29 дней. Без привязки к конкретному году система не сможет корректно рассчитать расходы.
  2. Избыточность кода: Вам придется писать длинные конструкции ветвления Если...ИначеЕсли для каждого месяца.
  3. Сложность масштабирования: Если учет перейдет на другие периоды (кварталы, полугодия), всю логику придется переписывать заново.

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

Разбор ошибки «Преобразование значения к типу Дата не может быть выполнено»

При попытке написать код расчета разработчики иногда сталкиваются с ошибкой:

{Документ.ОперацияКоллективныхДокументов.Форма.ФормаДокумента.Форма(100)}: Преобразование значения к типу Дата не может быть выполнено ПоследняяДата = КонецМесяца(20211231);

Давайте выясним причину возникновения этой ошибки. Она кроется в двух деталях:

  1. Неверный синтаксис литерала даты: В коде значение 20211231 передано как обычное число (тип Число). Функция КонецМесяца() ожидает на вход значение типа Дата. Платформа не может автоматически преобразовать числовую последовательность в дату. Чтобы прописать конкретную дату «жестко» в коде, ее необходимо заключать в одинарные кавычки в формате 'ГГГГММДД'. Правильный синтаксис литерала: '20211231'.
  2. Использование статической даты вместо переменной: Вместо передачи реального реквизита формы (в котором пользователь выбирает дату) в функцию было передано фиксированное значение. Программа должна динамически считывать значение из реквизита.

Как настроить интерфейс для удобного выбора месяца

Если мы заменим перечисление на реквизит типа Дата, стандартный календарь будет заставлять пользователя выбирать конкретное число (например, 15-е или 20-е число). Для нашей задачи конкретный день не важен — важен сам месяц. Мы можем настроить поле ввода так, чтобы пользователь выбирал и видел только месяц и год.

Рассмотрим, как настроить свойства элемента формы:

  1. Создайте реквизит документа (или формы) с именем ДатаМесяца (тип Дата).
  2. Перетащите его на форму, чтобы создалось поле ввода.
  3. Откройте палитру свойств этого поля ввода.
  4. Найдите свойство Формат редактирования (Edit Format) и нажмите кнопку выбора (...). В конструкторе форматной строки на вкладке «Дата» выберите формат представления месяца и года. В поле «Форматная строка» появится значение: ДФ='ММММ гггг' (для англоязычной локализации — DF='MMMM yyyy').
  5. Такое же значение ДФ='ММММ гггг' установите в свойстве Формат (Format).

Теперь при нажатии на кнопку выбора у пользователя откроется календарь, где можно интерактивно выбрать только месяц и год. Физически в реквизит запишется дата начала выбранного месяца (например, 01.05.2023 00:00:00), но отображаться на форме она будет красиво: «Май 2023 г.».

Реализация расчета количества дней на встроенном языке

После того как пользователь выбрал месяц, нам нужно автоматически рассчитать количество дней и заполнить их в табличной части (например, в колонке табличной части Долги с именем ДнейВМесяце).

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

Вариант 1. Реализация в Управляемых формах (современный интерфейс)

В управляемом приложении реквизиты документа находятся внутри объекта-контекста Объект. Обработчик выполняется на клиенте, при этом базовые функции работы с датами доступны непосредственно на клиенте без вызова сервера.


&НаКлиенте
Процедура ДатаМесяцаПриИзменении(Элемент)
    
    // Проверяем, заполнена ли дата пользователем
    Если ЗначениеЗаполнено(Объект.ДатаМесяца) Тогда
        
        // Получаем дату последнего дня выбранного месяца
        ПоследняяДатаМесяца = КонецМесяца(Объект.ДатаМесяца);
        
        // Функция День() возвращает число месяца (для последнего дня это и есть количество дней в месяце)
        КоличествоДней = День(ПоследняяДатаМесяца);
        
        // Обходим строки табличной части и заполняем значение
        Для Каждого СтрокаТЧ Из Объект.Долги Цикл
            СтрокаТЧ.ДнейВМесяце = КоличествоДней;
        КонецЦикла;
        
    КонецЕсли;
    
КонецПроцедуры

Важное примечание: Проверка ЗначениеЗаполнено() строго обязательна. Если пользователь очистит поле даты, а мы попытаемся передать пустую дату в функцию КонецМесяца(), система вернет дату 31.01.0001, и в таблицу запишется число 31, что логически неверно при пустом значении периода.

Вариант 2. Реализация в Обычных формах (старый интерфейс)

Если вы работаете в старых конфигурациях (например, УПП, КА 1.1 или старых версиях УТ 10.3), обращение к реквизитам идет напрямую, без префикса Объект.


Процедура ДатаМесяцаПриИзменении(Элемент)
    
    Если ЗначениеЗаполнено(ДатаМесяца) Тогда
        
        ПоследняяДатаМесяца = КонецМесяца(ДатаМесяца);
        КоличествоДней = День(ПоследняяДатаМесяца);
        
        Для Каждого СтрокаТЧ Из Долги Цикл
            СтрокаТЧ.ДнейВМесяце = КоличествоДней;
        КонецЦикла;
        
    КонецЕсли;
    
КонецПроцедуры

Альтернативные методы получения количества дней в месяце

Рассмотрим еще два подхода, которые могут пригодиться в специфических задачах.

1. Расчет количества дней через разность дат

В 1С разность между двумя датами возвращает количество секунд. Мы можем математически вычислить количество дней, разделив разницу между началом следующего месяца и началом текущего месяца на количество секунд в сутках (86 400 секунд):


НачалоТекущего = НачалоМесяца(Объект.ДатаМесяца);
НачалоСледующего = НачалоМесяца(ДобавитьМесяц(Объект.ДатаМесяца, 1));

КоличествоДней = (НачалоСледующего - НачалоТекущего) / 86400;

Этот метод рабочий, но более громоздкий по сравнению с лаконичной связкой День(КонецМесяца()).

2. Получение количества дней в запросе

Если вам нужно рассчитать количество дней непосредственно при выборке данных из базы данных (например, в отчетах или при заполнении документов), используйте аналогичную конструкцию внутри языка запросов 1С:


ВЫБРАТЬ
    ДЕНЬ(КОНЕЦПЕРИОДА(&ПериодРегистрации, МЕСЯЦ)) КАК КоличествоДнейВМесяце

Подведем итоги

Мы проанализировали задачу автоматического расчета дней в периоде и выяснили, что оптимальный путь — использовать реквизит с типом Дата с настроенным форматом вывода месяца и года (ДФ='ММММ гггг'). Использование встроенных функций КонецМесяца() и День() гарантирует точный расчет количества дней с учетом специфики любого года, включая високосные периоды, и полностью избавляет от написания сложных алгоритмов проверки дат вручную.

← На главную