В процессе разработки в системе 1С:Предприятие часто возникает задача вычисления новой даты на основе текущей с добавлением определенного количества дней, часов или секунд. Одной из распространенных проблем является ситуация, когда количество дней для добавления хранится в строковом формате или извлекается из сложной строки (например, "10 - 20"). В данной статье мы подробно разберем, как избежать ошибок приведения типов и правильно выполнить арифметические операции с датами.
Рассмотрим ситуацию: из справочника с помощью запроса получается строковое значение, например, "25" или "10 - 10". Нам необходимо извлечь из этой строки число и прибавить его к текущей дате в виде количества дней. Основная ошибка, с которой сталкиваются разработчики, — "Несоответствие типов" или невозможность преобразования строки к числу. Это происходит из-за того, что система не может автоматически выполнить арифметическую операцию, если один из операндов является строкой или если нарушен порядок следования типов в выражении.
Если данные в базе хранятся в строковом поле (например, "30 - 60"), первым делом нам нужно выделить подстроку, содержащую число. Рассмотрим, как это сделать с помощью функций работы со строками. Предположим, что переменная ДатаЗавершенияСтрокой содержит значение "30 - 60".
Проанализируем классический способ выделения первой части строки до пробела:
// Получаем позицию первого пробела
ПозицияПробела = СтрНайти(ДатаЗавершенияСтрокой, " ");
// Если пробел найден, извлекаем левую часть
Если ПозицияПробела > 0 Тогда
СтроковоеЗначение = Лев(ДатаЗавершенияСтрокой, ПозицияПробела - 1);
Иначе
СтроковоеЗначение = ДатаЗавершенияСтрокой;
КонецЕсли;
Однако выделение подстроки — это только половина дела. Полученная переменная СтроковоеЗначение все еще имеет тип Строка. Попытка умножить ее на количество секунд в сутках (60 * 60 * 24) приведет к ошибке, так как в 1С нельзя умножать строку на число.
Чтобы система могла производить расчеты, мы должны принудительно преобразовать строку в число, используя функцию Число(). Выясним важный нюанс: если в строке содержатся неразрывные пробелы (символ с кодом 160), которые часто используются как разделители разрядов, функция Число() может вызвать исключение. Поэтому перед преобразованием рекомендуется очистить строку.
Разберем безопасный код преобразования:
// Очищаем от неразрывных пробелов и преобразуем
ЧислоДней = Число(СтрЗаменить(СтроковоеЗначение, Символы.НПП, ""));
В 1С к значению типа Дата прибавляются секунды. Чтобы прибавить дни, мы умножаем количество дней на 86 400 (24 часа * 60 минут * 60 секунд).
Важное правило: тип результата выражения в 1С часто определяется по первому операнду. Рассмотрим два варианта:
ТекущаяДата() + Число — результатом будет Дата. Это корректный путь.Число + ТекущаяДата() — система может попытаться преобразовать дату в число, что приведет к неожиданным результатам или ошибке.Посмотрим на пример правильного расчета и форматирования вывода:
КоличествоСекунд = ЧислоДней * 24 * 60 * 60;
НоваяДата = ТекущаяДата() + КоличествоСекунд;
// Выводим результат в понятном формате
Сообщить(Формат(НоваяДата, "ДЛФ=Д"));
Если вы получаете данные из запроса, крайне важно убедиться, что вы обходите выборку в цикле и проверяете значения на NULL. Если поле в базе не заполнено, функция Число(NULL) вызовет ошибку.
Проанализируем пример кода с использованием выборки:
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ ЕСТЬNULL(Справочник.СрокВСтроке, ""0"") КАК Срок ИЗ Справочник.Сроки КАК Справочник";
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
// Парсим строку, если она сложная (например, "10 - 20")
Срез = Лев(Выборка.Срок, СтрНайти(Выборка.Срок + " ", " ") - 1);
// Прибавляем к дате, соблюдая порядок операндов
Результат = ТекущаяДата() + Число(Срез) * 86400;
Сообщить("Новая дата: " + Формат(Результат, "ДЛФ=Д"));
КонецЦикла;
Вместо того чтобы выполнять сложные манипуляции в программном коде, мы можем перенести логику сложения прямо в текст запроса. Это более эффективно с точки зрения производительности и избавляет от проблем с типами данных в коде 1С.
Если бы срок хранился в числовом поле, мы могли бы написать так:
"ВЫБРАТЬ
| ДОБАВИТЬКДАТЕ(&ТекущаяДата, ДЕНЬ, Таблица.КоличествоДней) КАК ДатаЗавершения
|ИЗ
| ..."
Однако, так как у нас строка, нам все равно придется обрабатывать ее в коде, но стоит помнить о функции ДОБАВИТЬКДАТЕ для будущих задач, где типы данных определены верно.
Если ваш код не работает, и вы не можете использовать штатный отладчик, используйте функцию ТипЗнч() для проверки того, что именно находится в ваших переменных. Это поможет выяснить, в какой момент число превращается в строку или где возникает Неопределено.
Сообщить("Тип переменной Срез: " + ТипЗнч(Срез));
Сообщить("Значение Срез: '" + Срез + "'");
Подведем итог: для успешного прибавления переменной к дате необходимо выполнить три условия: извлечь подстроку, явно преобразовать ее функцией Число() и прибавить полученное значение (в секундах) к дате, ставя дату первым операндом в выражении.