При разработке внешних обработок выгрузки данных, обменов с кассами и пакетного проведения документов разработчики нередко сталкиваются со специфической работой со временем в платформе 1С:Предприятие. Типичные проблемы — необходимость сместить дату назад на фиксированное число суток с установкой нестандартного утреннего времени (например, 08:00:00), а также гарантированно провести документы в конец дня (23:59:59) без их сброса на текущее время. Разберем по шагам, как решить эти задачи правильно, избегая логических ошибок и перезаписи реквизитов платформенными механизмами.
Рассмотрим распространенный сценарий: требуется сформировать период для снятия отчетов с кассовых аппаратов. Конечная дата должна указывать на конец текущего дня (23:59:59), а начальная дата — на предыдущий день строго в 08:00:00.
В платформе 1С дата хранится с точностью до секунды, а арифметические операции сложения и вычитания с датой производятся в секундах. Один день содержит 86400 секунд (24 * 60 * 60), а 8 часов — 28800 секунд (8 * 60 * 60).
Если разработчик просто вычитает часы из текущей даты без обнуления секунд или неправильно комбинирует методы, время может сброситься в полночь (00:00:00) или остаться на текущих сутках. Проанализируем корректное решение с использованием математики секунд:
// Сначала сдвигаем текущую дату на 1 день назад (86400 сек),
// затем обрезаем время до 00:00:00 через НачалоДня
// и прибавляем ровно 8 часов (8 * 60 * 60 сек)
ДатаНач = НачалоДня(ТекущаяДата() - 86400) + 8 * 60 * 60;
ДатаКон = КонецДня(ТекущаяДата());
Если необходимо отнимать произвольное количество дней, используем универсальную формулу с множителем:
КолВоДней = 1;
ДатаНач = НачалоДня(ТекущаяДата() - 86400 * КолВоДней) + 8 * 60 * 60;
ДатаКон = КонецДня(ТекущаяДата());
Выясним еще один надежный способ, который исключает ошибки при ручном подсчете секунд — использование конструктора объекта Дата. Разберем этот вариант:
// Получаем расчетную дату за минусом нужного количества дней
ТекДата = НачалоДня(ТекущаяДата() - 86400);
// Собираем точную дату через конструктор: Год, Месяц, День, Час, Минута, Секунда
ДатаНач = Дата(Год(ТекДата), Месяц(ТекДата), День(ТекДата), 8, 0, 0);
ДатаКон = КонецДня(ТекущаяДата());
Обратите внимание: если кассы или рабочие места находятся в разных часовых поясах, вместо функции ТекущаяДата(), возвращающей время сервера, рекомендуется применять ТекущаяДатаСеанса().
Вторая проблема заключается в том, что при пакетном проведении документов (например, кассовых отчетов) время проведения может самопроизвольно устанавливаться в текущее системное время вместо конца дня 23:59:59, нарушая последовательность партионного учета.
Разберем типичную ошибку в обработчике проведения:
Для Каждого СтрокаДок Из ТаблицаДокументов Цикл
Если СтрокаДок.Пометка Тогда
ДокументОбъект = СтрокаДок.Документ.ПолучитьОбъект();
Если ДокументОбъект <> Неопределено И НЕ СтрокаДок.ПометкаУдаления Тогда
Попытка
// Ошибка: при вызове без параметров платформа может переопределить время
ДокументОбъект.Записать(РежимЗаписиДокумента.Проведение);
СтрокаДок.Пометка = Ложь;
Исключение
КонецПопытки;
КонецЕсли;
КонецЕсли;
КонецЦикла;
Посмотрим на причины, почему время документа сбрасывается или не встает в 23:59:59:
Записать() без явного указания режима авто-времени применяет свойства метаданных документа (по умолчанию — текущее время или время последним в дне). Чтобы принудительно зафиксировать назначенное время, необходимо явно передавать РежимАвтоВремя.НеИспользовать.Дата, а затем провести повторно.Проанализируем правильный алгоритм пакетной установки времени и проведения:
Для Каждого СтрокаДок Из ТаблицаДокументов Цикл
Если СтрокаДок.Пометка Тогда
ДокументОбъект = СтрокаДок.Документ.ПолучитьОбъект();
Если ДокументОбъект <> Неопределено И НЕ СтрокаДок.ПометкаУдаления Тогда
Попытка
// 1. Устанавливаем время на конец дня
ДокументОбъект.Дата = КонецДня(ДокументОбъект.Дата);
// 2. Если документ проведен, отменяем проведение перед сменой времени
Если ДокументОбъект.Проведен Тогда
ДокументОбъект.Записать(РежимЗаписиДокумента.ОтменаПроведения);
КонецЕсли;
// 3. Проводим документ неоперативно без авто-времени
ДокументОбъект.Записать(РежимЗаписиДокумента.Проведение, РежимАвтоВремя.НеИспользовать, РежимПроведенияДокумента.Неоперативный);
СтрокаДок.Пометка = Ложь;
Исключение
Сообщить("Ошибка проведения документа: " + ОписаниеОшибки());
КонецПопытки;
КонецЕсли;
КонецЕсли;
КонецЦикла;
При автоматическом заполнении нескольких документов на один день часто используют смещение + 1 секунда от предыдущего документа. Рассмотрим критический риск: если предыдущий документ уже имел время 23:59:59, операция Таб[0].Дата + 1 переместит новый документ на 00:00:00 следующих суток. Это приведет к попаданию документа в чужой учетный период.
Для предотвращения перехода через полночь применяйте проверку границ дня:
НоваяДата = Таб[0].Дата + 1;
Если КонецДня(НоваяДата) <> КонецДня(ДатаДокумента) Тогда
// Если вышли за границы текущего дня, удерживаем время на 23:59:59
ДокОкс.Дата = КонецДня(ДатаДокумента);
Иначе
ДокОкс.Дата = НоваяДата;
КонецЕсли;
Соблюдение правил явного отключения авто-времени и контроль переполнения суток обеспечивают корректное формирование кассовых документов и целостность партионного учета.