К статье
Практический материал

Разработка и Конфигурация · 11 мин

Как работать с датами в 1С

Практическое руководство по работе с датами в 1С: тип Дата, функции языка, даты в запросах, форматирование, границы периодов и типичные ошибки разработчиков.

Дата — один из самых часто используемых типов данных в 1С: ей заполнены документы, регистры, отчёты и графики работы. При этом именно с датами связано больше всего тонких ошибок: неверный часовой пояс, «пустая» дата, которая не равна нулю, граница периода, захватывающая лишние секунды. Понимание того, как платформа хранит и обрабатывает даты, избавляет от целого класса дефектов в учёте.

В 1С тип «Дата» всегда содержит и календарную часть, и время с точностью до секунды. Отдельного типа «только дата без времени» в языке нет — когда вы видите дату без времени, время просто равно 00:00:00. Это фундаментальное свойство определяет поведение сравнений, запросов и функций.

Ниже разобраны практические приёмы: создание и форматирование дат, арифметика, работа в запросах, границы периодов и типичные ошибки. Примеры ориентированы на встроенный язык 1С:Предприятия 8.3 и подходят как для управляемых, так и для обычных форм.

Тип «Дата» и его особенности

Внутренне дата в 1С хранится как значение, включающее год, месяц, день, часы, минуты и секунды. Допустимый диапазон — с 01.01.0001 до 31.12.3999. Попытка выйти за эти границы при арифметических операциях приводит к ошибке, поэтому при расчётах с большими смещениями стоит добавлять проверки.

Пустая дата — это 01.01.0001 00:00:00, и именно так проверяют, заполнено ли значение: сравнением с Дата(1,1,1) или функцией ЗначениеЗаполнено(). Важно: пустая дата не равна NULL в запросах. Если поле в запросе может быть NULL (например, из левого соединения), проверять его нужно через ЕСТЬ NULL, а не сравнением с пустой датой.

Создание и получение дат

Конкретную дату создают функцией Дата(). Она принимает либо числовые параметры — год, месяц, день и опционально часы, минуты, секунды, либо строку в формате «ГГГГММДДччммсс». Например: Дата(2026, 3, 15, 10, 30, 0) или Дата("20260315"). Строковый вариант удобен при разборе данных из файлов обмена.

Текущее время получают через ТекущаяДатаСеанса() — это рекомендуемый способ, потому что он учитывает часовой пояс сеанса. Устаревшая ТекущаяДата() берёт время клиентского компьютера, и при разнице часовых поясов между пользователями документы могут «разъезжаться» по датам. В серверном коде всегда используйте дату сеанса.

Из даты извлекают составляющие функциями Год(), Месяц(), День(), Час(), Минута(), Секунда(), а также ДеньНедели(), ДеньГода(), НеделяГода(). Они возвращают числа и удобны для условий вида «только рабочие дни» или «первое число месяца».

bsl
НачалоДня = НачалоДня(ТекущаяДатаСеанса());
КонецДня = КонецДня(ТекущаяДатаСеанса()); // 23:59:59
Пустая = Дата(1,1,1);
Если Не ЗначениеЗаполнено(Док.ДатаОплаты) Тогда
	Сообщить("Дата оплаты не указана");
КонецЕсли;

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

Для вывода даты в сообщениях, печатных формах и надписях применяют функцию Формат() со строкой формата. Например, Формат(ДатаДокумента, "ДЛФ=D") выдаёт длинную дату вида «15 марта 2026 г.», а Формат(ДатаДокумента, "ДФ=dd.MM.yyyy") — короткую «15.03.2026». Параметр ДЛФ зависит от региональных настроек, ДФ задаёт шаблон явно.

Для времени используют параметры ДЛФ=T и ДЛФ=DT (дата со временем). При выгрузке в файлы и веб-сервисы дату обычно приводят к формату ISO 8601 через ЗаписатьДатуJSON() или форматную строку "ДФ=yyyy-MM-ddTHH:mm:ss" — так значение однозначно прочитается на принимающей стороне.

Частая ошибка — склеивать дату со строкой напрямую: "Документ от " + ДатаДокумента. Результат зависит от региональных настроек сеанса и может выглядеть иначе на сервере и у пользователя. Всегда оборачивайте дату в Формат() с явным шаблоном.

Арифметика дат и смещение периодов

Сложение и вычитание дат в 1С выполняется в секундах: ДатаДокумента + 86400 сдвинет значение ровно на сутки. Разность двух дат также даёт число секунд, которое затем делят на 60, 3600 или 86400 для получения минут, часов и дней. Помните, что при делении могут остаться дробные остатки — используйте Цел() там, где нужны полные сутки.

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

Для выравнивания даты на границу периода есть семейство функций: НачалоДня(), КонецДня(), НачалоНедели(), НачалоМесяца(), НачалоКвартала(), НачалоГода() и соответствующие «концы». КонецДня() возвращает 23:59:59 — это важно для отборов периодов, о чём ниже.

Как рассчитать период «прошлый месяц»
  1. 1
    Возьмите текущую дату сеанса: ТекущаяДатаСеанса()
  2. 2
    Сместите на минус один месяц: ДобавитьМесяц(Дата, -1)
  3. 3
    Выровняйте начало: НачалоМесяца(СмещённаяДата)
  4. 4
    Получите конец: КонецМесяца(СмещённаяДата)
  5. 5
    Используйте обе границы в отборе запроса или отчёта

Даты в запросах

В языке запросов дату-константу задают функцией ДАТАВРЕМЯ(2026, 3, 15, 0, 0, 0). Передавать даты параметрами предпочтительнее: это безопаснее и позволяет оптимизатору строить эффективный план. Параметр объявляется как &НачалоПериода и заполняется значением типа «Дата» перед выполнением запроса.

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

Отдельная тема — виртуальные таблицы регистров. У таблиц «Остатки», «Обороты», «ОстаткиИОбороты» параметры периода задаются специальным синтаксисом в скобках после имени таблицы, а не в условии ГДЕ. Перепутав место отбора, вы получите корректный, но медленный запрос: платформа сначала выберет всё, а потом отфильтрует.

Типичные ошибки в запросах с датами
01
Сравнение с пустой датой вместо ЕСТЬ NULL для полей из левого соединения — строки с NULL теряются или попадают в выборку ошибочно
02
Отбор по периоду в условии ГДЕ для виртуальных таблиц вместо параметров таблицы — резкое падение производительности
03
Конкатенация даты в текст запроса вместо параметра — риск ошибок формата и внедрения кода
04
Использование ДАТАВРЕМЯ с динамическими значениями там, где нужен параметр

Границы периодов и отбор «по день включительно»

Классическая проблема: пользователь задаёт период отчёта с 1 по 31 марта, а документы за 31 марта после 00:00:00 в отчёт не попадают. Причина — сравнение Период <= &КонецПериода, где конец периода равен 31.03.2026 00:00:00. Все документы позже полуночи отсекаются.

Решений два. Первое — всегда передавать в качестве конца периода КонецДня(ДатаОкончания), то есть 23:59:59. Второе — использовать объект Граница с видом «Включая»: Новый Граница(ДатаОкончания, ВидГраницы.Включая). Границы особенно важны при работе с регистрами сведений и моментами времени, где секундной точности может не хватать из-за одинакового времени у разных документов.

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

Контрольные точки

Как проверить корректность периода

Граница конца периода в отладчике
Норма

23:59:59 последнего дня или Граница с видом Включая

Тревожный признак

00:00:00 последнего дня при сравнении «меньше или равно»

Документы последнего дня в отчёте
Норма

Все документы дня присутствуют

Тревожный признак

Попадают только документы ровно в 00:00:00

Итоги виртуальной таблицы
Норма

Параметры периода заданы в скобках таблицы

Тревожный признак

Период фильтруется только в условии ГДЕ

Часовые пояса и дата сеанса

В распределённых системах пользователи могут работать в разных часовых поясах, а сервер — в третьем. Платформа хранит даты без привязки к поясу, поэтому ответственность за корректность лежит на разработчике. Базовое правило: весь серверный код опирается на ТекущаяДатаСеанса(), а пояс сеанса настраивается в свойствах информационной базы или сеанса.

Для преобразований между поясами есть функции МестноеВремя() и УниверсальноеВремя(). Если база обменивается данными с внешними системами, фиксируйте в соглашении об обмене, в каком поясе передаются даты — чаще всего выбирают UTC, чтобы исключить двусмысленность.

Проверки, сравнения и типовые приёмы

Сравнение дат выполняется обычными операторами: больше, меньше, равно. Помните, что сравнивается и время: 15.03.2026 14:00 не равно 15.03.2026 00:00. Если нужно сравнить только календарную часть, предварительно примените НачалоДня() к обоим значениям.

Полезные приёмы, которые встречаются в большинстве конфигураций: проверка попадания даты в период через два сравнения, расчёт возраста или стажа через разность годов с поправкой на месяц и день, определение пересечения двух периодов по правилу «начало первого раньше конца второго и наоборот». Для графиков и производственных календарей сдвиг даты на N рабочих дней делают не арифметикой, а запросом к регистру-календарю — выходные и праздники иначе не учесть.

Маршрут решения

Как выбрать способ работы с датой

Нужно сместить дату на дни или часыИспользуйте арифметику в секундах: Дата + 86400 * КоличествоДней
Нужно сместить дату на месяцы или годыИспользуйте ДобавитьМесяц() — она корректно обработает короткие месяцы
Нужно сгруппировать данные по периоду в запросеПримените НАЧАЛОПЕРИОДА с нужной периодичностью
Нужно учесть рабочие и праздничные дниИспользуйте производственный календарь или регистр графиков, а не арифметику
Нужно вывести дату пользователюПримените Формат() с явной форматной строкой

Частые вопросы

Как проверить, что дата не заполнена?

Сравните значение с пустой датой: ДатаПроверки = Дата(1,1,1), либо используйте универсальную функцию ЗначениеЗаполнено(ДатаПроверки) — она вернёт Ложь для пустой даты. В запросе для полей, которые могут быть NULL, проверку делайте через ЕСТЬ NULL, а не сравнением с пустой датой.

Почему документы за последний день не попадают в отчёт?

Потому что конец периода задан как 00:00:00 последнего дня, а документы имеют время позже. Передайте в отчёт КонецДня(ДатаОкончания) — 23:59:59 — или используйте объект Граница с видом «Включая».

Чем отличается ТекущаяДата() от ТекущаяДатаСеанса()?

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

Как прибавить к дате один месяц?

Функцией ДобавитьМесяц(Дата, 1). Простое прибавление 30 или 31 дня в секундах даст ошибку на коротких месяцах: ДобавитьМесяц корректно переносит, например, 31 января на последний день февраля.

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

Отдельного типа «дата без времени» в 1С нет. Примените НачалоДня(Дата) — время станет 00:00:00, и значение можно сравнивать и группировать как календарную дату. При выводе пользователю дополнительно отформатируйте её функцией Формат() без временной части.

Как передать дату в запрос?

Через параметр: в тексте запроса укажите &НачалоПериода, а перед выполнением вызовите Запрос.УстановитьПараметр("НачалоПериода", ЗначениеДаты). Для констант внутри текста запроса используйте ДАТАВРЕМЯ(год, месяц, день, часы, минуты, секунды), но параметры предпочтительнее — они безопаснее и быстрее.

Итог

Что важно запомнить

Дата в 1С всегда содержит время до секунды; пустая дата — это 01.01.0001. Создавайте даты через Дата(), форматируйте через Формат(), смещайте через ДобавитьМесяц() и арифметику в секундах. В запросах используйте ДАТАВРЕМЯ, НАЧАЛОПЕРИОДА и параметры, а конец периода задавайте как 23:59:59 или границей «Включая». В серверном коде опирайтесь на ТекущаяДатуСеанса().