При разработке в среде «1С:Предприятие 8» программисты, особенно начинающие, часто сталкиваются с задачей хранения или сопоставления дат без учета времени. Типичная ситуация: в коде пишется конструкция, которая должна «отсечь» время, но при попытке записать полученный результат в реквизит или переменную система либо выдает ошибку, либо просто не изменяет значение. Проанализируем, почему так происходит, и разберем правильные методы решения этой задачи.
Рассмотрим код, который изначально пытался использовать автор темы:
Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
ДатаБезВремени = Формат(Дата, "ДФ=dd.MM.yyyy");
ДатаТренДок = ДатаБезВремени;
КонецПроцедуры
На первый взгляд логика понятна: разработчик берет дату, применяет к ней форматную строку "ДФ=dd.MM.yyyy", чтобы получить привычный вид без часов и секунд (например, "15.07.2026"), а затем пытается записать этот результат в переменную ДатаТренДок. Однако эта схема не работает.
Главная причина ошибки кроется в несовпадении типов данных. В платформе 1С реквизиты и переменные имеют строгую типизацию (или ожидают определенный тип данных при заполнении реквизитов БД). Давайте разберем, что происходит «под капотом»:
Формат() всегда возвращает значение типа Строка. Она предназначена исключительно для визуального представления данных пользователю в интерфейсе или вывода в печатные формы. Она физически не способна изменить или обрезать саму дату.ДатаТренДок на форме или в метаданных имеет тип Дата.Для наглядности вспомним аналогичный пример автора, который у него успешно работал:
&НаСервере
Процедура ПриОткрытииНаСервере()
ДеньПрописью = Формат(Объект.Дата, "ДФ=дддд");
Объект.ДеньНедели = ДеньПрописью;
КонецПроцедуры
Почему этот код работал? Всё просто: реквизит Объект.ДеньНедели изначально имел тип Строка. Ему без проблем присваивалось строковое значение ("понедельник", "вторник" и т. д.), возвращенное функцией Формат(). В случае же с датой мы имеем совершенно другую картину.
Ниже мы подробно разберем, как правильно решить эту проблему на уровне программного кода и метаданных конфигурации.
В платформе «1С:Предприятие» физически не существует обособленного типа данных «Дата без времени». Любая переменная типа Дата всегда хранит в себе и дату, и время с точностью до секунды. Когда нам требуется сохранить «чистую дату», в системе это реализуется путем обнуления времени — то есть установки его в значение 00:00:00.
Для того чтобы быстро и корректно привести любую дату к началу дня (обнулить время), используется встроенная функция НачалоДня(). Она принимает на вход исходную дату, обнуляет время и возвращает значение, которое по-прежнему имеет тип Дата. Это позволяет без ошибок записывать результат в любые типизированные реквизиты.
Перепишем исходный код правильно:
Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
// Функция НачалоДня обнуляет время, сохраняя тип "Дата"
ДатаТренДок = НачалоДня(Дата);
КонецПроцедуры
После выполнения этой строки в реквизите ДатаТренДок будет лежать полноценная дата (например, 15.07.2026 00:00:00), которая прекрасно подходит для дальнейших расчетов, проведения документов и построения отчетов.
Если ДатаТренДок является полноценным реквизитом объекта (документа, справочника или части формы), мы можем переложить задачу очистки времени на саму платформу 1С. Для этого выполним следующие действия:
ДатаТренДок.После этого платформа 1С автоматически начнет «отсекать» время (приводить его к 00:00:00) при записи объекта в базу данных. В коде вам больше не потребуется вручную прописывать вызовы функции НачалоДня() для этого реквизита.
В ходе обсуждения у автора темы возникла идея: «Хотя может и строка подойдёт, если я потом буду просто две строки сравнивать...». Это критическая архитектурная ошибка! Настоятельно рекомендуем никогда так не делать по трем важным причинам:
"ДД.ММ.ГГГГ", то при сравнении строка "31.01.2023" окажется больше, чем строка "01.02.2024", потому что первый символ "3" больше, чем "0". Ваша логика проверок дат полностью сломается. Сравнивать строки дат корректно можно только в каноническом формате "ГГГГММДД" (например, "20240201" > "20230131"), но использовать строковые манипуляции в коде вместо работы со специализированным типом данных — это признак плохого тона в разработке.
Поскольку аналитика в 1С строится преимущественно с помощью запросов, важно знать, как обрабатывать даты без времени внутри самого текста запроса. Обратите внимание, что стандартная функция встроенного языка НачалоДня() в запросах не поддерживается.
Вместо нее в языке запросов 1С используется специальная функция НАЧАЛОПЕРИОДА(). Проанализируем пример запроса, который выбирает продажи и группирует их строго по дням, полностью игнорируя время проведения документов:
ВЫБРАТЬ
НАЧАЛОПЕРИОДА(Продажи.Период, ДЕНЬ) КАК ДеньПродажи,
СУММА(Продажи.Сумма) КАК Сумма
ИЗ
РегистрНакопления.Продажи КАК Продажи
СГРУППИРОВАТЬ ПО
НАЧАЛОПЕРИОДА(Продажи.Период, ДЕНЬ)
Такой подход гарантирует высокую скорость выполнения запроса на уровне базы данных и обеспечивает корректность группировок для любых отчетов.
При построении отчетов или выборок за определенный период (например, при получении документов с Даты А по Дату Б), разработчики часто совершают еще одну популярную ошибку, забывая про время:
НачалоДня(ДатаНачала) (установит время в 00:00:00).КонецДня(ДатаОкончания) (это установит время в 23:59:59).Если вы не приведете конечную дату к концу дня, то все документы, созданные в последний день периода (например, в 14:30:00), гарантированно не попадут в ваш отчет. Система будет сравнивать их с началом этого дня (00:00:00) и посчитает, что они находятся за рамками указанного интервала.
Если вам необходимо жестко задать или сконструировать конкретную дату без времени непосредственно в коде программы, используйте следующие проверенные конструкции:
Способ А. Использование литералов дат (прямой ввод в коде):
// Дата задается в формате 'ГГГГММДД'. Время автоматически будет 00:00:00
МояДата = '20260715';
Способ Б. Использование конструктора даты:
// Передаем параметры в формате: Дата(Год, Месяц, День)
МояДата = Дата(2026, 07, 15);
Способ В. Преобразование строго заданной строки:
// Преобразуем строку канонического формата в полноценную дату
МояДата = Дата("20260715000000");
Подводя итог: всегда разделяйте понятия значения данных и их представления. Для записи данных в базу используйте тип Дата в связке с функцией НачалоДня(), а функцию Формат() оставьте исключительно для вывода красивого текста на экраны пользователей.