Как правильно рассчитать разницу между двумя датами в годах, месяцах и днях в 1С 8.3

Программист 1С v8.3 (Управляемые формы)
← На главную

Расчет точной разницы между двумя датами — классическая задача, которая на первый взгляд кажется простой, но таит в себе множество подводных камней. Основная сложность заключается в переменном количестве дней в месяцах (28, 29, 30 или 31) и наличии високосных лет. В этой статье мы подробно разберем несколько подходов к решению этой задачи на платформе 1С:Предприятие 8.3, проанализируем примеры кода и выясним, как избежать типичных ошибок при работе с календарными периодами.

Метод 1. Циклический расчет с использованием встроенных функций

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

Проанализируем пример кода, реализующий этот подход:


ТекДата = НачалоКонтракта;
ВсегоМесяцев = 0;

// Цикл прибавления месяцев
Пока Истина Цикл
    НовДата = ДобавитьМесяц(ТекДата, 1);
    Если НовДата > ОкончаниеКонтракта Тогда
        Прервать;
    КонецЕсли;
    ТекДата = НовДата;
    ВсегоМесяцев = ВсегоМесяцев + 1;
КонецЦикла;

// Вычисление итоговых значений
Лет = Цел(ВсегоМесяцев / 12);
Месяцев = ВсегоМесяцев % 12;
// Разница в секундах делится на количество секунд в сутках
Дней = Цел((ОкончаниеКонтракта - ТекДата) / 86400);

В данном примере мы используем функцию ДобавитьМесяц, которая является ключевой. Она умеет правильно обрабатывать ситуации, когда, например, при прибавлении месяца к 31 августа мы получаем 30 сентября. Оставшаяся разница после вычета полных месяцев пересчитывается в дни простым делением разницы в секундах на 86 400 (количество секунд в одних сутках).

Метод 2. Использование возможностей Библиотеки стандартных подсистем (БСП)

Если вы работаете в современной конфигурации (УТ 11, ЗУП 3, ERP), то вам не нужно изобретать велосипед. Программисты фирмы «1С» уже включили необходимые инструменты в состав БСП. Рассмотрим, как можно использовать готовые функции для этих целей.

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

Преимущества использования БСП:

  1. Надежность: учитываются все нюансы календаря.
  2. Стандартизация: ваш код будет понятен другим разработчикам.
  3. Скорость разработки: вызов одной функции заменяет написание целой процедуры.

Метод 3. Процедура для детального разбора разности дат

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


Процедура РазобратьРазностьДат(Дата1, Дата2, Лет = 0, Месяцев = 0, Дней = 0)
    Лет = 0;
    Месяцев = 0;
    Дней = 0;
    
    Если Дата1 > Дата2 Тогда
        // Если даты перепутаны, можно либо выдать ошибку, либо поменять их местами
        Возврат;
    КонецЕсли;
    
    // Считаем годы
    Пока ДобавитьМесяц(Дата1, (Лет + 1) * 12) <= Дата2 Цикл
        Лет = Лет + 1;
    КонецЦикла;
    
    // Считаем месяцы
    Пока ДобавитьМесяц(ДобавитьМесяц(Дата1, Лет * 12), Месяцев + 1) <= Дата2 Цикл
        Месяцев = Месяцев + 1;
    КонецЦикла;
    
    // Остаток в днях
    ДатаПоследнегоМесяца = ДобавитьМесяц(ДобавитьМесяц(Дата1, Лет * 12), Месяцев);
    Дней = (Дата2 - ДатаПоследнегоМесяца) / 86400;
КонецПроцедуры

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

Особенности функции РАЗНОСТЬДАТ в запросах

Выясним причину, по которой функцию запроса РАЗНОСТЬДАТ нельзя использовать напрямую для создания калькулятора в формате «Лет-Месяцев-Дней». Проанализируем, как она работает: функция считает количество границ периодов, которые пересекаются между двумя датами.

Например, запрос:

ВЫБРАТЬ РАЗНОСТЬДАТ(ДАТАВРЕМЯ(2023, 12, 31), ДАТАВРЕМЯ(2024, 01, 01), ГОД)

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

Обратная задача: получение Даты Окончания по заданным Лет, Месяцев, Дней

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

  1. Возьмем реквизит НачалоКонтракта.
  2. Используем ДобавитьМесяц, передав туда общее количество месяцев (Лет * 12 + Месяцев).
  3. К полученному результату прибавим количество дней в секундах (Дней * 86400).

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

Подводные камни и рекомендации

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

1. Високосные годы: Если контракт начинается 29 февраля, а его длительность составляет 1 год, то функция ДобавитьМесяц вернет 28 февраля следующего года. Это стандартное поведение платформы, которое соответствует юридической практике.

2. Графики работы: Если ваша задача — посчитать не календарные, а рабочие дни, то описанные выше математические методы не подойдут. В этом случае необходимо использовать запросы к регистру сведений Календари или ГрафикиРаботы, чтобы исключить праздники и выходные.

3. Точность до секунды: Помните, что в 1С дата включает в себя время. Если в реквизите НачалоКонтракта время установлено на 12:00, а в ОкончаниеКонтракта на 00:00, то при вычитании дат вы можете получить нецелое количество дней. Рекомендуется всегда использовать функцию НачалоДня() для обоих параметров перед расчетом разницы.

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

← На главную