«Подводные камни» в простых методах 1С

24.02.26

Разработка - Механизмы платформы 1С

Все о «подводных камнях» в простых методах 1С: от неожиданного поведения дат и времени из-за региональных настроек и часовых поясов (ТекущаяДата() vs ТекущаяДатаСеанса()), преобразования строк в числа с учетом разделителей, до коварств Null в запросах, методов Пустая() и ЗначениеЗаполнено() с пустыми/битыми ссылками.

Все о «подводных камнях» в простых методах 1С рассказывает Саша, разработчик 1С из  нашей команды.

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

Содержание:

1Работа с датами и временем.

2.  Работа с числами.

3. Обработка пустых значений

4. Заключение

 

 

1. Работа с датами и временем.

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

 

 

    1.  Региональные установки информационной базы. Формат даты.

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

  Дата = ТекущаяДата(); 
    
  ДатаБезФормата      = Дата;
  ЛокДатаД            = Формат(Дата, "ДЛФ=Д");
    
  ДатаЧерезСлэш       = Формат(Дата, "ДФ=dd/MM/yy");
  ЛокДатаЧерезСлэш    = Формат(Дата, "ДЛФ=dd/MM/yy");
    

Для этого зайдем в меню «Администрирование - Региональные установки информационной базы» и установим формат даты:

  • dd/MM/yy

 

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

 

  • yyyy-MM-dd.

 

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

 

Анализ результатов выполнения идентичной процедуры при различных региональных настройках формата демонстрирует, что итоговые данные могут существенно различаться. Это подчёркивает необходимость детального указания строки формата в функциях.

 

    1.  Часовые пояса и получение текущей даты

Еще одним из подводных камней может быть получение Текущей даты, когда речь идет о работе из нескольких часовых поясов одновременно.

ТекущаяДата() – возвращает системную дату компьютера. Причем если сервер и клиент — это разные компьютеры, и дата или время на них не совпадает, то данная функция вернет разные значения.

ТекущаяДатаСеанса() – данная функция получает дату и время с учетом часового пояса сеанса пользователя.

Пользователи в разных часовых поясах получают разные значения, что нарушает логику сравнения.

Предположим, у нас в базе работают 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. Преобразование Строки в Число

При работе с числами в 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. Обработка пустых значений

 

 

В 1С «пустота» — понятие относительное. Оно зависит от типа данных. Разные функции проверки ведут себя поR09;разному, и это может привести к неожиданным результатам. Существуют несколько способов обозначить отсутствие данных:

  • Null — специальное значение, возвращаемое при отсутствии данных в запросах;
  • Неопределенно — значение по умолчанию для неинициализированных переменных;
  • Пустая строка — "";
  • Ноль — 0;
  • Пустая ссылка (для ссылочных типов).
    1. Значение 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С действительно может привести к множеству ошибок, если не соблюдать аккуратность и понимание основ работы с этим специальным типом данных.

    1. Методы Пустая() и ЗначениеЗаполнено()

Метод Пустая() работает корректно только тогда, когда ссылка инициализирована и имеет тип конкретного справочника или документа. Если же вы работаете с типом ЛюбаяСсылка или значением Неопределенно, вызов метода просто даст ошибку исполнения.

Создадим таблицу значение с колонкой составного типа (Строка и Контрагенты). Далее в таблицу добавим 3 строки с пустыми значениями (но разными типами):

ТЧ = Новый ТаблицаЗначений();
ДоступныеТипы = Новый Массив;
ДоступныеТипы.Добавить("Строка");
ДоступныеТипы.Добавить("СправочникСсылка.Контрагенты");
ТЧ.Колонки.Добавить("ПолеПроверки", Новый ОписаниеТипов(ДоступныеТипы));
  • Добавим строку, но не заполним само значение реквизита.
//НоваяСтрока = ТЧ.Добавить(); //Ошибка: Значение не является значением объектного типа (Пустая)
//Если НоваяСтрока.ПолеПроверки.Пустая() Тогда
//  Сообщить("Строка 1: Пусто");
//конецесли;

Попытка проверить заполненность реквизита через метод «Пустая» приводит к ошибке выполнения. Данное поведение объясняется тем, что значением по умолчанию у реквизитов составного типа является значение «Неопределено». А метод «Пустая» доступен только для ссылочных типов.

  • Для второй строки таблицы заполним пустой строкой.
//НоваяСтрока = ТЧ.Добавить(); //Ошибка: Значение не является значением объектного типа (Пустая)
//НоваяСтрока.ПолеПроверки = "";
//Если НоваяСтрока.ПолеПроверки.Пустая() Тогда
//  Сообщить("Строка 2: Пусто");
//конецесли;

В данном случаи при выполнении процедуры мы получим Ошибку. Т.к сейчас у нас реквизит имеет тип «Строка», а как мы помним, метод «Пустая» работает только для ссылочных типов.

  • И значение в 3 строке таблицы заполним значением Пустой ссылкой справочника Контрагенты»
НоваяСтрока = ТЧ.Добавить(); //Условие выполнится
НоваяСтрока.ПолеПроверки = Справочники.Контрагенты.ПустаяСсылка();
Если НоваяСтрока.ПолеПроверки.Пустая() Тогда
    Сообщить("Строка 3: Пусто");
конецесли;

Для третей строки условие выполнится успешно, как мы ожидали изначально: Значение в таблице не заполнено!

Из результата данного примера можно сказать, что использовать метод «Пустая» надо с осторожностью, только если мы точно уверены, что значение является значением ссылочного типа.

Для универсальной проверки лучше использовать функцию ЗначениеЗаполнено(). Она «переваривает» и Неопределено, и NULL, и Пустые ссылки.

НоваяСтрока = ТЧ.Добавить(); //1 - Неопределено

НоваяСтрока = ТЧ.Добавить(); //2 - ""
НоваяСтрока.ПолеПроверки = "";

НоваяСтрока = ТЧ.Добавить(); //3 - Пустая ссылка
НоваяСтрока.ПолеПроверки = Справочники.Контрагенты.ПустаяСсылка();

НоваяСтрока = ТЧ.Добавить(); //4 - Ссылка на существующего контрагента
НоваяСтрока.ПолеПроверки = Справочники.Контрагенты.НайтиПоНаименованию("Тестовый контрагент");

Сч = 1;
Для каждого СтрТаб из ТЧ Цикл
    Если НЕ ЗначениеЗаполнено(СтрТаб.ПолеПроверки) Тогда
        Сообщить(СтрШаблон("строка %1: Пусто", Сч));
    Иначе
        Сообщить(СтрШаблон("строка %1: Заполнено", Сч));
    КонецЕсли;
    Сч = Сч + 1;
КонецЦикла;
  1.  
  2.  
  3.  
    1. «Битая» ссылка — пустая или нет?

Пустая ссылка — это ссылка, состоящая из одних нулей в GUID (00000000-0000-0000...).

«Битая» ссылка — это когда GUID есть, но записи в таблице БД с таким идентификатором нет (например, удалили объект напрямую).

Метод Пустая() для «битой» ссылки вернет «Ложь», ЗначениеЗаполнено() – «Истина». Так как ссылка формально существует, просто указывает на несуществующий объект.

Метод Пустая() для «битой» ссылки вернет «Ложь», ЗначениеЗаполнено() – «Истина». Так как ссылка формально существует, просто указывает на несуществующий объект. 
НовыйКонтрагент = Справочники.Контрагенты.СоздатьЭлемент();
НовыйКонтрагент.Наименование = "Тест БитаяСсылка";
НовыйКонтрагент.Записать();
КонтрагентСсылка = НовыйКонтрагент.Ссылка;
НовыйКонтрагент.Удалить();

Если КонтрагентСсылка.Пустая() Тогда // Для "Битой ссылки" всегда вернет ЛОЖЬ
    Сообщить("Ссылка пустая!");
Иначе
    Сообщить("Контрагент существует");
КонецЕсли;

 

 

Почему так происходит? Потому что в 1С существует концепция существования ссылки независимо от наличия соответствующего ей объекта. Таким образом, битая ссылка не считается пустой, она лишь указывает на исчезнувший объект.

Один из способов проверить ссылку на «битость» — это попытаться обратиться к соответствующему объекту и сравнить с Неопределенно.

КонтрагентОбъект = КонтрагентСсылка.ПолучитьОбъект();

Если КонтрагентОбъект = Неопределено Тогда //ИСТИНА
    Сообщить("Ссылка битая!");
Иначе
    Сообщить("Контрагент существует");
КонецЕсли;

Такой подход эффективен, если вы работаете с небольшими объёмами данных, но будьте осторожны: массированная проверка таким способом может серьёзно снизить производительность системы.

У любого реального объекта в базе есть скрытый реквизит ВерсияДанных. У пустых и битых ссылок он всегда пуст. Данный метод работает на сервере и требует обращения к БД, но он гораздо быстрее, чем ПолучитьОбъект().

Если СокрЛП(КонтрагентСсылка.ВерсияДанных) = "" Тогда
    Сообщить("Контрагента нет!");
Иначе
    Сообщить("Контрагент существует");
КонецЕсли; 

 

Заключение

В этой статье мы рассмотрели несколько простых функций, которые, на первый взгляд, кажутся безобидными, но при неправильном использовании могут привести к серьезным проблемам в работе системы. Надеюсь, этот материал поможет вам избежать подобных ошибок в будущем. Если у вас есть свои примеры «подводных камней», делитесь ими в комментариях!

 

Поведение всех методов проверялось на платформе 8.3.27.1559.

Вступайте в нашу телеграмм-группу Инфостарт

1c дата время числа строка в число пустые значения Null

См. также

Механизмы платформы 1С Программист Бесплатно (free)

Разберем 15 мифов о работе платформы «1С:Предприятие 8» – как распространенных, так и малоизвестных. Начнем с классики: «Код, написанный в одну строку, работает быстрее, чем многострочный». Так ли это на самом деле?

16.07.2025    28742    TitanLuchs    106    

148

Механизмы платформы 1С Работа с интерфейсом Программист Стажер 1С:Предприятие 8 Бесплатно (free)

Про ООП в 1С и о том, как сделать свой код более кратким и выразительным при помощи использования текучего интерфейса (fluent interface).

03.02.2025    15724    bayselonarrend    127    

68

Механизмы платформы 1С Программист 1С:Предприятие 8 Бесплатно (free)

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

30.01.2025    18255    user2122906    9    

64

Механизмы платформы 1С WEB-интеграция Программист 1С:Предприятие 8 Бесплатно (free)

В платформе 8.3.27 появилась возможность использовать WebSocket-клиент. Давайте посмотрим, как это все устроено и чем оно нам полезно.

14.01.2025    29027    dsdred    89    

144

Механизмы платформы 1С Программист Стажер 1С:Предприятие 8 1C:Бухгалтерия Бесплатно (free)

Эта небольшая статья - некоторого рода шпаргалка по файловым потокам: как и зачем с ними работать, какие преимущества это дает.

23.06.2024    26191    bayselonarrend    22    

175

Механизмы платформы 1С Программист Стажер 1С:Предприятие 8 1C:Бухгалтерия Бесплатно (free)

Пример использования «Сервисов интеграции» без подключения к Шине и без обменов.

13.03.2024    14196    dsdred    22    

85
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. dsdred 4201 24.02.26 16:00 Сейчас в теме
У любого реального объекта в базе есть скрытый реквизит ВерсияДанных

Это таймстемп
2. user-z99999 77 24.02.26 16:06 Сейчас в теме
А почему не установить групповой политикой всем пользователям одинаковые настройки?
Ну ок, пусть будет зоопарк.
Может текущую дату всегда брать с сервера?
3. DmitryKlimushkin 136 24.02.26 16:09 Сейчас в теме
И всё это меркнет перед коварством объектов "СхемаXML" и "ЗаписьУзловDOM"))
4. RocKeR_13 1466 24.02.26 16:39 Сейчас в теме
Один из способов проверить ссылку на «битость» — это попытаться обратиться к соответствующему объекту и сравнить с Неопределенно.

Или использовать функцию БСП ОбщегоНазначения.СсылкаСуществует

Ну или запросом сравнить с Null значение одного из реквизитов объекта.
VyacheslavShilov; +1 Ответить
5. SergMuravev 877 24.02.26 17:02 Сейчас в теме
(4) Или функцией СтрНачинаетсяС(КонтрагентСсылка, "<Объект не найден>")
VyacheslavShilov; +1 Ответить
Для отправки сообщения требуется регистрация/авторизация