Работа с датами в запросах 1С — одна из самых частых задач при разработке отчетов, обработок и интеграций. Казалось бы, что может быть проще, чем получить текущую дату? Однако даже здесь есть нюансы: разные версии платформы, особенности СУБД (PostgreSQL, MS SQL, файловая база) и контекст выполнения запроса могут влиять на результат. Новички часто допускают ошибки, используя не те функции или забывая про параметры, что приводит к некорректной фильтрации данных.

В этой статье мы разберем все актуальные способы получения текущей даты в запросах 1С:Предприятие 8.3, включая редкие случаи, когда стандартные методы не работают. Вы узнаете, чем отличается ТекущаяДата() от Дата(), как передавать дату через параметры и почему иногда лучше использовать виртуальные таблицы. Материал будет полезен как начинающим разработчикам, так и опытным программистам, столкнувшимся с неочевидными багами.

📊 Как часто вы работаете с датами в запросах 1С?
Ежедневно
Несколько раз в неделю
Редко
Никогда

1. Стандартная функция ТекущаяДата() — простой, но не всегда безопасный способ

Самый очевидный метод — использовать встроенную функцию ТекущаяДата() прямо в тексте запроса. Она возвращает текущие дату и время на сервере в момент выполнения запроса. Пример:

ВЫБРАТЬ

ТекущаяДата() КАК ТекущаяДатаСервера

На первый взгляд, все просто. Но здесь кроются два подводных камня:

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

Чтобы избежать проблем с кэшированием, рекомендуется явно указывать параметр РАЗРЕШИТЬ КЭШИРОВАНИЕ = ЛОЖЬ в настройках запроса. Пример:

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

Запрос.Текст =

"ВЫБРАТЬ

| ТекущаяДата() КАК ТекущаяДата

|ИЗ

| Справочник.Номенклатура КАК Номенклатура

|ГДЕ

| Номенклатура.ДатаСоздания > ТекущаяДата() - 30";

Запрос.УстановитьПараметр("Кэшировать", Ложь); // Отключаем кэширование

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

💡

Если вам нужно получить дату без времени (только дату), используйте конструкцию НАЧАЛОДНЯ(ТекущаяДата()). Это избавит от проблем с сравнением дат, где время может мешать точной фильтрации.

2. Функция Дата() — когда нужна конкретная дата, а не "сейчас"

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

ВЫБРАТЬ

Дата(Год(ТекущаяДата()), Месяц(ТекущаяДата()), День(ТекущаяДата())) КАК СегодняБезВремени

Такой подход полезен, когда:

  • 📅 Нужно сравнивать даты без учета времени (например, для фильтрации документов "за сегодня").
  • ⏱️ Требуется "обнулить" время, чтобы избежать погрешностей при сравнении с датами из справочников, где время может быть 00:00:00.
  • 🔄 Необходимо гарантированно получить дату на начало дня, независимо от текущего времени.

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

Что будет, если передать несуществующую дату в функцию Дата()?

При передаче некорректных значений (например, Дата(2023, 2, 30) для 30 февраля) запрос завершится с ошибкой:

Ошибка при вызове метода контекста (Дата): Неверная дата.

В отличие от встроенного языка 1С, где некорректная дата преобразуется в Дата(1,1,1), в запросах это приводит к исключению.

3. Передача текущей даты через параметры — лучший способ для сложных запросов

Опытные разработчики предпочитают передавать текущую дату в запрос через параметры. Это дает несколько преимуществ:

  1. Прозрачность кода. Видно, какие данные передаются в запрос, что упрощает отладку.
  2. 🔄 Гибкость. Легко заменить текущую дату на любую другую без изменения текста запроса.
  3. 🛡️ Защита от кэширования. Параметры не кэшируются, в отличие от функций внутри запроса.

Пример передачи текущей даты через параметр:

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

Запрос.Текст =

"ВЫБРАТЬ

| Документ.ЗаказКлиента.Ссылка КАК Ссылка,

| Документ.ЗаказКлиента.Дата КАК ДатаЗаказа

|ИЗ

| Документ.ЗаказКлиента КАК Документ.ЗаказКлиента

|ГДЕ

| Документ.ЗаказКлиента.Дата >= &ТекущаяДата";

Запрос.УстановитьПараметр("ТекущаяДата", ТекущаяДата());

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

Такой подход особенно важен в следующих сценариях:

  • 📊 Отчеты с динамическими периодами, где пользователь может выбрать произвольную дату вместо "сегодня".
  • 🔄 Фоновые задания, где время выполнения запроса может отличаться от времени формирования задачи.
  • 🌍 Распределенные базы, где серверное время на разных узлах может расходиться.

Убедитесь, что параметр имеет корректный тип (Дата, а не Строка)

Проверьте часовой пояс сервера и клиента при работе с распределенными базами

Отключите кэширование, если запрос выполняется многократно с разными параметрами

Используйте именованные параметры (&Имя) вместо позиционных (?), чтобы избежать путаницы-->

4. Использование виртуальных таблиц — альтернатива для отчетов

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

Пример:

ВЫБРАТЬ

ОстаткиТоваровОстатки.Номенклатура КАК Номенклатура,

ОстаткиТоваровОстатки.КоличествоОстаток КАК Остаток

ИЗ

РегистрНакопления.ОстаткиТоваров.Остатки(

&ТекущаяДата,

Номенклатура В (

ВЫБРАТЬ

Справочник.Номенклатура.Ссылка

ИЗ

Справочник.Номенклатура

ГДЕ

Справочник.Номенклатура.ЭтоГруппа = ЛОЖЬ

)

) КАК ОстаткиТоваровОстатки

Преимущества этого подхода:

  • 📈 Автоматическое обновление. Виртуальные таблицы всегда возвращают актуальные данные на момент выполнения.
  • 🔍 Упрощение кода. Не нужно писать сложные соединения (JOIN) для получения остатков.
  • 🛠️ Поддержка платформой. Виртуальные таблицы оптимизированы и работают быстрее, чем ручные запросы к регистрам.

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

💡

Виртуальные таблицы — самый эффективный способ работы с остатками и оборотами на текущую дату, но они доступны только в клиент-серверном варианте 1С.

5. Особенности работы с разными СУБД: MS SQL vs PostgreSQL vs файловая база

Поведение функций даты в запросах может отличаться в зависимости от используемой СУБД. Рассмотрим ключевые различия:

СУБД Функция ТекущаяДата() Часовой пояс Особенности
MS SQL Server Использует GETDATE() Серверное время Поддерживает виртуальные таблицы, высокая производительность
PostgreSQL Использует CURRENT_TIMESTAMP Настраивается в конфигурации сервера Может требовать явного приведения типов в сложных запросах
Файловая база Встроенная функция 1С Локальное время компьютера Нет поддержки виртуальных таблиц, медленнее при больших объемах данных

Например, в PostgreSQL иногда возникают проблемы с неявным приведением типов. Если вы получаете ошибку вида Ошибка оператора: operator does not exist: timestamp without time zone = date, явно преобразуйте типы:

ВЫБРАТЬ

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

ИЗ

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

ГДЕ

ДАТАВРЕМЯ(Документ.РеализацияТоваровУслуг.Дата, "00:00:00") = ДАТАВРЕМЯ(&ТекущаяДата, "00:00:00")

Для MS SQL аналогичная проблема решается проще:

ВЫБРАТЬ

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

ИЗ

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

ГДЕ

CONVERT(DATE, Документ.РеализацияТоваровУслуг.Дата) = CONVERT(DATE, &ТекущаяДата)

💡

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

6. Распространенные ошибки и как их избежать

Даже опытные разработчики иногда допускают ошибки при работе с датами в запросах. Вот TOP-5 проблем и способы их решения:

  1. Сравнение даты с временем и без времени

    Ошибка: ГДЕ ДатаДокумента = ТекущаяДата() не сработает, если в ДатаДокумента есть время (например, 10.05.2023 14:30:00), а ТекущаяДата() возвращает 10.05.2023 15:45:22.

    Решение: Используйте НАЧАЛОДНЯ() для обеих сторон сравнения:

    ГДЕ НАЧАЛОДНЯ(ДатаДокумента) = НАЧАЛОДНЯ(ТекущаяДата())
  2. Игнорирование часовых поясов

    Ошибка: В распределенной базе сервер и клиент находятся в разных часовых поясах, из-за чего ТекущаяДата() возвращает неожидаемое значение.

    Решение: Явно передавайте дату через параметры или настройте синхронизацию времени на серверах.

  3. Кэширование запросов с ТекущаяДата()

    Ошибка: Запрос с ТекущаяДата() кэшируется, и при повторном выполнении возвращает устаревшую дату.

    Решение: Отключите кэширование или используйте параметры.

Еще одна типичная ошибка — попытка использовать функции даты в ПОЛНОЕ СОЕДИНЕНИЕ (FULL JOIN) или других сложных конструкциях, где может некорректно обработать контекст. В таких случаях лучше разбить запрос на несколько простых частей.

Почему иногда ТекущаяДата() возвращает вчерашнюю дату?

Это может происходить в двух случаях:

1. Запрос выполняется в фоновом задании, которое было создано вчера, но выполнилось сегодня. В этом случае ТекущаяДата() берется на момент создания задания, а не выполнения.

2. Включено кэширование запроса, и платформа возвращает сохраненный результат.

Чтобы избежать этого, всегда передавайте дату через параметры в фоновых задачах.

7. Продвинутые техники: динамические периоды и работа с временными зонами

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

Примеры:

// Последние 30 дней

ВЫБРАТЬ

Документ.ЗаказПокупателя.Ссылка,

Документ.ЗаказПокупателя.Дата

ИЗ

Документ.ЗаказПокупателя КАК Документ.ЗаказПокупателя

ГДЕ

Документ.ЗаказПокупателя.Дата >= ТекущаяДата() - 30

// Текущий квартал

ВЫБРАТЬ

Документ.РеализацияТоваровУслуг.Ссылка,

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

ИЗ

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

ГДЕ

Документ.РеализацияТоваровУслуг.Дата >= НАЧАЛОКВАРТАЛА(ТекущаяДата())

И Документ.РеализацияТоваровУслуг.Дата < КОНЕЦКВАРТАЛА(ТекущаяДата()) + 1

Для работы с временными зонами в 1С 8.3.20+ появилась поддержка типа ЧасовойПояс. Пример использования:

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

Запрос.Текст =

"ВЫБРАТЬ

| ТекущаяДата() КАК ДатаПоСерверу,

| ТекущаяДатаВЧасовомПоясе(&ЧасовойПояс) КАК ДатаВУказанномПоясе";

Запрос.УстановитьПараметр("ЧасовойПояс", ЧасовойПояс.Мск); // или другой пояс

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

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

💡

Для динамических периодов всегда используйте функции НАЧАЛОДНЯ(), КОНЕЦДНЯ(), НАЧАЛОМЕСЯЦА() и т.д. Они учитывают особенности календаря (например, последний день февраля в високосный год).

FAQ: Ответы на частые вопросы

❓ Почему ТекущаяДата() в запросе и ТекущаяДата() во встроенном языке возвращают разные значения?

ТекущаяДата() в запросе выполняется на сервере 1С и зависит от его времени. Во встроенном языке функция выполняется на клиенте (если код запущен на клиенте) или на сервере (если код серверный). Разница может возникать из-за:

  • Разных часовых поясов сервера и клиента.
  • Задержки синхронизации времени в домене (для Windows-серверов).
  • Использования виртуальных машин с неверными настройками времени.

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

❓ Можно ли в запросе получить дату создания документа "сегодня"?

Да, но нужно учитывать время. Если документ создан сегодня в 10:00, а запрос выполняется в 15:00, то простое сравнение ДатаДокумента = ТекущаяДата() не сработает, потому что в ТекущаяДата() будет время (15:00), а в ДатаДокумента — 10:00.

Правильный вариант:

ГДЕ НАЧАЛОДНЯ(Документ.Ссылка.Дата) = НАЧАЛОДНЯ(ТекущаяДата())

Или через параметр:

ГДЕ Документ.Ссылка.Дата >= НАЧАЛОДНЯ(&ТекущаяДата)

И Документ.Ссылка.Дата < НАЧАЛОДНЯ(&ТекущаяДата) + 86400 // +1 день в секундах

❓ Как получить текущую дату в запросе к внешней базе данных (не 1С)?

Если вы выполняете запрос к внешней базе (например, через HTTPСервис или ADO), функции ТекущаяДата() не будет. В этом случае:

  1. Получите дату во встроенном языке: ТекущаяДата = ТекущаяДата();
  2. Передайте ее в запрос как параметр.
  3. Используйте синтаксис внешней СУБД для работы с датами (например, GETDATE() для MS SQL или NOW() для MySQL).

Пример для MS SQL:

Запрос.Текст = "SELECT * FROM Orders WHERE OrderDate >= @CurrentDate";

Запрос.УстановитьПараметр("CurrentDate", ТекущаяДата());

❓ Почему при сравнении дат в запросе не работают индексы?

Если вы используете функции над полем даты (например, НАЧАЛОДНЯ(Документ.Дата)), не может воспользоваться индексами по этому полю. Это приводит к полному сканированию таблицы (Table Scan) и замедлению запроса.

Решения:

  • Используйте параметры с явным указанием границ:
    ГДЕ Документ.Дата >= НАЧАЛОДНЯ(&ДатаНачала)
    

    И Документ.Дата < НАЧАЛОДНЯ(&ДатаОкончания) + 86400

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

Виртуальные таблицы доступны только в клиент-серверном варианте 1С (MS SQL, PostgreSQL, IBM DB2). В файловой базе они не работают.

Чтобы проверить поддержку:

  1. Откройте конфигуратор и перейдите в Администрирование → Поддержка → Тестирование и исправление.
  2. Посмотрите тип СУБД в информации о базе.
  3. Попробуйте выполнить простой запрос с виртуальной таблицей:
    ВЫБРАТЬ РАЗРЕШЕННЫЕ РОЛИ ИЗ ВиртуальнаяТаблица.РолиПользователей

    Если запрос выполняется без ошибок — виртуальные таблицы поддерживаются.