При импорте данных из файлов Microsoft Excel в 1С с помощью объекта ТабличныйДокумент разработчики нередко сталкиваются с ситуацией, когда время 24-часового формата (например, 13:57:12 или 19:28:18) после чтения превращается в 12-часовое значение (1:57:12 или 07:28:18). В результате теряется признак второй половины дня, что приводит к некорректной записи дат и документов.
Разберем подробнее, почему возникает такое поведение платформы, и рассмотрим проверенные способы корректного считывания времени.
Рассмотрим типовой фрагмент кода, в котором проявляется проблема:
ТабДокумент = Новый ТабличныйДокумент();
Попытка
ТабДокумент.Прочитать(тмпИмяФайла, СпособЧтенияЗначенийТабличногоДокумента.Значение);
Исключение
ВызватьИсключение "Ошибка открытия файла Excel";
КонецПопытки;
ВсегоКолонок = ТабДокумент.ШиринаТаблицы;
ВсегоСтрок = ТабДокумент.ВысотаТаблицы;
Для НомерСтроки = 1 По ВсегоСтрок Цикл
Для НомерКолонки = 1 По ВсегоКолонок Цикл
// Ошибка возникает здесь: читается свойство Текст
ЗначениеЯчейки = ТабДокумент.Область(НомерСтроки, НомерКолонки).Текст;
КонецЦикла;
КонецЦикла;
Выясним причину ошибки. При использовании режима СпособЧтенияЗначенийТабличногоДокумента.Значение платформа считывает само типизированное значение в свойство Область.Значение, а в свойство Область.Формат переносит визуальную маску отображения ячейки из Excel. В файлах Excel для времени часто используется шаблон с двенадцатичасовым представлением (hh:mm:ss). Когда код обращается к свойству Область.Текст, 1С накладывает эту маску, из-за чего значение визуально обрезается до 12 часов.
Проанализируем самый правильный и надежный способ. Если файл прочитан в режиме значений, необходимо обращаться напрямую к свойству Значение области ячейки, а затем при необходимости самостоятельно форматировать полученную дату с использованием заглавных букв ЧЧ (24-часовой формат):
Для НомерСтроки = 1 По ВсегоСтрок Цикл
Для НомерКолонки = 1 По ВсегоКолонок Цикл
Ячейка = ТабДокумент.Область(НомерСтроки, НомерКолонки);
Если Ячейка.СодержитЗначение И ЗначениеЗаполнено(Ячейка.Значение) Тогда
Если ТипЗнч(Ячейка.Значение) = Тип("Дата") Тогда
// Форматируем дату в 24-часовой формат
ТекстВремени = Формат(Ячейка.Значение, "ДФ=""дд.ММ.гггг ЧЧ:мм:сс""");
ЗначениеДляЗаписи = Ячейка.Значение;
Иначе
ЗначениеДляЗаписи = Ячейка.Значение;
КонецЕсли;
Иначе
ЗначениеДляЗаписи = СокрЛП(Ячейка.Текст);
КонецЕсли;
КонецЦикла;
КонецЦикла;
Если алгоритм построен на чтении свойства Область.Текст и переписывать логику нежелательно, можно сбросить навязанный Excel формат для всей таблицы сразу после загрузки файла:
ТабДокумент = Новый ТабличныйДокумент();
ТабДокумент.Прочитать(тмпИмяФайла, СпособЧтенияЗначенийТабличногоДокумента.Значение);
// Сбрасываем форматирование для всех ячеек документа
ТабДокумент.Область().Формат = "";
// Теперь свойство Текст будет возвращать стандартное системное представление
Для НомерСтроки = 1 По ВсегоСтрок Цикл
ЗначениеЯчейки = ТабДокумент.Область(НомерСтроки, 1).Текст;
КонецЦикла;
Посмотрим на вариант, когда файл считывается как чистый текст без разбора внутренних типов Excel:
ТабДокумент = Новый ТабличныйДокумент();
ТабДокумент.Прочитать(тмпИмяФайла, СпособЧтенияЗначенийТабличногоДокумента.Текст);
В этом режиме платформа не пытается интерпретировать ячейки как типизированные объекты и читает строки ровно в том виде, как они отображаются в оригинальном файле.
В ряде случаев ячейка со временем без даты может считываться в 1С как дробное число (в Excel время хранится как доля суток от 0 до 1, где 1 час равен 1/24). Разберем, как преобразовать такое число в корректную дату:
Если ТипЗнч(ЗначениеЯчейки) = Тип("Число") Тогда
// Переводим долю суток в секунды (86400 секунд в сутках)
ВсегоСекунд = Окр(ЗначениеЯчейки * 86400);
// Получаем результирующее время
ИтоговаяДата = Дата(1, 1, 1) + ВсегоСекунд;
СтрокаВремени = Формат(ИтоговаяДата, "ДФ=ЧЧ:мм:сс");
КонецЕсли;
Для загрузки больших таблиц Excel без ручного обхода ячеек удобно использовать объект ПостроительЗапроса, который выгружает типизированные данные листа напрямую в таблицу значений:
ТабДокумент = Новый ТабличныйДокумент();
ТабДокумент.Прочитать(тмпИмяФайла, СпособЧтенияЗначенийТабличногоДокумента.Значение);
Построитель = Новый ПостроительЗапроса;
Построитель.ИсточникДанных = Новый ОписаниеИсточникаДанных(ТабДокумент.Область());
Построитель.Выполнить();
ТаблицаДанных = Построитель.Результат.Выгрузить();
Полученная таблица значений будет содержать исходные значения без искажения масками строкового форматирования.