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

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

-
- Региональные установки информационной базы. Формат даты.
При разработке надо учитывать формат даты, установленный в настройках информационной базы. Иногда результат может быть неожиданным. Выполним простую процедуру с разными настройками ИБ и сверим результат выполнения.
Дата = ТекущаяДата();
ДатаБезФормата = Дата;
ЛокДатаД = Формат(Дата, "ДЛФ=Д");
ДатаЧерезСлэш = Формат(Дата, "ДФ=dd/MM/yy");
ЛокДатаЧерезСлэш = Формат(Дата, "ДЛФ=dd/MM/yy");
Для этого зайдем в меню «Администрирование - Региональные установки информационной базы» и установим формат даты:
- dd/MM/yy

В результате выполнения процедуры выше мы получим результат:

- yyyy-MM-dd.

Затем получим:

Анализ результатов выполнения идентичной процедуры при различных региональных настройках формата демонстрирует, что итоговые данные могут существенно различаться. Это подчёркивает необходимость детального указания строки формата в функциях.
Еще одним из подводных камней может быть получение Текущей даты, когда речь идет о работе из нескольких часовых поясов одновременно.
ТекущаяДата() – возвращает системную дату компьютера. Причем если сервер и клиент — это разные компьютеры, и дата или время на них не совпадает, то данная функция вернет разные значения.
ТекущаяДатаСеанса() – данная функция получает дату и время с учетом часового пояса сеанса пользователя.
Пользователи в разных часовых поясах получают разные значения, что нарушает логику сравнения.
Предположим, у нас в базе работают 2 пользователя: Иван из Ижевска (UTC+4) и Семен из Краснодара (UTC+3). В 10:40 они одновременно выполнять процедуру:
ДатаДляПроверки = Дата(2026,02,06,10,20,00); //06.02.2026 10:20
Если ДатаДляПроверки > ТекущаяДатаСеанса() Тогда
Сообщить("Дата из будущего!");
Иначе
Сообщить("Дата уже прошла!");
КонецЕсли;
В результате выполнения на экране они увидят различный результат. У Семена выйдет сообщение «Дата уже прошла», а вот для Ивана – «Дата из будущего».
Для того, чтобы Иван и Семен не спорили о том, что время наступило или еще нет, мы можем использовать универсальное время для сравнений:
ДатаДляПроверки = Дата(2026,02,06,10,20,00); //06.02.2026 10:20
УниверсальноеВремяСоздания = УниверсальноеВремя(ДатаПроверки, ЧасовойПояс());
УниверсальноеТекущее = УниверсальноеВремя(ТекущаяДатаСеанса(), ЧасовойПояс());
Если УниверсальноеВремяСоздания > УниверсальноеТекущее Тогда
Сообщить("Дата из будущего!");
Иначе
Сообщить("Дата уже прошла!");
КонецЕсли;
- Работа с числами
- Преобразование Строки в Число
При работе с числами в 1С нужно быть внимательным к тому, как они хранятся и обрабатываются. Например, если вы используете функцию Число(), то нужно быть внимательным к тому, какой тип данных используется.
Число1 = Число("10"); //10
//Число2 = Число("10 1"); // Ошибка "Преобразование значения к типу Число не может быть выполнено"
//Число3 = Число(""); // Ошибка "Преобразование значения к типу Число не может быть выполнено"
Для избегания ошибки необходимо предварительно обрабатывать Строку или использовать функцию СтрВЧисло() (только в новых версиях).
ЧислоСтрокой = "10 1"; //"10", "10.1", ""
Если ЗначениеЗаполнено(ЧислоСтрокой)
И ТипЗнч(ЧислоСтрокой) = Тип("Строка") Тогда
Число1 = Число(СтрЗаменить(ЧислоСтрокой, " ", ""));
Иначе
Число1 = 0;
КонецЕсли;
////ИЛИ
Число1 = СтрокаВЧисло("10.1"); //10.1
Число2 = СтрокаВЧисло("10 1"); //0
Число3 = СтрокаВЧисло(""); //0
Также при работе с числами важно учитывать Региональные установки информационной базы.
Установим значения: Разделитель дробной части = «Точка», а Разделителем групп укажем Запятая. И выполним простой код преобразования Числа из строки с указанием дробной части.

Число1 = СтрокаВЧисло("10.1"); // 10.1
Число2 = СтрокаВЧисло("10,1"); // 101 (т.к в региональных настройках указан разделитель групп ",")
Число3 = СтрокаВЧисло("10 1"); // 0 (т.е не получилось преобразовать Число)
При выполнения простой функции преобразования Строки с дробной частью в Число мы видим, как легко можно ошибиться с полученным результатом, если не учесть Региональные установки ИБ.

В 1С «пустота» — понятие относительное. Оно зависит от типа данных. Разные функции проверки ведут себя поR09;разному, и это может привести к неожиданным результатам. Существуют несколько способов обозначить отсутствие данных:
- Null — специальное значение, возвращаемое при отсутствии данных в запросах;
- Неопределенно — значение по умолчанию для неинициализированных переменных;
- Пустая строка — "";
- Ноль — 0;
- Пустая ссылка (для ссылочных типов).
- Значение Null
Значение Null — один из самых коварных элементов в разработке на 1С. На первый взгляд, оно просто обозначает «отсутствие значения», но на практике порождает множество неочевидных ошибок. Разберём ключевые проблемы и способы их решения.
- Сравнение с NULL в запросах всегда даёт Ложь
Рассмотрим простую процедуру проверки наличия значения:
ЗначениеДляПроверки = Null;
ЗначениеДляПроверки2 = "12";
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ВЫБОР
| КОГДА &ЗначениеДляПроверки = NULL
| ТОГДА ""Значение1 равно Null""
| ИНАЧЕ ""Значение1 Существует""
| КОНЕЦ КАК Поле1,
| ВЫБОР
| КОГДА &ЗначениеДляПроверки2 = NULL
| ТОГДА ""Значение2 равно Null""
| ИНАЧЕ ""Значение2 Существует""
| КОНЕЦ КАК Поле2";
Запрос.УстановитьПараметр("ЗначениеДляПроверки" , ЗначениеДляПроверки);
Запрос.УстановитьПараметр("ЗначениеДляПроверки2", ЗначениеДляПроверки2);
Выборка = Запрос.Выполнить().Выбрать();
Выборка.Следующий();
Сообщить("Проверка 1: " + Выборка.Поле1;
Сообщить("Проверка 2: " + Выборка.Поле2;
Выполняя данный запрос, мы ожидаем увидеть в результате, что «Значение1 равно Null», и «Значение2 существует». Но выполняя процедуру, мы получаем сообщение, о том, что оба значения существуют:

Как видим из результата, выполнения процедуры, прямое сравнение = Null, всегда возвращает ЛОЖЬ, даже если значение действительно Null. Это происходит потому, что Null означает «неизвестное значение», поэтому любое сравнение с ним неопределённо.
Для корректного сравнение со значением Null необходимо использовать конструкцию сравнения «ЕСТЬ NULL». Давайте немного подправим наш запрос и выполним его.
Запрос.Текст =
"ВЫБРАТЬ
| ВЫБОР
| КОГДА &ЗначениеДляПроверки ЕСТЬ NULL
| ТОГДА ""Значение1 равно Null""
| ИНАЧЕ ""Значение1 Существует""
| КОНЕЦ КАК Поле1,
| ВЫБОР
| КОГДА &ЗначениеДляПроверки2 ЕСТЬ NULL
| ТОГДА ""Значение2 равно Null""
| ИНАЧЕ ""Значение2 Существует""
| КОНЕЦ КАК Поле2";

Как видим, теперь мы получили ожидаемый результат!
- Арифметические операции со значением NULL
Другая важная особенность работы с NULL состоит в том, что любые арифметические операции с участием NULL возвращают NULL. То есть даже простое сложение или умножение даст тот же результат — NULL.
Для примера предположим, что на определенный товар у нас отсутствует Цена, а мы хотим получить стоимость данного товара путем «Количество * Цена». При отсутствии значения цены мы предполагаем получить стоимость, равную 0.
Количество = 5;
Цена = Null;
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| &Количество * &Цена КАК Стоимость,
| &Количество КАК Количество,
| &Цена КАК Цена";
Запрос.УстановитьПараметр("Количество" , Количество);
Запрос.УстановитьПараметр("Цена" , Цена);
Выборка = Запрос.Выполнить().ВЫбрать();
Выборка.Следующий();
Стоимость = Выборка.Стоимость; //Null
//Стоимость = Выборка.Количество * Выборка.Цена; //Ошибка "Преобразование значения к типу Число не может быть выполнено"
//Стоимость = Количество * Цена; //Ошибка "Преобразование значения к типу Число не может быть выполнено"
Из результата выполнения кода выше мы можем увидеть, что в результате умножения на Null в запросе мы получаем всегда Null. А если мы хотим выполнить данное действие вне запроса, то вообще получаем ошибку.
Для корректного выполнения данной задачи необходимо немного подправить написанный код выше использовав метод ЕстьNull или сравнение с Null(вне запроса):
Количество = 5;
Цена = Null;
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ЕстьNull(&Количество,0) * ЕстьNull(&Цена,0) КАК Стоимость,
| ЕстьNull(&Количество,0) КАК Количество,
| ЕстьNull(&Цена,0) КАК Цена";
Запрос.УстановитьПараметр("Количество" , Количество);
Запрос.УстановитьПараметр("Цена" , Цена);
Выборка = Запрос.Выполнить().Выбрать();
Выборка.Следующий();
Стоимость1 = Выборка.Стоимость; // 5*0 = 0
Стоимость2 = Выборка.Количество * Выборка.Цена; // 5*0 = 0
Стоимость3 = ?(Количество = Null, 0, Количество) * ?(Цена= Null, 0 , Цена); // 5*0 = 0
Использование NULL-значений в 1С действительно может привести к множеству ошибок, если не соблюдать аккуратность и понимание основ работы с этим специальным типом данных.
-
- Методы Пустая() и ЗначениеЗаполнено()
Метод Пустая() работает корректно только тогда, когда ссылка инициализирована и имеет тип конкретного справочника или документа. Если же вы работаете с типом ЛюбаяСсылка или значением Неопределенно, вызов метода просто даст ошибку исполнения.
Создадим таблицу значение с колонкой составного типа (Строка и Контрагенты). Далее в таблицу добавим 3 строки с пустыми значениями (но разными типами):
ТЧ = Новый ТаблицаЗначений();
ДоступныеТипы = Новый Массив;
ДоступныеТипы.Добавить("Строка");
ДоступныеТипы.Добавить("СправочникСсылка.Контрагенты");
ТЧ.Колонки.Добавить("ПолеПроверки", Новый ОписаниеТипов(ДоступныеТипы));
- Добавим строку, но не заполним само значение реквизита.
//НоваяСтрока = ТЧ.Добавить(); //Ошибка: Значение не является значением объектного типа (Пустая)
//Если НоваяСтрока.ПолеПроверки.Пустая() Тогда
// Сообщить("Строка 1: Пусто");
//конецесли;
Попытка проверить заполненность реквизита через метод «Пустая» приводит к ошибке выполнения. Данное поведение объясняется тем, что значением по умолчанию у реквизитов составного типа является значение «Неопределено». А метод «Пустая» доступен только для ссылочных типов.
- Для второй строки таблицы заполним пустой строкой.
//НоваяСтрока = ТЧ.Добавить(); //Ошибка: Значение не является значением объектного типа (Пустая)
//НоваяСтрока.ПолеПроверки = "";
//Если НоваяСтрока.ПолеПроверки.Пустая() Тогда
// Сообщить("Строка 2: Пусто");
//конецесли;
В данном случаи при выполнении процедуры мы получим Ошибку. Т.к сейчас у нас реквизит имеет тип «Строка», а как мы помним, метод «Пустая» работает только для ссылочных типов.
- И значение в 3 строке таблицы заполним значением Пустой ссылкой справочника Контрагенты»
НоваяСтрока = ТЧ.Добавить(); //Условие выполнится
НоваяСтрока.ПолеПроверки = Справочники.Контрагенты.ПустаяСсылка();
Если НоваяСтрока.ПолеПроверки.Пустая() Тогда
Сообщить("Строка 3: Пусто");
конецесли;
Для третей строки условие выполнится успешно, как мы ожидали изначально: Значение в таблице не заполнено!
Из результата данного примера можно сказать, что использовать метод «Пустая» надо с осторожностью, только если мы точно уверены, что значение является значением ссылочного типа.
Для универсальной проверки лучше использовать функцию ЗначениеЗаполнено(). Она «переваривает» и Неопределено, и NULL, и Пустые ссылки.
НоваяСтрока = ТЧ.Добавить(); //1 - Неопределено
НоваяСтрока = ТЧ.Добавить(); //2 - ""
НоваяСтрока.ПолеПроверки = "";
НоваяСтрока = ТЧ.Добавить(); //3 - Пустая ссылка
НоваяСтрока.ПолеПроверки = Справочники.Контрагенты.ПустаяСсылка();
НоваяСтрока = ТЧ.Добавить(); //4 - Ссылка на существующего контрагента
НоваяСтрока.ПолеПроверки = Справочники.Контрагенты.НайтиПоНаименованию("Тестовый контрагент");
Сч = 1;
Для каждого СтрТаб из ТЧ Цикл
Если НЕ ЗначениеЗаполнено(СтрТаб.ПолеПроверки) Тогда
Сообщить(СтрШаблон("строка %1: Пусто", Сч));
Иначе
Сообщить(СтрШаблон("строка %1: Заполнено", Сч));
КонецЕсли;
Сч = Сч + 1;
КонецЦикла;
-
- «Битая» ссылка — пустая или нет?
Пустая ссылка — это ссылка, состоящая из одних нулей в GUID (00000000-0000-0000...).
«Битая» ссылка — это когда GUID есть, но записи в таблице БД с таким идентификатором нет (например, удалили объект напрямую).
Метод Пустая() для «битой» ссылки вернет «Ложь», ЗначениеЗаполнено() – «Истина». Так как ссылка формально существует, просто указывает на несуществующий объект.
Метод Пустая() для «битой» ссылки вернет «Ложь», ЗначениеЗаполнено() – «Истина». Так как ссылка формально существует, просто указывает на несуществующий объект.
НовыйКонтрагент = Справочники.Контрагенты.СоздатьЭлемент();
НовыйКонтрагент.Наименование = "Тест БитаяСсылка";
НовыйКонтрагент.Записать();
КонтрагентСсылка = НовыйКонтрагент.Ссылка;
НовыйКонтрагент.Удалить();
Если КонтрагентСсылка.Пустая() Тогда // Для "Битой ссылки" всегда вернет ЛОЖЬ
Сообщить("Ссылка пустая!");
Иначе
Сообщить("Контрагент существует");
КонецЕсли;

Почему так происходит? Потому что в 1С существует концепция существования ссылки независимо от наличия соответствующего ей объекта. Таким образом, битая ссылка не считается пустой, она лишь указывает на исчезнувший объект.
Один из способов проверить ссылку на «битость» — это попытаться обратиться к соответствующему объекту и сравнить с Неопределенно.
КонтрагентОбъект = КонтрагентСсылка.ПолучитьОбъект();
Если КонтрагентОбъект = Неопределено Тогда //ИСТИНА
Сообщить("Ссылка битая!");
Иначе
Сообщить("Контрагент существует");
КонецЕсли;
Такой подход эффективен, если вы работаете с небольшими объёмами данных, но будьте осторожны: массированная проверка таким способом может серьёзно снизить производительность системы.
У любого реального объекта в базе есть скрытый реквизит ВерсияДанных. У пустых и битых ссылок он всегда пуст. Данный метод работает на сервере и требует обращения к БД, но он гораздо быстрее, чем ПолучитьОбъект().
Если СокрЛП(КонтрагентСсылка.ВерсияДанных) = "" Тогда
Сообщить("Контрагента нет!");
Иначе
Сообщить("Контрагент существует");
КонецЕсли;
Заключение
В этой статье мы рассмотрели несколько простых функций, которые, на первый взгляд, кажутся безобидными, но при неправильном использовании могут привести к серьезным проблемам в работе системы. Надеюсь, этот материал поможет вам избежать подобных ошибок в будущем. Если у вас есть свои примеры «подводных камней», делитесь ими в комментариях!
Поведение всех методов проверялось на платформе 8.3.27.1559.
Вступайте в нашу телеграмм-группу Инфостарт
