Как устранить ошибку преобразования даты при выгрузке данных из 1С в MSSQL?

Программист IT и автоматизация бизнеса
← На главную

При организации интеграции между 1С и внешними базами данных на базе MSSQL программисты часто сталкиваются с ошибкой: «Преобразование типа данных varchar в тип данных datetime привело к выходу значения за пределы диапазона». Эта проблема возникает из-за различий в представлении даты внутри платформы 1С и в правилах интерпретации строк SQL-сервером.

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

Разберем причину возникновения ошибки

Прежде чем переходить к коду, выясним причину сбоя. В MSSQL стандартный тип данных DATETIME имеет ограничение: он поддерживает даты в диапазоне от 1 января 1753 года до 31 декабря 9999 года. В 1С «пустая» дата соответствует значению 01.01.0001.

Когда вы пытаетесь передать пустую дату из 1С в поле DATETIME таблицы MSSQL, сервер получает значение «0001-01-01», которое находится вне допустимого диапазона, и выдает ошибку. Также проблема может быть в том, что SQL-сервер неверно распознает порядок дня и месяца в присланной вами строке (например, ожидает месяц-день-год, а получает год-день-месяц).

Решение 1: Правильное форматирование строки в 1С

Самый простой и распространенный способ — это явное приведение даты к строковому виду, который «понятен» SQL-серверу. Рассмотрим, как дополнить стандартный запрос 1С, чтобы он корректно воспринимался базой данных.

Проанализируем пример кода, где мы формируем условие WHERE для запроса к внешней таблице:


// Формируем строку условия с учетом времени
ТекстЗапроса = "SELECT * FROM table_re WHERE Date_Re >= '" 
    + Формат(ДатаНачала, "ДФ=""гггг-MM-дд""") + " 00:00:00" 
    + "' AND Date_Re <= '" 
    + Формат(ДатаОкончания, "ДФ=""гггг-MM-дд""") + " 23:59:59" + "'";

В данном примере мы используем функцию Формат с маской гггг-MM-дд. Обратите внимание, что добавление константы времени 00:00:00 помогает SQL-серверу однозначно интерпретировать строку как тип DATETIME.

Решение 2: Использование универсального формата ISO (без разделителей)

Посмотрим на более надежный метод. В зависимости от настроек локализации (языка) SQL-сервера, формат с дефисами (гггг-мм-дд) может быть воспринят неоднозначно. Существует универсальный формат YYYYMMDD, который MSSQL всегда интерпретирует как «год-месяц-день» независимо от настроек DATEFORMAT.

Реализуем этот подход в 1С:


// Универсальный формат без дефисов и точек
СтрокаДата = Формат(ДатаНачала, "ДФ=ггггММдд");
ТекстЗапроса = "INSERT INTO table1 (date_incoming) VALUES ('" + СтрокаДата + "')";

Использование ггггММдд исключает влияние региональных настроек сервера и считается «золотым стандартом» при формировании текстовых SQL-запросов вручную.

Решение 3: Обработка пустых дат

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

Рассмотрим пример функции-обертки:


Функция ПодготовитьДатуДляSQL(ВхДата)
    Если Не ЗначениеЗаполнено(ВхДата) Или ВхДата < '17530101' Тогда
        // Возвращаем минимально допустимую дату для SQL или NULL
        Возврат "17530101"; 
    Иначе
        Возврат Формат(ВхДата, "ДФ=ггггММдд");
    КонецЕсли;
КонецФункции

Если структура таблицы в MSSQL позволяет записывать пустые значения, вместо «17530101» лучше возвращать строку NULL (без кавычек в тексте запроса).

Решение 4: Использование параметризованных запросов (ADODB)

Выясним, как полностью уйти от проблем форматирования. Вместо склейки строк («динамический SQL») рекомендуется использовать параметры через объект Command. В этом случае драйвер (например, SQLOLEDB или MSOLEDBSQL) сам позаботится о правильной передаче даты.

Разберем по шагам:

  1. Создаем объект соединения ADODB.Connection.
  2. Создаем объект команды ADODB.Command.
  3. Добавляем параметр с типом adDBTimeStamp.

// Пример использования параметров
Command = Новый COMОбъект("ADODB.Command");
Command.ActiveConnection = Connection; // Ваше открытое соединение
Command.CommandText = "INSERT INTO table1 (date_field) VALUES (?)";

// Создаем параметр: имя, тип (135 = adDBTimeStamp), направление, размер, значение
Param = Command.CreateParameter("pDate", 135, 1, , ДатаИз1С);
Command.Parameters.Append(Param);
Command.Execute();

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

Решение 5: Настройка на стороне SQL (SET DATEFORMAT)

Если вы не можете оперативно изменить программный код в 1С, ситуацию можно исправить на стороне SQL-сервера. Перед основным запросом можно выполнить инструкцию, которая укажет серверу, как трактовать входящие строки.

Рассмотрим SQL-команду:


-- Устанавливаем порядок: год, месяц, день
SET DATEFORMAT ymd;
SELECT * FROM table_re WHERE Date_Re >= '2017-09-01';

Эта команда действует в рамках текущей сессии подключения. Она сообщает серверу, что в строке '2017-09-01' первым идет год, вторым — месяц, а третьим — день.

Решение 6: Переход на тип данных DATETIME2

Если вы проектируете структуру таблицы в MSSQL самостоятельно, рассмотрите возможность использования типа DATETIME2 вместо устаревшего DATETIME. Тип DATETIME2 поддерживает диапазон дат с 0001-01-01, что идеально совпадает с «пустой» датой 1С и полностью снимает проблему выхода за пределы диапазона.

Резюмируем: для быстрого исправления используйте формат ггггММдд в функции Формат(), а для надежной работы в крупных проектах переходите на параметризованные запросы через ADODB.Command.

← На главную