При работе с внешними источниками данных в 1С, особенно при взаимодействии с СУБД Oracle, мы часто сталкиваемся с проблемой несоответствия форматов данных, в частности, типа "Дата". Такая ситуация может привести к ошибкам вроде "literal does not match format string" или "a non-numeric character was found where a numeric was expected". Давайте подробно разберем, как решить эту распространенную задачу и обеспечить корректную запись дат из 1С в Oracle.
Представим, что у нас есть задача по модификации данных в таблице внешнего источника данных (СУБД Oracle). Мы создали в 1С (на платформе 8.3.25.1394, что характерно для управляемых форм) внешний источник данных и добавили в него соответствующую таблицу. Одно из полей таблицы, например, с именем period, в 1С автоматически определилось как тип "Дата" (Дата + время). На стороне Oracle это поле также имеет тип DATE и содержит значения в формате, например, 2022-01-01 00:00:00.000.
Когда мы пытаемся записать новую строку в эту таблицу, присваивая полю period значение типа "Дата" из переменной 1С, например, ДанныеКОбработке.НачалоПериода, мы получаем ошибку: "literal does not match format string".
Вот пример нашего первоначального кода:
ТекущееСогласование = МенеджерВИ.СоздатьОбъект;
ТекущееСогласование.CODE = 1111111111111100;
ТекущееСогласование.period = ДанныеКОбработке.НачалоПериода; // Здесь возникает ошибка
ТекущееСогласование.cd_coll_boss = ДанныеКОбработке.КодРуководителя;
ТекущееСогласование.cd_dept = ДанныеКОбработке.КодПодразделения;
ТекущееСогласование.status = 0;
ТекущееСогласование.condition = 0;
ТекущееСогласование.doc_tab_src = Т13ДвоичныеДанные;
ТекущееСогласование.doc_tab_type = "XLSX";
ТекущееСогласование.ERR_MSG = null;
ТекущееСогласование.MODIFIED = null;
Попытка
ТекущееСогласование.Записать;
Исключение
Сообщить(ОписаниеОшибки);
Продолжить;
КонецПопытки;
Мы выяснили, что если заменить строку ТекущееСогласование.period = ДанныеКОбработке.НачалоПериода; на ТекущееСогласование.period = null;, то новая запись успешно создается. Это явно указывает на то, что проблема заключается в формате передаваемой даты.
В поисках решения мы пробовали изменить тип поля period на стороне 1С на "Строка" и попытаться передать дату в виде строки, используя функцию Oracle TO_DATE(), например, так:
ТекущееСогласование.period = "to_date(" + "'" + ДанныеКОбработке.НачалоПериода + "','"+ "YYYY-MM-DD HH24:MI:SS" + "')";
или даже как простой строковый литерал с вызовом TO_DATE:
ТекущееСогласование.period = "to_date('2025.08.21','yyyy.mm.dd')";
В обоих случаях мы получили ошибку Oracle: "a non-numeric character was found where a numeric was expected".
Важно понимать: менеджер внешнего источника данных в 1С (МенеджерВИ) не интерпретирует строку "to_date('...','...')" как SQL-функцию, которую нужно выполнить на стороне СУБД. Вместо этого он передает ее как строковое значение для поля period. Oracle затем пытается неявно преобразовать эту строку "to_date('...','...')" в дату, что, очевидно, не удается, поскольку это не является корректным строковым представлением даты.
Даже когда разработчик Oracle сообщил, что ожидаемый формат даты — 'dd.mm.yyyy hh24:mi', прямые попытки присвоить строку в этом формате также приводили к ошибке "a non-numeric character was found where a numeric was expected". Это подтверждает, что механизм неявного преобразования на стороне Oracle очень чувствителен к точным настройкам локали и формату входящей строки, а прямое внедрение SQL-функций через поля внешнего источника данных не работает.
Мы выяснили, что Oracle способен неявно преобразовывать строки в даты, если формат строки соответствует его ожиданиям, особенно с учетом настроек локали сессии. Решение, которое успешно заработало, заключалось в форматировании даты в 1С таким образом, чтобы она максимально точно соответствовала одному из стандартных форматов Oracle для неявного преобразования, особенно с учетом английской локали.
Вот измененная строка кода, которая позволила успешно записывать даты:
ТекущееСогласование = МенеджерВИ.СоздатьОбъект;
ТекущееСогласование.CODE = 1111111111111100;
ТекущееСогласование.period = Формат(ДанныеКОбработке.НачалоПериода, "Л=en; ДФ='дд МММ гггг'"); // Это рабочее решение!
ТекущееСогласование.cd_coll_boss = ДанныеКОбработке.КодРуководителя;
ТекущееСогласование.cd_dept = ДанныеКОбработке.КодПодразделения;
ТекущееСогласование.status = 0;
ТекущееСогласование.condition = 0;
ТекущееСогласование.doc_tab_src = Т13ДвоичныеДанные;
ТекущееСогласование.doc_tab_type = "XLSX";
ТекущееСогласование.ERR_MSG = null;
ТекущееСогласование.MODIFIED = null;
Попытка
ТекущееСогласование.Записать;
Исключение
Сообщить(ОписаниеОшибки);
Продолжить;
КонецПопытки;
Давайте разберем параметры функции Формат() в 1С, которые сделали это решение эффективным:
Л=en (Локаль = English): Этот параметр имеет критическое значение. Он гарантирует, что названия месяцев в строковом представлении даты будут на английском языке (например, "Jan" вместо "Янв", "Feb" вместо "Фев" и так далее). Многие инсталляции Oracle по умолчанию настроены на английский язык для обработки дат, и неявное преобразование работает гораздо более надежно с англоязычными названиями месяцев.ДФ='дд МММ гггг' (Дата Формат = день Месяц (сокращенное) год): Этот параметр определяет желаемый шаблон форматирования даты. В данном случае мы получаем:
дд – день месяца (две цифры, например, "21").МММ – сокращенное название месяца (три буквы, например, "Jan").гггг – полный год (четыре цифры, например, "2025").Пример вывода такой строки: "21 Jan 2025". Именно этот формат Oracle смог успешно преобразовать в свой внутренний тип DATE.
Таким образом, мы видим, что ключ к решению заключался не в использовании сложных SQL-функций, а в точном подборе формата строкового представления даты, которое 1С отправляет в Oracle, чтобы оно соответствовало ожиданиям СУБД для неявного преобразования.
В процессе поиска решения мы испробовали несколько других подходов, которые не привели к успеху. Давайте проанализируем, почему они не сработали, чтобы лучше понять механику взаимодействия 1С и Oracle.
'YYYYMMDD', 'YYYY-MM-DDThh:mm:ss', 'MM/DD/YYYY')Мы пробовали использовать различные строковые форматы, которые кажутся логичными для даты:
ТекущееСогласование.period = '20250801'; // Получена ошибка "not a valid month"
ТекущееСогласование.period = '2025-08-01T12:43:05'; // Получена ошибка "not a valid month"
ТекущееСогласование.period = "'08/01/2025'"; // Получена ошибка Oracle "a non-numeric character was found where a numeric was expected"
Эти ошибки показывают, что хотя Oracle может работать с подобными форматами при явном указании в TO_DATE(), для неявного преобразования необходима строка, которая **точно** соответствует текущему значению параметра сессии NLS_DATE_FORMAT (например, 'DD-MON-YY' или 'DD.MM.YYYY HH24:MI'). Малейшее отклонение, например, в разделителях, порядке компонентов даты или наличии компонента времени, которого Oracle не ожидает в этом контексте, приводит к ошибке. Если 1С передает такую строку как значение поля, Oracle просто не может ее разобрать.
{ts '...'}Один из предложенных вариантов был использовать синтаксис {ts '"+Формат(Знч,"ДФ=гггг-ММ-дд")+" "+Формат(Знч,"ДФ=ЧЧ:мм:сс")+"'}". Этот синтаксис является стандартным способом передачи отметок времени (timestamps) в SQL-запросах через JDBC/ODBC драйверы и предназначен для обеспечения совместимости между различными СУБД.
Однако, когда мы работаем с объектами ОбъектВнешнегоИсточникаДанных в 1С (например, ТекущееСогласование), менеджер внешнего источника данных 1С, скорее всего, не обертывает значение поля в этот специальный синтаксис {ts '...'}, а передает его в базу данных как обычную строку. Таким образом, база данных Oracle не распознает эту конструкцию как инструкцию для обработки даты, а пытается неявно преобразовать всю строку, что снова приводит к ошибке.
Для создания более надежной и устойчивой интеграции между 1С и Oracle, особенно в части работы с датами, мы предлагаем рассмотреть следующие рекомендации:
TO_DATE() в Oracle (при возможности прямого SQL)Если в вашем сценарии есть возможность формировать SQL-запросы напрямую (например, через выполнение запроса к внешнему источнику 1С или используя хранимые процедуры Oracle), это самый надежный и предпочтительный способ работы с датами. В таких случаях мы явно указываем Oracle, какой формат имеет наша строка даты, используя функцию TO_DATE().
-- Пример SQL-запроса, который вы могли бы отправить через Execute(...)
INSERT INTO ТАБЛИЦА_ORACLE (period, other_field)
VALUES (TO_DATE('2025-01-01 10:30:00', 'YYYY-MM-DD HH24:MI:SS'), 'some_value');
В этом примере 'YYYY-MM-DD HH24:MI:SS' является форматом, в котором вы подготовили строку даты в 1С. Такой подход исключает зависимость от настроек NLS_DATE_FORMAT сессии и обеспечивает однозначное толкование даты.
Независимо от того, используете ли вы прямое SQL или механизм внешних источников данных 1С, всегда выбирайте один универсальный и однозначный формат даты для формирования строкового представления в 1С. Хорошим примером является формат YYYY-MM-DD HH:MM:SS.
// Пример форматирования для получения универсальной строки
СтрокаДатыДляOracle = Формат(МояДата, "ДФ='гггг-ММ-дд ЧЧ:мм:СС'");
Этот формат является международным стандартом (ISO 8601) и чаще всего легко распознается базами данных или может быть использован в функции TO_DATE(). В случае с внешними источниками данных 1С, если найденное решение с "Л=en; ДФ='дд МММ гггг'" перестанет работать (например, после обновления Oracle или изменения настроек локали), попытка использовать ISO-формат с английской локалью может быть следующим шагом.
NLS_DATE_FORMATМы должны всегда помнить, что значение параметра NLS_DATE_FORMAT в сессии Oracle (или на уровне базы данных) определяет, как Oracle ожидает и отображает даты при неявных преобразованиях. Если у нас есть необходимые права, мы можем проверить его значение:
SELECT VALUE FROM NLS_SESSION_PARAMETERS WHERE PARAMETER = 'NLS_DATE_FORMAT';
Знание этого формата критически важно. Оно поможет нам точно настроить функцию Формат() в 1С, чтобы генерировать строки, которые Oracle будет гарантированно понимать.
В сложных случаях, при нестандартных настройках базы данных или если ни один из стандартных подходов не работает, всегда полезно проконсультироваться с администратором базы данных Oracle. Он сможет предоставить точные сведения об ожидаемых форматах даты, настройках локали и возможных ограничениях, которые могут влиять на процесс интеграции.
В заключение, мы выяснили, что основной трудностью при записи даты из 1С в Oracle через внешний источник данных является необходимость формирования строкового представления даты в 1С таким образом, чтобы Oracle мог неявно преобразовать ее в свой внутренний тип DATE. Решение с использованием Формат(ДанныеКОбработке.НачалоПериода, "Л=en; ДФ='дд МММ гггг'") оказалось эффективным благодаря точному соответствию одному из форматов, которые Oracle ожидает для неявного преобразования, особенно с учетом английской локали. При этом важно осознавать ограничения механизма внешних источников данных 1С в отношении прямого выполнения SQL-функций.