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

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

Как определить високосный год в 1С

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

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

Существует два рабочих подхода. Первый — арифметический: год високосный, если он делится на 4, но не делится на 100, либо делится на 400. Второй — платформенный: попросить 1С прибавить год к дате 29 февраля и посмотреть, что получилось. Оба способа дают одинаковый результат, но различаются по читаемости и устойчивости к ошибкам.

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

Как устроено правило високосного года

Григорианский календарь, по которому работает 1С, использует трёхступенчатое правило. Год считается високосным, если его номер делится на 4 без остатка. Исключение — годы, делящиеся на 100: они невисокосные. Но из этого исключения есть обратное исключение: годы, делящиеся на 400, снова високосные.

На практике это означает: 2020 и 2026 — високосные, 1900 и 2100 — нет (делятся на 100, но не на 400), 2000 — високосный (делится на 400). Ошибка в любом из трёх условий приводит к неверному результату на граничных годах, поэтому «сокращённая» проверка только на делимость на 4 — распространённый источник дефектов.

Способ 1: арифметическая проверка делимости

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

Функция ЭтоВисокосныйГод(Год) Экспорт

Возврат (Год % 4 = 0 И Год % 100 <> 0) ИЛИ Год % 400 = 0;

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

Функция принимает число — номер года — и возвращает булево. Если в распоряжении есть не число, а дата, год извлекается стандартной функцией Год(Дата):

ДатаПроверки = ТекущаяДатаСеанса();

Если ЭтоВисокосныйГод(Год(ДатаПроверки)) Тогда

Сообщить("В феврале 29 дней");

КонецЕсли;

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

bsl
Функция ЭтоВисокосныйГод(Год) Экспорт
    Возврат (Год % 4 = 0 И Год % 100 <> 0) ИЛИ Год % 400 = 0;
КонецФункции

Способ 2: проверка через ДобавитьМесяц

Альтернатива без арифметики — использовать штатную функцию ДобавитьМесяц. Идея: взять дату 28 февраля проверяемого года, прибавить один день через конструкцию с датой и посмотреть, какой день получился. Более надёжный вариант — прибавить к 1 марта минус один день или проверить конец февраля.

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

Функция ЭтоВисокосныйГодЧерезДату(Год) Экспорт

ДатаПроверки = Дата(Год, 3, 1) - 86400; // последний день февраля

Возврат День(ДатаПроверки) = 29;

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

Здесь используется важное свойство типа «Дата» в 1С: вычитание целого числа означает вычитание секунд. Отнимая 86400 секунд (одни сутки) от 1 марта, мы всегда получаем последний день февраля — 28-е в обычном году и 29-е в високосном. Этот приём заодно решает смежную задачу — определение количества дней в любом месяце.

Сравнение двух подходов

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

Сравнение вариантов

Делимость (Год % 4, % 100, % 400)

Быстрый и явный код, легко читается тем, кто знает правило. Требует аккуратности с тремя условиями — легко потерять проверку на 400.

Через Дата(Год,3,1) - 86400

Не требует знания правила календаря, заодно даёт последний день февраля. Менее очевиден для читающего код, опирается на арифметику секунд.

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

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

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

Где это применяется на практике

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

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

Третий сценарий — формирование производственных календарей и графиков. При автоматической генерации календаря на год количество дней февраля определяется именно такой проверкой, иначе в невисокосный год в график попадёт несуществующая дата.

Функция ДнейВГоду(Год) Экспорт

Если ЭтоВисокосныйГод(Год) Тогда

Возврат 366;

Иначе

Возврат 365;

КонецЕсли;

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

Как проверить корректность функции

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

КонтрольныеГода = Новый Массив;

КонтрольныеГода.Добавить(2000); // високосный (делится на 400)

КонтрольныеГода.Добавить(1900); // невисокосный (делится на 100)

КонтрольныеГода.Добавить(2026); // високосный

КонтрольныеГода.Добавить(2023); // невисокосный

КонтрольныеГода.Добавить(2100); // невисокосный

Для Каждого Год Из КонтрольныеГода Цикл

Сообщить(Строка(Год) + ": " + ЭтоВисокосныйГод(Год));

КонецЦикла;

Ожидаемый результат: Истина для 2000 и 2026, Ложь для 1900, 2023 и 2100. Если на 1900 или 2100 функция возвращает Истина — потеряна проверка делимости на 100. Если на 2000 возвращает Ложь — потеряна проверка делимости на 400.

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

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

Год 2000
Норма

Функция возвращает Истина

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

Ложь — отсутствует условие делимости на 400

Год 1900 или 2100
Норма

Функция возвращает Ложь

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

Истина — отсутствует условие делимости на 100

Год 2026
Норма

Истина, последний день февраля — 29

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

Ложь или 28 февраля — ошибка в базовом условии

Дата(Год, 2, 29) в невисокосный год
Норма

Код не создаёт такую дату без проверки

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

Дата формируется без валидации — риск ошибки исполнения

Типичные ошибки и ограничения

Главная ошибка — упрощённая проверка только на делимость на 4. На ближайшие десятилетия она будет работать корректно, и дефект проявится только в 2100 году, поэтому такой код спокойно проходит тестирование и живёт в конфигурациях годами.

Вторая ошибка — путаница с типами. Если в функцию передать строку «2026» вместо числа, оператор % может отработать неочевидно или вызвать ошибку преобразования. Перед проверкой стоит явно привести значение к числу или проверить тип.

Третья ошибка — использование арифметики секунд без учёта её природы. Начинающие разработчики иногда пишут Дата + 1, ожидая прибавления одного дня, а получают прибавление одной секунды. Для суток нужно 86400, либо используйте ДобавитьМесяц для месячных сдвигов.

Типичные ошибки
01
Проверка только на делимость на 4 — в 2100 году код выдаст неверный результат, а дефект обнаружится слишком поздно
02
Передача строки вместо числа — ошибка преобразования типов или непредсказуемый результат оператора %
03
Дата + 1 вместо Дата + 86400 — прибавляется секунда, а не сутки, расчёты сдвигаются незаметно
04
Формирование Дата(Год, 2, 29) без проверки високосности — ошибка исполнения в невисокосный год

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

FAQ

Есть ли в 1С готовая функция определения високосного года?

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

Как узнать количество дней в феврале конкретного года?

Вычтите одни сутки из 1 марта: Дата(Год, 3, 1) - 86400. День получившейся даты — 28 или 29 — и есть количество дней в феврале. Тот же приём работает для любого месяца: возьмите первое число следующего месяца и отнимите сутки.

Что будет, если создать дату Дата(2023, 2, 29)?

2023 год невисокосный, и такая дата недопустима. В зависимости от контекста платформа либо выдаст ошибку исполнения, либо значение будет приведено некорректно. Поэтому перед формированием даты 29 февраля всегда проверяйте високосность года.

Работает ли оператор % в английском синтаксисе 1С?

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

Нужно ли учитывать високосный год при расчёте среднедневного заработка?

Да, если методика расчёта делит годовую сумму на количество календарных дней. В високосный год делитель равен 366, и использование 365 занижает среднедневное значение. Конкретный делитель определяется методикой расчёта, закреплённой в учётной политике и нормативных документах.

Можно ли определить високосность через запрос к базе данных?

Да, в языке запросов доступны функции работы с датами, включая ГОД и ДЕНЬ. Можно построить выражение: взять дату 1 марта нужного года, добавить -1 день через ДОБАВИТЬКДАТЕ и проверить день результата. Однако для разовой проверки проще выполнить расчёт в коде, а запрос использовать, когда проверка нужна прямо в выборке данных.

Итог

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

Готовой функции в 1С нет — используйте проверку (Год % 4 = 0 И Год % 100 <> 0) ИЛИ Год % 400 = 0, либо приём Дата(Год,3,1) - 86400. Всегда тестируйте на граничных годах 1900, 2000 и 2100, а изменения в общих модулях внедряйте через копию базы.