Почему при импорте из Excel в 1С 7.7 документы улетают в начало журнала и как правильно считывать даты?

Программист 1С v7.7 1C:Бухгалтерия Бухгалтерский учет IT и автоматизация бизнеса
← На главную

При автоматизации импорта данных из внешних систем (например, файлов выгрузки клиент-банка в формате Excel) разработчики на платформе 1С 7.7 часто сталкиваются со странным поведением системы. Выгрузка завершается успешно, программа сообщает, что все документы загружены, однако в привычном интервале видимости журнала документов новые записи не появляются. При этом точечный поиск по номеру или программный перебор находит созданный документ, но его интерактивное открытие вызывает кучу ошибок, связанных с датой запрета редактирования.

В этой статье мы подробно разберем, почему возникает эта проблема, как диагностировать скрытые ошибки позиционирования документов в базах данных DBF/SQL и рассмотрим наиболее надежные способы чтения дат через COM-объект Excel, которые навсегда защитят ваш код от подобных сбоев.

Выясняем причину: куда пропадают документы?

Рассмотрим классическую ситуацию. При импорте файла Excel код успешно отрабатывает, но созданные документы оказываются в самом начале журнала — даже перед документами 1998 года. При попытке открыть такой документ программный модуль выдает предупреждение о запрете редактирования, ссылаясь на то, что дата документа меньше даты запрета (например, 01.01.2017). При этом отладчик нагло утверждает, что переменная ДатаДок равна '29.07.20', а в коде импорта используется стандартная функция выделения подстроки:


дат = СокрЛП(НашЛист.Cells(i,16).Value);
День = Сред(Дат,1,2);
Мес = Сред(Дат,4,2);
год = Сред(Дат,7,4);
Тз.Дата = Дата(год,мес,день);

В чем же здесь кроется подвох? Дело в том, что в настройках интерфейса 1С 7.7 по умолчанию может быть установлено отображение года двумя цифрами. Когда мы смотрим на дату в отладчике или в журнале, мы видим привычные глазу 29.07.20. Но стоит зайти в меню "Сервис" — "Параметры" — вкладка "Общие" и установить параметр "Год четырьмя цифрами", как пелена спадает с глаз: реальная дата документа в базе данных оказывается 29.07.0020 (20-й год нашей эры!).

Естественно, документ, созданный в первом веке нашей эры, улетает в самое начало журнала (так как он "старше" документов 1998 года почти на две тысячи лет). Константа ДатаЗапретаРедактирования (например, 01.01.2017) оказывается гораздо позже этой даты, поэтому стандартная функция глПроверкаДатыДок мгновенно блокирует любые действия с документом.

Почему это произошло? При обращении к свойству ячейки Excel Value через COM-соединение, система пытается автоматически привести типы. Если в настройках операционной системы Windows или самого Excel формат даты по умолчанию настроен как короткий (с двузначным годом), свойство Value возвращает строку вида "29.07.20". Жестко прописанная функция Сред(Дат,7,4) считывает символы начиная с 7-й позиции. В строке "29.07.20" на этой позиции находятся всего два символа — "20". Функция Дата() интерпретирует переданную строку "20" не как 2020 год, а буквально — как 20-й год.

Давайте разберем по шагам, как исправить эту ошибку и сделать процедуру импорта абсолютно отказоустойчивой.

Решение 1: Использование свойства .Text вместо .Value

Самый простой способ избежать искажения строкового формата даты — считывать видимое текстовое представление ячейки. Свойство Value пытается передать значение с учетом внутреннего типа данных Excel, в то время как свойство Text возвращает строку ровно в том виде, в каком она отображается пользователю на экране монитора.

Если в файле Excel колонка с датой отформатирована с четырехзначным отображением года (например, ДД.ММ.ГГГГ), то использование следующей конструкции гарантирует получение корректной строки:


// Считываем строковое отображение ячейки
Дат = СокрЛП(НашЛист.Cells(i,16).Text);
// Теперь строка гарантированно содержит "29.07.2020"
День = Сред(Дат, 1, 2);
Мес = Сред(Дат, 4, 2);
Год = Сред(Дат, 7, 4);
ТекДата = Дата(Год, Мес, День);

Важное примечание: Этот способ сработает только в том случае, если вы уверены, что в самом файле Excel настроен правильный показ четырехзначного года. Если файл формируется сторонней программой с двузначным годом, этот метод потребует дополнительной программной обработки строки.

Решение 2: Получение даты через .Value2 (математический расчет)

Наиболее надежный и профессиональный метод работы с датами в Excel — это использование свойства ячейки Value2. В отличие от Value, это свойство полностью игнорирует форматирование ячейки (денежное, дата, время) и возвращает чистое значение в виде числа с плавающей запятой.

Внутренний стандарт хранения дат в Microsoft Excel представляет собой количество дней, прошедших с гипотетической даты 1 января 1900 года. Например, дата 29.07.2020 в числовом выражении Excel будет выглядеть как 44041.

Мы можем легко перевести это число в стандартную дату 1С 7.7 с помощью простой математической формулы. При этом полностью исключаются проблемы локальных настроек Windows, разделителей (точки, слэши) и количества символов в году.

Посмотрим на пример реализации такого пересчета:


ЧисловоеЗначение = НашЛист.Cells(i,16).Value2;
Если ПустоеЗначение(ЧисловоеЗначение) = 0 Тогда
    // Преобразуем число Excel в дату 1С. 
    // Вычитаем 2 дня для компенсации исторической ошибки високосного 1900 года в Excel
    ТекДата = ПолучитьДатуИзExcel(ЧисловоеЗначение);
КонецЕсли;

// Функция-помощник для пересчета
Функция ПолучитьДатуИзExcel(Знач ЧислоДней)
    // Excel считает 1900 год високосным (ошибка разработчиков Microsoft), 
    // поэтому для дат после 28.02.1900 нужно вычитать 2 дня.
    Возврат '01.01.1900' + Число(ЧислоДней) - 2;
КонецФункции

Этот алгоритм работает невероятно быстро, не зависит от региональных стандартов операционной системы и всегда формирует корректную дату в 1С 7.7.

Решение 3: Универсальная функция разбора строки даты

Если вы все же предпочитаете разбирать текстовую строку, никогда не используйте жесткую адресацию символов через Сред(Дат, 7, 4). Достаточно клиенту изменить формат выгрузки (например, убрать ведущие нули у дней или месяцев: 9.7.2020 вместо 09.07.2020), и ваш импорт полностью сломается.

Проанализируем ситуацию и напишем надежную функцию, которая самостоятельно найдет разделители (точки или косые черты) и корректно восстановит четырехзначный год, даже если в исходном файле было передано всего две цифры (например, "20"):


Функция ПреобразоватьСтрокуВДату(Знач СтрДаты)
    СтрДаты = СокрЛП(СтрДаты);
    Если ПустаяСтрока(СтрДаты) = 1 Тогда
        Возврат ПолучитьПустуюДату();
    КонецЕсли;
    
    // Заменяем возможные разделители на точки
    СтрДаты = СтрЗаменить(СтрДаты, "/", ".");
    СтрДаты = СтрЗаменить(СтрДаты, "-", ".");
    
    // Находим позиции разделителей
    Поз1 = Найти(СтрДаты, ".");
    Если Поз1 = 0 Тогда
        Возврат ПолучитьПустуюДату();
    КонецЕсли;
    
    День = СокрЛП(Лев(СтрДаты, Поз1 - 1));
    ОстатокСтроки = Сред(СтрДаты, Поз1 + 1);
    
    Поз2 = Найти(ОстатокСтроки, ".");
    Если Поз2 = 0 Тогда
        Возврат ПолучитьПустуюДату();
    КонецЕсли;
    
    Месяц = СокрЛП(Лев(ОстатокСтроки, Поз2 - 1));
    Год = СокрЛП(Сред(ОстатокСтроки, Поз2 + 1));
    
    // Дополняем элементы даты ведущими нулями для стандартизации
    Если СтрДлина(День) = 1 Тогда
        День = "0" + День;
    КонецЕсли;
    Если СтрДлина(Месяц) = 1 Тогда
        Месяц = "0" + Месяц;
    КонецЕсли;
    
    // Обрабатываем двузначный год
    Если СтрДлина(Год) = 2 Тогда
        ЧислоГода = Число(Год);
        // Граница столетия (например, все что меньше 60 относится к 2000-м годам)
        Если ЧислоГода < 60 Тогда
            Год = "20" + Год;
        Иначе
            Год = "19" + Год;
        КонецЕсли;
    КонецЕсли;
    
    Попытка
        Возврат Дата(Год, Месяц, День);
    Исключение
        Возврат ПолучитьПустуюДату();
    КонецПопытки;
КонецФункции

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

Решение 4: Безопасное чтение ячеек со служебными ошибками

Еще одна скрытая опасность при чтении файлов Excel напрямую через COM-объект — это наличие в ячейках формульных ошибок (таких как #ЗНАЧ!, #ДЕЛ/0!, #Н/Д). Если ваш код попытается прочитать свойство Value или Value2 у ячейки, содержащей подобную ошибку, выполнение программы 1С 7.7 аварийно прервется. В худшем случае зависнет фоновый процесс EXCEL.EXE, заблокировав файл для чтения.

Чтобы избежать критического сбоя, перед чтением числового значения всегда проверяйте тип ячейки или используйте обращение к текстовому свойству для первичного анализа на наличие символа ошибки:


Тек ТекстЯчейки = СокрЛП(НашЛист.Cells(i,16).Text);
// Если строка начинается со знака ошибки "#", пропускаем чтение значения
Если Лев(ТекстЯчейки, 1) = "#" Тогда
    // Записываем лог или выводим предупреждение пользователю
    Сообщить("В строке " + i + " обнаружена ошибка формулы Excel! Пропуск строки.", "!");
    Продолжить;
КонецЕсли;

Подведем итоги

Мы детально проанализировали причины сбоев при импорте дат и нашли эффективные способы их предотвращения. При работе с интеграцией 1С 7.7 и Excel рекомендуем придерживаться следующих правил:

  1. Всегда держите включенной настройку "Год четырьмя цифрами" в параметрах системы 1С для оперативной диагностики реального состояния дат в документах.
  2. Избегайте жестко закодированных индексов при нарезке строк (таких как Сред(..., 7, 4)). Используйте гибкий поиск разделителей.
  3. Для максимальной надежности и быстродействия преобразуйте даты математическим путем через свойство ячейки Value2.
  4. Если требуется строковое представление, отдавайте предпочтение свойству Text вместо капризного Value.
← На главную