Как правильно прибавить числовую переменную к дате в 1С:Предприятие

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

В процессе разработки в системе 1С:Предприятие часто возникает задача вычисления новой даты на основе текущей с добавлением определенного количества дней, часов или секунд. Одной из распространенных проблем является ситуация, когда количество дней для добавления хранится в строковом формате или извлекается из сложной строки (например, "10 - 20"). В данной статье мы подробно разберем, как избежать ошибок приведения типов и правильно выполнить арифметические операции с датами.

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

Рассмотрим ситуацию: из справочника с помощью запроса получается строковое значение, например, "25" или "10 - 10". Нам необходимо извлечь из этой строки число и прибавить его к текущей дате в виде количества дней. Основная ошибка, с которой сталкиваются разработчики, — "Несоответствие типов" или невозможность преобразования строки к числу. Это происходит из-за того, что система не может автоматически выполнить арифметическую операцию, если один из операндов является строкой или если нарушен порядок следования типов в выражении.

Шаг 1: Правильное извлечение числа из строки

Если данные в базе хранятся в строковом поле (например, "30 - 60"), первым делом нам нужно выделить подстроку, содержащую число. Рассмотрим, как это сделать с помощью функций работы со строками. Предположим, что переменная ДатаЗавершенияСтрокой содержит значение "30 - 60".

Проанализируем классический способ выделения первой части строки до пробела:


// Получаем позицию первого пробела
ПозицияПробела = СтрНайти(ДатаЗавершенияСтрокой, " ");

// Если пробел найден, извлекаем левую часть
Если ПозицияПробела > 0 Тогда
    СтроковоеЗначение = Лев(ДатаЗавершенияСтрокой, ПозицияПробела - 1);
Иначе
    СтроковоеЗначение = ДатаЗавершенияСтрокой;
КонецЕсли;

Однако выделение подстроки — это только половина дела. Полученная переменная СтроковоеЗначение все еще имеет тип Строка. Попытка умножить ее на количество секунд в сутках (60 * 60 * 24) приведет к ошибке, так как в 1С нельзя умножать строку на число.

Шаг 2: Явное преобразование типов

Чтобы система могла производить расчеты, мы должны принудительно преобразовать строку в число, используя функцию Число(). Выясним важный нюанс: если в строке содержатся неразрывные пробелы (символ с кодом 160), которые часто используются как разделители разрядов, функция Число() может вызвать исключение. Поэтому перед преобразованием рекомендуется очистить строку.

Разберем безопасный код преобразования:


// Очищаем от неразрывных пробелов и преобразуем
ЧислоДней = Число(СтрЗаменить(СтроковоеЗначение, Символы.НПП, ""));

Шаг 3: Арифметика дат и порядок операндов

В 1С к значению типа Дата прибавляются секунды. Чтобы прибавить дни, мы умножаем количество дней на 86 400 (24 часа * 60 минут * 60 секунд).

Важное правило: тип результата выражения в 1С часто определяется по первому операнду. Рассмотрим два варианта:

  1. ТекущаяДата() + Число — результатом будет Дата. Это корректный путь.
  2. Число + ТекущаяДата() — система может попытаться преобразовать дату в число, что приведет к неожиданным результатам или ошибке.

Посмотрим на пример правильного расчета и форматирования вывода:


КоличествоСекунд = ЧислоДней * 24 * 60 * 60;
НоваяДата = ТекущаяДата() + КоличествоСекунд;

// Выводим результат в понятном формате
Сообщить(Формат(НоваяДата, "ДЛФ=Д")); 

Шаг 4: Обработка результатов запроса

Если вы получаете данные из запроса, крайне важно убедиться, что вы обходите выборку в цикле и проверяете значения на NULL. Если поле в базе не заполнено, функция Число(NULL) вызовет ошибку.

Проанализируем пример кода с использованием выборки:


Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ ЕСТЬNULL(Справочник.СрокВСтроке, ""0"") КАК Срок ИЗ Справочник.Сроки КАК Справочник";
Выборка = Запрос.Выполнить().Выбрать();

Пока Выборка.Следующий() Цикл
    // Парсим строку, если она сложная (например, "10 - 20")
    Срез = Лев(Выборка.Срок, СтрНайти(Выборка.Срок + " ", " ") - 1);
    
    // Прибавляем к дате, соблюдая порядок операндов
    Результат = ТекущаяДата() + Число(Срез) * 86400;
    
    Сообщить("Новая дата: " + Формат(Результат, "ДЛФ=Д"));
КонецЦикла;

Альтернативный подход: Использование функции ДОБАВИТЬКДАТЕ в запросе

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

Если бы срок хранился в числовом поле, мы могли бы написать так:


"ВЫБРАТЬ
|   ДОБАВИТЬКДАТЕ(&ТекущаяДата, ДЕНЬ, Таблица.КоличествоДней) КАК ДатаЗавершения
|ИЗ
|   ..."

Однако, так как у нас строка, нам все равно придется обрабатывать ее в коде, но стоит помнить о функции ДОБАВИТЬКДАТЕ для будущих задач, где типы данных определены верно.

Рекомендации по отладке

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


Сообщить("Тип переменной Срез: " + ТипЗнч(Срез));
Сообщить("Значение Срез: '" + Срез + "'");

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

← На главную