Расчет разницы между датами в днях — одна из самых востребованных операций в 1С:Предприятие. Бухгалтерам нужно определять просрочку платежей, кадровикам — стаж сотрудников, логистам — сроки доставки. Даже в простых отчетах часто требуется вывести количество дней между двумя событиями. Но как это сделать правильно, учитывая особенности платформы 1С 8.3?

Многие пользователи ошибочно думают, что достаточно вычесть одну дату из другой — как в Excel. Однако в такой подход работает иначе: результат вычитания дат возвращается в формате количества секунд, а не дней. Без преобразования вы получите некорректное значение. В этой статье разберем три основных метода расчета разницы в днях — от элементарных до продвинутых, с учетом рабочих дней, праздников и особенностей конфигураций.

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

📊 Для чего вам чаще всего нужно считать разность дат в 1С?
Для расчета просрочки платежей
Определения стажа сотрудников
Логистических расчетов
Формирования отчетов
Другой вариант

1. Простой расчет: функция Дни() и вычитание дат

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

```1с

КоличествоДней = Дни(КонечнаяДата, НачальнаяДата);

```

Если вычесть даты напрямую (КонечнаяДата - НачальнаяДата), результат будет в секундах. Чтобы преобразовать его в дни, разделите на количество секунд в сутках:

```1с

КоличествоДней = Цел((КонечнаяДата - НачальнаяДата) / 86400);

```

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

  • Плюсы метода: простота, не требует программирования, работает во всех конфигурациях.
  • Минусы: не учитывает рабочие/выходные дни, праздники.
  • 🔄 Когда использовать: для базовых расчетов (сроки договоров, возраст документов).
⚠️ Внимание: Если одна из дат пустая (Дата(1,1,1)), функция Дни() вернет ошибку. Всегда проверяйте заполненность параметров перед расчетом.

2. Учет рабочих дней: алгоритм с календарем

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

Пример кода для подсчета рабочих дней между двумя датами (без учета праздников):

```1с

Функция РабочиеДни(ДатаНачало, ДатаОкончание)

Счетчик = 0;

ТекущаяДата = ДатаНачало;

Пока ТекущаяДата <= ДатаОкончание Цикл

Если Не ТекущаяДата.ДеньНедели() = 6 И Не ТекущаяДата.ДеньНедели() = 7 Тогда

Счетчик = Счетчик + 1;

КонецЕсли;

ТекущаяДата = ТекущаяДата + 86400; // +1 день

КонецЦикла;

Возврат Счетчик;

КонецФункции

```

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

```1с

Если Не НайтиСтроку(Справочник.Праздники.НайтиПоНаименованию(Формат(ТекущаяДата, "ДЛФ=DT")), "") Тогда

Счетчик = Счетчик + 1;

```

  • 📅 Важно: День недели в нумеруется с 1 (понедельник) до 7 (воскресенье).
  • 🔧 Оптимизация: Для больших периодов (год и более) используйте рекурсивный метод вместо цикла.
  • 📌 Готовое решение: В некоторых конфигурациях (например, 1С:ЗУП) уже есть процедуры для расчета рабочих дней — ищите их в модулях.
Как ускорить расчет для больших периодов?

Для периодов более 1000 дней вместо поэлементного перебора используйте математический алгоритм: вычислите количество полных недель (умножьте на 5 рабочих дней), затем добавьте оставшиеся дни с проверкой на выходные. Это сократит время выполнения в 100+ раз.

3. Использование запросов для массовых расчетов

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

```1с

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

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

"ВЫБРАТЬ

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

| ДокументДата КАК ДатаДокумента,

| ТЕКУЩАЯДАТА() КАК Сегодня,

| ДНИ(ТЕКУЩАЯДАТА(), ДокументДата) КАК ДнейПросрочки

|ИЗ

| Документ.ПлатежноеПоручение КАК Документ

|ГДЕ

| ДокументДата < ТЕКУЩАЯДАТА()";

```

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

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

Метод Сложность Производительность Учет рабочих дней
Функция Дни() Низкая Высокая Нет
Вычитание дат Низкая Высокая Нет
Цикл по дням Средняя Низкая (для больших периодов) Да
Запрос с ДНИ() Низкая Высокая Нет
Рекурсивный алгоритм Высокая Средняя Да
⚠️ Внимание: При использовании запросов с функцией ДНИ() в больших базах данных может возникнуть проблема производительности. Тестируйте запрос на небольшой выборке перед применением ко всей базе.

4. Типовые ошибки и как их избежать

Даже опытные пользователи иногда допускают ошибки при работе с датами. Вот самые распространенные:

  • 🗓️ Пустые даты: Если одна из дат не заполнена (Дата(1,1,1)), расчет вернет некорректный результат. Всегда проверяйте:
    Если НачальнаяДата = Дата(1,1,1) Или КонечнаяДата = Дата(1,1,1) Тогда
    

    Сообщить("Укажите корректные даты!");

    Возврат 0;

    КонецЕсли;

  • Временная зона: В распределенных базах даты могут храниться в разных часовых поясах. Используйте НачалоДня() для приведения к одному формату:
    НачальнаяДата = НачалоДня(НачальнаяДата);
  • 🔄 Отрицательное значение: Если конечная дата раньше начальной, функция Дни() вернет отрицательное число. Используйте Абс() для получения модуля:
    КоличествоДней = Абс(Дни(КонечнаяДата, НачальнаяДата));

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

Убедиться, что обе даты заполнены|Привести даты к одному формату (НачалоДня)|Проверить порядок дат (начальная <= конечная)|Учесть часовой пояс (если база распределенная)|Определить, нужны ли рабочие дни или календарные-->

5. Практический пример: расчет просрочки платежей

Рассмотрим реальный кейс: нужно сформировать отчет по просроченным платежам с указанием количества дней задержки. Вот пошаговый алгоритм:

  1. Создайте запрос, который выбирает все неоплаченные счета с датой ранее текущей.
  2. Добавьте в выборку поле с расчетом дней просрочки:
    ДНИ(ТЕКУЩАЯДАТА(), Документ.Дата) КАК ДнейПросрочки
  3. Отсортируйте результат по убыванию количества дней, чтобы сначала показывались самые просроченные платежи.
  4. Для визуализации используйте условное оформление: например, красным цветом выделяйте строки с просрочкой более 30 дней.

Пример кода для отчета:

```1с

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

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

"ВЫБРАТЬ

| СчетНаОплату.Номер КАК НомерСчета,

| СчетНаОплату.Дата КАК ДатаСчета,

| СчетНаОплату.Сумма КАК Сумма,

| ДНИ(ТЕКУЩАЯДАТА(), СчетНаОплату.Дата) КАК ДнейПросрочки

|ИЗ

| Документ.СчетНаОплату КАК СчетНаОплату

|ГДЕ

| СчетНаОплату.Оплачен = ЛОЖЬ

| И СчетНаОплату.Дата < ТЕКУЩАЯДАТА()

|

|УПОРЯДОЧИТЬ ПО

| ДнейПросрочки УБЫВ";

```

Для удобства можно добавить группировку по интервалам просрочки (например, 0-7 дней, 8-30 дней, более 30 дней). Это поможет быстро оценить "возраст" долгов.

💡

Если в вашей конфигурации есть справочник "Договоры контрагентов", добавьте в запрос связь с ним. Это позволит анализировать просрочки не только по счетам, но и по конкретным договорам или клиентам.

6. Альтернативные решения: внешние обработки и расширения

Если встроенные методы не покрывают ваши нужды (например, требуется учитывать региональные праздники или сложные графики работы), рассмотрите следующие варианты:

  • 📦 Готовые обработки: На сайте Инфостарт есть бесплатные и платные обработки для расчета рабочих дней с учетом производственного календаря РФ. Примеры:
    • "Календарь рабочих дней"
    • "Расчет стажа с учетом праздников"
  • 🔧 Расширения конфигурации: Для 1С:ЗУП и 1С:ERP есть типовые расширения, добавляющие функции работы с датами.
  • 🌐 Интеграция с внешними сервисами: Можно подключить API государственных календарей (например, production-calendar.ru) для автоматического обновления праздничных дней.

При выборе внешнего решения обращайте внимание на:

  • Совместимость с вашей версией 1С:Предприятие (8.3.20+).
  • Наличие технической поддержки.
  • Отзывы других пользователей (особенно о корректности расчетов).
⚠️ Внимание: Перед установкой сторонних обработок или расширений обязательно сделайте резервную копию базы. Тестируйте новые модули на копии рабочей базы, а не на боевой системе.

7. Оптимизация производительности для больших баз

Если вам нужно рассчитать разницу дат для десятков тысяч записей, стандартные методы могут тормозить. Вот как ускорить процесс:

Проблема: Цикл по дням для расчета рабочих дней в периоде 5+ лет занимает несколько минут.

Решение:

  1. Используйте кеширование: один раз рассчитайте все праздники и выходные за год и сохраните в массив.
  2. Для массовых расчетов применяйте пакетные операции вместо поэлементной обработки.
  3. Если возможен, используйте SQL-запросы напрямую к базе (только для опытных пользователей!).

Пример оптимизированного кода для расчета рабочих дней с кешированием:

```1с

Функция РабочиеДниОптимизированно(ДатаНачало, ДатаОкончание)

// Кешируем праздники за год

ГодНачало = Год(ДатаНачало);

ГодОкончание = Год(ДатаОкончание);

МассивПраздников = Новый Массив;

Для СчетчикГода = ГодНачало По ГодОкончание Цикл

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

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

"ВЫБРАТЬ

| Дата КАК День

|ИЗ

| Справочник.Праздники КАК Праздники

|ГДЕ

| ГОД(Дата) = &Год";

Запрос.УстановитьПараметр("Год", СчетчикГода);

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

Пока Результат.Следующий() Цикл

МассивПраздников.Добавить(Результат.День);

КонецЦикла;

КонецЦикла;

// Далее стандартный расчет с проверкой по кешу

// ...

КонецФункции

```

Такой подход сокращает время выполнения в 5-10 раз по сравнению с поэлементной проверкой каждого дня на принадлежность к празднику.

💡

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

FAQ: Частые вопросы по расчету дат в 1С

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

Используйте вычитание дат с делением на количество секунд в часе/минуте:

КоличествоЧасов = (КонечнаяДата - НачальнаяДата) / 3600;

КоличествоМинут = (КонечнаяДата - НачальнаяДата) / 60;

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

Почему функция Дни() возвращает отрицательное число?

Это означает, что начальная дата позже конечной. Используйте Абс(Дни(Дата1, Дата2)), чтобы всегда получать положительное значение, или проверяйте порядок дат перед расчетом.

Как учесть праздничные дни в расчете рабочих дней?

Создайте справочник "Праздники" с полем типа Дата. При расчете проверяйте, попадает ли текущая дата в этот справочник. Пример кода:

Если НЕ Справочник.Праздники.НайтиПоРеквизиту("Дата", ТекущаяДата).Пустая() Тогда

Продолжить; // Пропускаем праздники

КонецЕсли;

Для автоматического обновления праздников можно написать обработку, загружающую данные с сайта правительства РФ.

Можно ли рассчитать разницу дат в месяцах или годах?

Для месяцев используйте функцию Месяц() с корректировкой:

КоличествоМесяцев = (Год(Дата2) - Год(Дата1)) * 12 + (Месяц(Дата2) - Месяц(Дата1));

Для лет: Год(Дата2) - Год(Дата1). Оба метода дают приблизительный результат. Для точного расчета (например, 1 год и 2 месяца) требуется сложный алгоритм с учетом дней.

Как посчитать количество будних дней между датами в 1С:ЗУП?

В 1С:Зарплата и Управление Персоналом есть встроенный механизм работы с производственным календарем. Используйте функцию Календарь.РабочиеДниМеждуДатами():

КоличествоРабочихДней = Календарь.РабочиеДниМеждуДатами(НачальнаяДата, КонечнаяДата);

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