При разработке обработок по загрузке данных из внешних файлов, таких как Excel, программисты часто сталкиваются с проблемой несовместимости типов данных. Одной из самых распространенных задач является корректный перенос даты. В этой статье мы подробно разберем, почему возникают ошибки при заполнении даты, и рассмотрим несколько способов решения этой задачи: от простых до универсальных.
Разберем типичную ситуацию: вы читаете файл Excel, используя объект ТабличныйДокумент или COM-соединение, и пытаетесь записать значение в реквизит документа с типом Дата. Если вы используете свойство ТекущаяОбласть.Текст, то 1С получает строковое представление (например, "01.05.2023").
Проблема заключается в том, что тип данных Строка и тип данных Дата в 1С — это разные сущности. 1С не всегда может автоматически преобразовать строку в дату, особенно если формат строки не соответствует внутреннему стандарту (ГГГГММДДЧЧММСС). Если в табличной части вашей обработки колонка имеет тип Дата, а вы пытаетесь записать туда строку, значение просто не примется и останется пустым. Если же колонка строковая, то при попытке записать эту строку в реальный документ 1С выдаст ошибку "Поле 'Дата' не может быть пустым", так как объект документа ожидает именно дату.
Самый быстрый способ — это явное преобразование строки в дату с помощью встроенной функции 1С. Однако важно помнить, что функция Дата() ожидает строку в определенном формате или наличие времени. Проанализируем пример, предложенный в обсуждении:
// Предположим, в переменной ТекстИзЭксель содержится "25.12.2022"
СтрокаДанных.Дата = Дата(ТабДок.ПолучитьОбласть("R" + НомерСтроки + "C1").ТекущаяОбласть.Текст + " 00:00:00");
Добавляя " 00:00:00", мы помогаем платформе распознать строку как дату. Рассмотрим, как это выглядит в контексте цикла обхода строк Excel:
Для НомерСтроки = 2 По КоличествоСтрок Цикл
СтрокаДанных = Объект.ДанныеФайла.Добавить();
// Получаем текст из ячейки и преобразуем его
СчитанныйТекст = ТабДок.ПолучитьОбласть("R" + Формат(НомерСтроки, "ЧГ=0") + "C" + 1).ТекущаяОбласть.Текст;
Попытка
СтрокаДанных.Дата = Дата(СчитанныйТекст + " 00:00:00");
Исключение
Сообщить("В строке " + НомерСтроки + " некорректный формат даты!");
СтрокаДанных.Дата = '00010101'; // Пустая дата
КонецПопытки;
СтрокаДанных.НомерТТН = ТабДок.ПолучитьОбласть("R" + Формат(НомерСтроки, "ЧГ=0") + "C" + 2).ТекущаяОбласть.Текст;
СтрокаДанных.Сумма = ТабДок.ПолучитьОбласть("R" + Формат(НомерСтроки, "ЧГ=0") + "C" + 3).ТекущаяОбласть.Текст;
КонецЦикла;
Важный нюанс: использование свойства ТекущаяОбласть.Текст возвращает строку именно в том виде, в котором она отображается в Excel. Если в Excel настроен формат ячейки "01-Май-23", конструктор Дата() выдаст ошибку. В таких случаях лучше использовать ТекущаяОбласть.Значение.
Если файл Excel читается через ТабличныйДокумент, мы можем попробовать получить значение сразу в типе Дата, минуя строковые преобразования. Платформа 1С при чтении файла пытается сопоставить типы ячеек Excel с типами 1С.
Рассмотрим вариант кода с использованием свойства Значение:
// Вместо .Текст используем .Значение
ЗначениеЯчейки = ТабДок.ПолучитьОбласть("R" + НомерСтроки + "C1").ТекущаяОбласть.Значение;
Если ТипЗнч(ЗначениеЯчейки) = Тип("Дата") Тогда
СтрокаДанных.Дата = ЗначениеЯчейки;
Иначе
// Если 1С не распознала дату, пробуем преобразовать текст
ТекстЯчейки = ТабДок.ПолучитьОбласть("R" + НомерСтроки + "C1").ТекущаяОбласть.Текст;
// Здесь применяем логику преобразования из Способа 1
КонецЕсли;
Иногда дата в файле может приходить в самых разных форматах: с разделителями точками, слешами или дефисами. Для таких случаев разработаем и проанализируем функцию, которая "вытаскивает" числа из строки и собирает из них дату.
Рассмотрим пример функции, которая справляется со сложными случаями:
Функция ПреобразоватьВДату(ИсхСтр)
Стр = СокрЛП(ИсхСтр);
// Ищем разделители
МассивЧастей = СтрРазделить(Стр, ".,/-", Ложь);
Если МассивЧастей.Количество() < 3 Тогда
Возврат '00010101'; // Недостаточно данных для даты
КонецЕсли;
// Извлекаем день, месяц, год (предполагаем формат ДД ММ ГГГГ)
День = Число(МассивЧастей[0]);
Месяц = Число(МассивЧастей[1]);
Год = Число(МассивЧастей[2]);
// Обработка двухзначного года (например, 23 -> 2023)
Если Год < 100 Тогда
Год = 2000 + Год;
КонецЕсли;
Попытка
Возврат Дата(Год, Месяц, День);
Исключение
Возврат '00010101';
КонецПопытки;
КонецФункции
Эта функция гораздо надежнее, так как она не зависит от того, какой разделитель использовал пользователь в Excel. Мы просто разбиваем строку на части и работаем с числами.
Если вы используете Excel.Application для чтения файла, помните, что Excel хранит даты как числа (количество дней с начала прошлого века). Выясним, как правильно обработать такое значение. Если 1С получает число (например, 44927), его нужно конвертировать следующим образом:
// Формула преобразования числа Excel в дату 1С
ЧислоИзExcel = ExcelЯчейка.Value;
Дата1С = Дата(1899, 12, 30) + (ЧислоИзExcel * 86400);
Здесь 86400 — это количество секунд в сутках. Это знание поможет вам, если стандартные методы 1С по какой-то причине не распознают формат ячейки Excel.
Чтобы ваша загрузка работала стабильно, придерживайтесь следующих правил:
ЗначениеЗаполнено(Объект.Дата) возвращает Истина.ОбщегоНазначения. Там часто есть готовые функции типа СтрокаВДату(), которые уже учитывают множество нюансов.СокрЛП(), чтобы убрать лишние пробелы, которые могут привести к ошибке конструктора Дата().Проанализировав все способы, мы видим, что наиболее надежным методом для начинающего является сочетание получения значения ячейки и резервного преобразования через очищенную строку с добавлением времени. Это гарантирует, что ваш документ "Поступление товаров" всегда будет иметь корректно заполненную дату.