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

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

Как рассчитать дату в 1С: функции, примеры и типичные ошибки

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

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

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

Как устроен тип «Дата» и почему это важно

Тип «Дата» в 1С содержит и календарную дату, и время с точностью до секунды. Когда вы пишете Дата("20260115"), время равно 00:00:00. Если документ проведён в 14:35:20, его дата хранит и это время — сравнение такой даты с «чистой» календарной датой даст неравенство, хотя визуально день один и тот же.

Арифметика с датами работает в секундах. Выражение Дата + 1 прибавляет одну секунду, а не один день. Чтобы сдвинуть дату на сутки, нужно прибавить 86400 (60 × 60 × 24). Это самая частая ошибка начинающих разработчиков: код ДатаОплаты = ДатаДокумента + 10 компилируется без ошибок, но сдвигает дату на 10 секунд.

Как прибавить или вычесть дни

Для сдвига на целое число дней используется сложение или вычитание с умножением на 86400. Пример расчёта срока оплаты — 14 календарных дней от даты счёта:

ДатаОплаты = ДатаСчета + 14 * 86400;

Просрочено = ТекущаяДата() > ДатаОплаты;

Если нужно сохранить время суток (например, дата отгрузки всегда в 10:00), сначала обрежьте время функцией НачалоДня(), затем прибавьте дни и нужное количество часов:

ДатаОтгрузки = НачалоДня(ДатаЗаказа) + 3  86400 + 10  3600;

Вычитание работает симметрично: ДатаНачала = ДатаОкончания - 30 * 86400 даст дату за 30 суток до указанной. Учтите, что так считаются календарные дни. Для расчёта рабочих дней арифметики недостаточно — нужен производственный календарь, об этом ниже.

Как прибавить месяцы и годы: функция ДобавитьМесяц

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

ДатаОкончанияДоговора = ДобавитьМесяц(ДатаНачала, 12); // ровно год

СледующийПлатеж = ДобавитьМесяц(ДатаПлатежа, 1);

Особый случай — конец месяца. Если исходная дата 31 января, то ДобавитьМесяц вернёт 28 или 29 февраля (последний день месяца), а не 3 марта. Это логичное поведение для финансовых расчётов, но о нём нужно помнить при тестировании на граничных датах.

Чтобы прибавить годы, умножьте количество на 12: ДобавитьМесяц(Дата, 5 * 12) — плюс пять лет. Отдельной функции «ДобавитьГод» во встроенном языке нет.

Границы периодов: начало и конец дня, месяца, квартала

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

  • НачалоДня(Дата), КонецДня(Дата) — 00:00:00 и 23:59:59;
  • НачалоНедели(Дата), КонецНедели(Дата);
  • НачалоМесяца(Дата), КонецМесяца(Дата);
  • НачалоКвартала(Дата), КонецКвартала(Дата);
  • НачалоГода(Дата), КонецГода(Дата).

Типичный пример — формирование периода отчёта за предыдущий месяц:

НачалоПериода = НачалоМесяца(ДобавитьМесяц(ТекущаяДата(), -1));

КонецПериода = КонецМесяца(НачалоПериода);

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

Как посчитать разницу между датами

Вычитание двух дат даёт разницу в секундах. Чтобы получить дни, разделите на 86400:

ДнейПросрочки = (ТекущаяДата() - ДатаОплаты) / 86400;

Результат будет дробным, если время у дат разное. Для целого числа дней используйте Цел() или предварительно приведите обе даты к началу дня — так расчёт не будет «плясать» от времени проведения документа:

ДнейМежду = (НачалоДня(Дата2) - НачалоДня(Дата1)) / 86400;

Разница в месяцах арифметикой не считается из-за разной длины месяцев. Практический способ — вычислить через год и месяц: (Год(Д2) - Год(Д1)) * 12 + Месяц(Д2) - Месяц(Д1), а затем скорректировать результат, если день второй даты меньше дня первой. В запросах для разницы дат есть встроенная функция РАЗНОСТЬДАТ(Дата1, Дата2, ДЕНЬ) — в запросах предпочтительнее использовать именно её.

Порядок действий для расчёта срока оплаты
  1. 1
    Определите базовую дату: дата счёта или дата отгрузки
  2. 2
    Уточните единицы срока: календарные дни, рабочие дни или месяцы
  3. 3
    Для дней прибавьте N * 86400, для месяцев используйте ДобавитьМесяц
  4. 4
    Приведите результат к началу или концу дня, если время не важно
  5. 5
    Проверьте расчёт на граничных датах: 31 января, 29 февраля, конец года

Расчёт по рабочим дням и в запросах

Если срок задан в рабочих днях, простой арифметики недостаточно — нужно учитывать выходные и праздники. В типовых конфигурациях для этого используется регистр сведений с производственным календарём (например, «ДанныеПроизводственногоКалендаря»). Алгоритм: в цикле прибавлять по одному дню и проверять по календарю, является ли день рабочим, пока не наберётся нужное количество.

В языке запросов 1С доступны свои инструменты: ДОБАВИТЬКДАТЕ(Дата, ДЕНЬ, 5), РАЗНОСТЬДАТ, НАЧАЛОПЕРИОДА и КОНЕЦПЕРИОДА. Они удобны тем, что вычисляются на стороне СУБД и не требуют выгрузки данных в код. Единицы периода указываются ключевыми словами: СЕКУНДА, МИНУТА, ЧАС, ДЕНЬ, НЕДЕЛЯ, МЕСЯЦ, КВАРТАЛ, ГОД.

Сравнение вариантов расчёта

Арифметика дат (дата + N * 86400)

Подходит для дней и недель. Не подходит для месяцев и лет из-за разной длины месяцев.

ДобавитьМесяц

Единственный корректный способ сдвига на месяцы и годы в коде. Учитывает високосные годы.

ДОБАВИТЬКДАТЕ в запросе

Универсальный вариант при выборке данных; выполняется на сервере СУБД, не требует обхода результата.

Производственный календарь

Обязателен для расчёта в рабочих днях. Требует актуального заполнения календаря в базе.

Типичные ошибки и проверка результата

Первая ошибка — прибавление дней без умножения на 86400: код работает, ошибок не выдаёт, но дата сдвигается на секунды. Вторая — сравнение дат документов с «чистыми» датами без приведения через НачалоДня: документ, проведённый в 15:00, оказывается «больше» границы периода, заданной как начало того же дня.

Третья ошибка — расчёт месяцев через 30 дней: Дата + 30 * 86400 вместо ДобавитьМесяц(Дата, 1). На длинных дистанциях такой код накапливает погрешность и смещает даты платежей. Четвёртая — игнорирование пустой даты: пустая дата в 1С равна 01.01.0001, и любые расчёты с ней дадут бессмысленный результат. Перед вычислениями проверяйте ЗначениеЗаполнено(Дата).

Типичные ошибки
01
Дата + 10 вместо Дата + 10 * 86400 — сдвиг на секунды вместо дней
02
Сравнение дат с временем без НачалоДня — документы выпадают из периода
03
Месяц через 30 дней — накопление погрешности и сдвиг дат платежей
04
Расчёт без проверки пустой даты — результат уходит в год 0001
05
Рабочие дни через арифметику — игнорируются выходные и праздники
Контрольные точки

Как проверить результат

Сдвиг на 1 день
Норма

Изменилось только число, время сохранилось

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

Дата изменилась на секунды или сбросилось время

Добавление месяца к 31.01
Норма

Получено последнее число февраля

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

Дата ушла в март

Разница между датами
Норма

Целое число дней при датах без времени

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

Дробное значение из-за разного времени

Период отчёта
Норма

Начало 00:00:00, конец 23:59:59

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

Документы первого или последнего дня не попадают

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

Итог

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

Дни прибавляйте через умножение на 86400, месяцы и годы — только через ДобавитьМесяц, границы периодов берите штатными функциями Начало/Конец, разницу считайте через вычитание с приведением к началу дня или РАЗНОСТЬДАТ в запросах. Всегда проверяйте заполненность даты и тестируйте код на граничных календарных значениях.

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

Как прибавить к дате 10 рабочих дней?

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

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

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

Как получить последний день месяца?

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

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

Почти всегда причина во времени: дата документа содержит время проведения, а дата-константа — 00:00:00. Приведите обе даты к началу дня перед сравнением: НачалоДня(Дата1) = НачалоДня(Дата2). Также проверьте, не сравниваете ли вы дату со строкой — неявное преобразование типов в 1С в таких сравнениях не выполняется.

Как посчитать возраст или стаж в полных годах?

Вычислите разницу в годах через Год(Дата2) - Год(Дата1), затем уменьшите результат на 1, если месяц и день рождения в текущем году ещё не наступили. Удобное сравнение: если ДобавитьМесяц(ДатаРождения, Годы * 12) больше текущей даты, вычтите единицу. Такой подход корректно работает с 29 февраля.

Можно ли складывать даты с часовыми поясами?

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