При разработке конфигураций в платформе 1С:Предприятие 8 программисты часто сталкиваются с необходимостью работы с типом Дата. Этот тип данных по своей природе всегда содержит и календарную дату, и точное время с точностью до секунды. Однако в бизнес-задачах часто требуется сравнить только даты, игнорируя часовые и минутные показатели, например, для формирования отчетов по периодам или фильтрации документов.

Если просто присвоить одну переменную другой, временная составляющая сохранится, что может привести к логическим ошибкам при сравнении или группировке данных. Существует несколько надежных способов «обрезать» время, оставив только дату. Выбор конкретного метода зависит от версии платформы, контекста задачи и требований к производительности кода.

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

Метод НачалоДня: стандартный подход платформы

Самым надежным и рекомендуемым разработчиками 1С способом получения даты без времени является использование встроенной функции НачалоДня(). Эта функция принимает значение типа Дата и возвращает новую дату, у которой время установлено в 00:00:00. Она работает предсказуемо на любых версиях платформы и не требует дополнительных вычислений.

Использование этой функции делает код читаемым и понятным для других разработчиков. Когда вы видите НачалоДня(ДатаДокумента), сразу становится ясно, что программист намеренно отбрасывает время. Это соответствует стандартам разработки и упрощает поддержку конфигурации в будущем.

Функция корректно обрабатывает переходы через полночь и не зависит от системных настроек часового пояса в том виде, в котором это делает работа с таймерами. Результат всегда будет строго началом суток указанной даты.

⚠️ Внимание: Функция НачалоДня возвращает значение типа Дата, а не Строка. Если вам нужно отобразить дату в отчете без времени, форматирование следует выполнять отдельно через функцию Формат().
💡

Всегда используйте НачалоДня() при формировании периодов для отчетов, чтобы избежать дублирования записей из-за разного времени создания документов.

Пример использования функции в коде выглядит следующим образом:

ДатаСВременем = ТекущаяДата();

ДатаБезВремени = НачалоДня(ДатаСВременем);

Сообщить(ДатаБезВремени); // Выведет дату вида 25.10.2023 0:00:00

Такой подход гарантирует, что даже если исходная дата имела время 23:59:59, результат будет сброшен к началу суток. Это критически важно при сравнении дат в условиях запросов или операторов Если.

Использование функции Час для обнуления времени

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

Этот метод требует больше строк кода и выглядит громоздко по сравнению с НачалоДня(). Однако он может быть полезен в ситуациях, когда нужно не просто обнулить время, а изменить его на конкретное значение, например, установить 12:00:00 для усреднения.

Для извлечения компонентов используются функции Год(), Месяц() и День(). Затем эти значения передаются в конструктор Дата(), где последние три аргумента (часы, минуты, секунды) задаются явно как ноль.

  • 📅 Функция Год(Дата) возвращает числовое значение года.
  • 📅 Функция Месяц(Дата) возвращает номер месяца от 1 до 12.
  • 📅 Функция День(Дата) возвращает номер дня в месяце.

Код реализации этого подхода будет выглядеть так:

ИсходнаяДата = ТекущаяДата();

НоваяДата = Дата(Год(ИсходнаяДата), Месяц(ИсходнаяДата), День(ИсходнаяДата), 0, 0, 0);

Хотя результат будет идентичен использованию НачалоДня(), читаемость такого кода ниже. Разработчику приходится анализировать каждый аргумент конструктора, чтобы понять суть операции.

📊 Какой метод получения даты без времени вы используете чаще?
НачалоДня()
Конструктор Дата()
Математическое вычитание
Форматирование строки

Математические операции с типом Дата

В языке 1С тип Дата поддерживает арифметические операции. Дату можно представлять как количество секунд, прошедших с некоторой эпохи. Зная это, можно попытаться обнулить время путем вычисления остатка от деления или вычитания прошедших секунд.

В сутках содержится 86400 секунд (24 часа × 60 минут × 60 секунд). Если мы возьмем полное количество секунд в дате и найдем остаток от деления на 86400, мы получим количество секунд, прошедших с начала текущих суток. Вычтя это значение из исходной даты, мы получим начало дня.

Однако этот метод считается «плохим тоном» в современной разработке 1С. Он менее производителен, так как требует дополнительных вычислений, и менее понятен при чтении кода. Кроме того, он может вести себя некорректно при переходе через високосные секунды или в специфических часовых поясах.

⚠️ Внимание: Избегайте математических трюков с датами в высоконагруженных системах. Лишние вычисления секунд могут замедлить обработку больших массивов данных в циклах.

Тем не менее, понимание этого механизма полезно для отладки. Пример реализации через вычисление секунд:

СекундВДне = 86400;

ВремяВСекундах = Время(Час(Дата), Минута(Дата), Секунда(Дата));

// Вычитаем время, приведенное к секундам, из даты

ДатаБезВремени = Дата - ВремяВСекундах;

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

Сравнение дат и проблемы точности

Одной из самых частых ошибок при работе с датами является попытка сравнить две даты, у одной из которых время обнулено, а у другой — нет. Если вы используете операторы сравнения =, < или >, платформа будет учитывать каждую секунду.

Например, дата 25.10.2023 00:00:00 не равна дате 25.10.2023 10:30:00, хотя визуально для пользователя это один и тот же день. В отчетах это может привести к тому, что документы, созданные в течение дня, не попадут в выборку, если условие написано неверно.

Для корректного сравнения необходимо приводить обе сравниваемые величины к единому формату. Лучше всего использовать НачалоДня() для обеих переменных перед сравнением. Это гарантирует, что сравнение будет происходить строго по календарным суткам.

Ситуация Дата 1 Дата 2 Результат сравнения (=)
Без обработки 25.10.2023 00:00:00 25.10.2023 15:00:00 Ложь
С НачалоДня НачалоДня(25.10...) НачалоДня(25.10...) Истина
Разные дни 25.10.2023 23:59:59 26.10.2023 00:00:01 Ложь
Граница суток НачалоДня(25.10...) НачалоДня(26.10...) Ложь

Особое внимание стоит уделить диапазонам дат. Если вы формируете период «с» и «по», для даты «по» часто используют функцию КонецДня() или добавляют один день к началу следующего периода и используют знак «меньше».

💡

При сравнении дат всегда приводите их к началу дня с помощью НачалоДня(), иначе сравнение будет учитывать время и даст неверный результат.

Работа с датами в запросах 1С

В языке запросов 1С также существует возможность работы с датами без времени. Однако синтаксис отличается от встроенного языка. В запросах часто используется приведение типов или специальные функции, доступные в конкретной версии платформы.

Если вы передаете параметр в запрос, лучше всего подготовить его на стороне встроенного языка перед выполнением запроса. Это снижает нагрузку на сервер баз данных и упрощает логику выборки. Передавайте в запрос уже «очищенную» дату.

В тексте запроса можно использовать конструкцию НАЧАЛОДНЯ(), если СУБД и версия платформы это поддерживают напрямую в выражениях. Но наиболее универсальный способ — использование параметров.

Запрос = Новый Запрос;

Запрос.Текст = "ВЫБРАТЬ Документ.Ссылка

| ИЗ Документ.РеализацияТоваровУслуг КАК Документ

| ГДЕ НачалоДня(Документ.Дата) = &Период";

Запрос.УстановитьПараметр("Период", НачалоДня(ВыбраннаяДата));

Результат = Запрос.Выполнить();

Такой подход обеспечивает максимальную совместимость и производительность. Сервер 1С сам оптимизирует выполнение запроса, используя индексы по полю Дата, если они построены корректно.

⚠️ Внимание: Функции в условии ГДЕ запроса (например, НАЧАЛОДНЯ(Документ.Дата)) могут препятствовать использованию индексов, что замедлит работу на больших объемах данных. Лучше сравнивать диапазоном: Документ.Дата >= &Начало И Документ.Дата < &Конец.
Почему индексы не работают с функциями?

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

Форматирование даты для вывода пользователю

Часто задача «получить дату без времени» возникает не для вычислений, а для отображения в печатных формах или интерфейсе. В этом случае не обязательно менять само значение переменной. Достаточно изменить формат строки представления.

Для этого используется функция Формат(). Она позволяет задать шаблон вывода, в котором можно указать, что нужно показывать только день, месяц и год. При этом внутреннее значение переменной останется типом Дата со временем, что удобно для дальнейших расчетов.

Строка формата выглядит как "ДФ='dd.MM.yyyy'". Буквы ДФ означают «Дата Формат», а последующие символы задают порядок вывода компонентов. Это стандартный подход для отчетов и печатных форм.

  • 🖨 dd — день месяца с ведущим нулем (01, 02...).
  • 🖨 MM — номер месяца с ведущим нулем (01, 12...).
  • 🖨 yyyy — год четырехзначным числом.

Пример кода для подготовки строки к выводу:

ТекущаяДата = ТекущаяДата();

СтрокаДаты = Формат(ТекущаяДата, "ДФ='dd.MM.yyyy'");

Сообщить(СтрокаДаты); // Выведет "25.10.2023" как строку

Помните, что результат функции Формат — это тип Строка. С ней нельзя выполнять арифметические операции или сравнивать её с датами как с датами. Используйте этот метод только для финального отображения.

☑️ Проверка перед внедрением

Выполнено: 0 / 4

Частые ошибки и рекомендации

Новички часто пытаются преобразовать дату в строку, обрезать лишние символы и снова преобразовать в дату. Это крайне неэффективный путь, который приводит к ошибкам парсинга и зависимостям от региональных настроек пользователя.

Еще одна ошибка — игнорирование часовых поясов при работе с веб-сервисами или файловыми версиями. Время может сдвигаться при сохранении и загрузке данных. Всегда проверяйте, в каком часовом поясе хранится дата в базе.

Используйте типизированные переменные. Не храните даты в строковых полях базы данных, если планируете по ним делать отборы. Это лишает вас преимуществ индексации и скорости работы СУБД.

В чем разница между НачалоДня и КонецДня?

Функция НачалоДня() устанавливает время в 00:00:00 выбранной даты. Функция КонецДня() устанавливает время в 23:59:59 той же даты. Они часто используются в паре для формирования диапазона периода: от начала одного дня до конца другого.

Что вернет функция, если передать ей строку?

Функции работы с датой (НачалоДня, Год и др.) ожидают на входе тип Дата. Если передать строку, возникнет ошибка выполнения. Сначала необходимо преобразовать строку в дату функцией Дата() или Попытка...Исключение.

Как получить вчерашнюю дату без времени?

Комбинируйте вычитание дней и функцию начала суток: НачалоДня(ТекущаяДата() - 1). Сначала отнимается один день (вместе со временем), затем результат округляется до начала полученных суток.

Можно ли хранить дату без времени в базе данных?

В таблицах базы данных 1С тип поля всегда Дата, который физически хранит и время. Невозможно создать поле, которое хранит только дату. Обнуление времени происходит программно при чтении или записи данных.

Влияет ли летнее время на работу функций даты?

В современных версиях платформы 1С работа с датами учитывает переходы на летнее/зимнее время автоматически, если на сервере настроены корректные часовые пояса. Функция НачалоДня всегда вернет локальное начало суток для указанного момента.