Тип Дата во встроенном языке 1С 8.3: от литерала до отбора в запросе

· 10 мин

Содержание

Дата в 1С — это одно значение «дата + время» с точностью до секунды. Работать с датами в 1С значит опираться на четыре правила: прибавление числа сдвигает дату на секунды, ДобавитьМесяц() сдвигает на месяцы, НачалоМесяца()/КонецДня() дают границы периода, а Формат() превращает дату в строку для пользователя.

Всё ниже относится к платформе 1С:Предприятие 8.3 и не зависит от конфигурации: одинаково работает в Бухгалтерии 3.0, ЗУП 3.1, УТ 11 и в собственных разработках. Примеры даны для даты 15 марта 2024 года, 14:05:09 — так их удобно проверить в отладчике.

Как устроен тип Дата: хранение, литералы и пустое значение

Значение типа Дата всегда содержит и календарную дату, и время. Отдельного типа «только время» или «только дата» в языке нет. Диапазон — от 01.01.0001 00:00:00 до 31.12.9999 23:59:59.

Часового пояса внутри значения нет. 1С хранит «голые» числа: год, месяц, день, часы, минуты, секунды. Какой это пояс, решает код, который дату записал.

Три способа получить дату в коде

Д1 = '20240315';                 // литерал: только дата, время 00:00:00
Д2 = '20240315140509';           // литерал с временем
Д3 = Дата(2024, 3, 15, 14, 5, 9); // конструктор из чисел
Д4 = Дата("20240315140509");     // из строки формата ГГГГММДДччммсс

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

Пустая дата

Пустая дата — это '00010101000000', то есть 1 января 1 года. Так выглядит незаполненный реквизит документа или параметр, который никто не передал.

  • ✅ Проверка «заполнена ли дата»: ЗначениеЗаполнено(ДатаДокумента).
  • ✅ Явное сравнение: ДатаДокумента = Дата(1, 1, 1).
  • ❌ Сравнение с Неопределено не сработает: у реквизита типа Дата пустое значение — не Неопределено.

Состав даты в метаданных

У реквизита типа Дата в конфигураторе задаётся квалификатор «Состав даты»: Дата, Время или Дата и время. Он управляет только вводом и показом на форме.

При составе «Дата» в базе всё равно лежит полное значение со временем 00:00:00. При составе «Время» дата становится 01.01.0001, а время сохраняется. Учитывайте это при сравнении таких реквизитов между собой.

Сложение и вычитание дат: секунды, дни, месяцы

Арифметика с датами в 1С идёт в секундах. Других единиц у операторов + и - нет.

ОперацияРезультатПример
Дата + ЧислоДата, сдвинутая на N секунд'20240315' + 3600 → 15.03.2024 01:00:00
Дата − ЧислоДата, сдвинутая назад'20240315' - 86400 → 14.03.2024
Дата − ДатаЧисло секунд между датами'20240315' - '20240301' → 1 209 600
Дата + ДатаОшибкатак нельзя

Сдвиг на дни и недели

В сутках 86 400 секунд. Отсюда простые формулы:

Завтра      = НачалоДня(ТекущаяДатаСеанса()) + 86400;
ЧерезНеделю = НачалоДня(ТекущаяДатаСеанса()) + 7 * 86400;

Количество дней между датами получают делением разности на 86 400. Если у дат есть время, результат будет дробным. Поэтому сначала обрежьте время:

Дней = (НачалоДня(ДатаКон) - НачалоДня(ДатаНач)) / 86400;
// 15.03.2024 и 01.03.2024 → 14
// включительно (обе даты в периоде) → прибавьте 1, будет 15

Сдвиг на месяцы, кварталы и годы — только ДобавитьМесяц

Месяцы разной длины, поэтому + 30 * 86400 даёт неверный результат. Для календарного сдвига есть ДобавитьМесяц(Дата, КоличествоМесяцев):

ДобавитьМесяц('20240315', 1);   // 15.04.2024
ДобавитьМесяц('20240315', -3);  // 15.12.2023 — минус квартал
ДобавитьМесяц('20240315', 12);  // 15.03.2025 — плюс год
ДобавитьМесяц('20240131', 1);   // 29.02.2024 — день «поджимается» к концу месяца

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

Пример: полных лет между датами

Задача из кадрового учёта и проверок договоров: сколько полных лет прошло с даты рождения или даты приёма.

Функция ПолныхЛет(ДатаНачала, ДатаНаКоторую) Экспорт
	Лет = Год(ДатаНаКоторую) - Год(ДатаНачала);
	Если ДобавитьМесяц(ДатаНачала, Лет * 12) > ДатаНаКоторую Тогда
		Лет = Лет - 1;
	КонецЕсли;
	Возврат Лет;
КонецФункции

Для рождения 20.05.1990 на 15.03.2024: разность годов 34, но 20.05.2024 ещё не наступило — функция вернёт 33.

Начало и конец периода: функции границ дат в 1С

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

ФункцияРезультат для 15.03.2024 14:05:09
НачалоГода() / КонецГода()01.01.2024 00:00:00 / 31.12.2024 23:59:59
НачалоКвартала() / КонецКвартала()01.01.2024 00:00:00 / 31.03.2024 23:59:59
НачалоМесяца() / КонецМесяца()01.03.2024 00:00:00 / 31.03.2024 23:59:59
НачалоНедели() / КонецНедели()11.03.2024 00:00:00 / 17.03.2024 23:59:59
НачалоДня() / КонецДня()15.03.2024 00:00:00 / 15.03.2024 23:59:59
НачалоЧаса() / КонецЧаса()15.03.2024 14:00:00 / 15.03.2024 14:59:59
НачалоМинуты() / КонецМинуты()15.03.2024 14:05:00 / 15.03.2024 14:05:59

Неделя в 1С начинается с понедельника. Функции «Конец…» возвращают последнюю секунду периода, а не начало следующего.

Полезные комбинации

// Последний день прошлого месяца
КонецПрошлогоМесяца = НачалоМесяца(Дата) - 1;          // 29.02.2024 23:59:59

// Первое число следующего месяца
НачалоСледующего = КонецМесяца(Дата) + 1;               // 01.04.2024 00:00:00

// Сколько дней в месяце
ДнейВМесяце = День(КонецМесяца(Дата));                  // 31

// Одна ли это календарная дата (время не важно)
ОдинДень = (НачалоДня(Д1) = НачалоДня(Д2));

Приём «минус одна секунда от начала» и «плюс одна секунда к концу» надёжнее, чем вычитание дней: он не зависит от длины месяца.

Части даты: год, квартал, день недели

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

  • 📅 Год(Д) → 2024, Месяц(Д) → 3, День(Д) → 15.
  • 🕑 Час(Д) → 14, Минута(Д) → 5, Секунда(Д) → 9.
  • 📆 ДеньНедели(Д) → 5: понедельник = 1, воскресенье = 7.
  • 🔢 ДеньГода(Д) → 75 (31 + 29 + 15, год високосный).
  • 📊 НеделяГода(Д) → номер недели в году.

Отдельной функции «номер квартала» во встроенном языке нет. Его считают от месяца:

Квартал = Цел((Месяц(Д) - 1) / 3) + 1;   // март → 1, апрель → 2

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

Форматирование дат в 1С для пользователя

Для вывода в печатную форму, сообщение или имя файла дату превращают в строку функцией Формат(). Простое Строка(Д) даёт 15.03.2024 14:05:09 и зависит от языка сеанса — для печати это слабый вариант.

Готовые форматы ДЛФ

Параметр ДЛФ (локальный формат) выбирает один из стандартных видов:

ВызовРезультат
Формат(Д, "ДЛФ=D")15.03.2024
Формат(Д, "ДЛФ=DD")15 марта 2024 г.
Формат(Д, "ДЛФ=T")14:05:09
Формат(Д, "ДЛФ=DT")15.03.2024 14:05:09

Свой шаблон ДФ

Параметр ДФ задаёт шаблон вручную. Символы можно писать латиницей или кириллицей: dd.MM.yyyy и дд.ММ.гггг равнозначны. Шаблон с пробелами берите в одинарные кавычки.

ШаблонРезультат
"ДФ=dd.MM.yyyy"15.03.2024
"ДФ='dd MMMM yyyy'"15 марта 2024
"ДФ=yyyyMMdd"20240315
"ДФ='HH:mm'"14:05
"ДФ='dd.MM.yy HH:mm:ss'"15.03.24 14:05:09
"ДФ=dddd"пятница

Регистр символов важен: MM — месяц, mm — минуты. Перепутать их — классическая причина дат вида «15.05.2024» в 14:05.

HH — часы в 24-часовом формате, hh — в 12-часовом. Для русских документов почти всегда нужен HH.

Пустая дата в выводе

По умолчанию Формат() для пустой даты возвращает пустую строку. Чтобы вывести осмысленный текст, добавьте параметр ДП:

Текст = Формат(ДатаОплаты, "ДФ=dd.MM.yyyy; ДП='не оплачено'");

Период словами

Для заголовков отчётов есть ПредставлениеПериода(НачалоПериода, КонецПериода). Для 01.03.2024–31.03.2024 она вернёт строку вида «март 2024 г.». Собирать такие строки вручную не нужно.

Перевод строки в дату и обратно

Данные из Excel, файлов обмена и HTTP-сервисов приходят строкой. Конструктор Дата("...") понимает только сплошные цифры ГГГГММДД или ГГГГММДДччммсс. Строку «15.03.2024» он не разберёт.

Строка «ДД.ММ.ГГГГ»

Функция ДатаИзСтрокиДДММГГГГ(Знач Стр) Экспорт
	Стр = СокрЛП(Стр);
	Если СтрДлина(Стр) <> 10 Тогда
		Возврат Дата(1, 1, 1);
	КонецЕсли;
	Попытка
		Возврат Дата(Сред(Стр, 7, 4) + Сред(Стр, 4, 2) + Лев(Стр, 2));
	Исключение
		Возврат Дата(1, 1, 1);
	КонецПопытки;
КонецФункции

Для «15.03.2024» собирается строка «20240315», и получается 15.03.2024 00:00:00. Попытка нужна на случай мусора вроде «31.02.2024»: такую дату платформа не создаст и выдаст исключение.

Формат ISO 8601 для обменов

JSON и XML передают дату как 2024-03-15T14:05:09. Здесь пригодятся функции сериализации:

Стр = XMLСтрока(Д);                                   // "2024-03-15T14:05:09"
Д   = XMLЗначение(Тип("Дата"), "2024-03-15T14:05:09"); // обратно в Дату

Если в строке ISO есть смещение пояса (+03:00 или Z), заранее договоритесь со второй стороной обмена, в каком поясе хранится дата в 1С. Сам тип Дата смещение не хранит.

Даты в запросах 1С: параметры, функции периода, разность

Язык запросов имеет свой набор функций. Названия похожи на встроенный язык, но это другие функции, и синтаксис у них свой.

Константа даты и параметры

Дату в тексте запроса задают через ДАТАВРЕМЯ(2024, 3, 15) или ДАТАВРЕМЯ(2024, 3, 15, 23, 59, 59). Внутри ДАТАВРЕМЯ допустимы только числа, поля и параметры туда не передать.

На практике даты передают параметрами — текст запроса остаётся неизменным, а границы считает код:

Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
|	Док.Ссылка,
|	Док.Дата
|ИЗ
|	Документ.РеализацияТоваровУслуг КАК Док
|ГДЕ
|	Док.Дата МЕЖДУ &ДатаНач И &ДатаКон";
Запрос.УстановитьПараметр("ДатаНач", НачалоДня(ДатаНач));
Запрос.УстановитьПараметр("ДатаКон", КонецДня(ДатаКон));

КонецДня() в параметре — обязательная деталь. Без неё в отбор не попадут документы последнего дня, проведённые после 00:00:00.

Функции дат в языке запросов

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

Для НАЧАЛОПЕРИОДА и КОНЕЦПЕРИОДА доступны периоды МИНУТА, ЧАС, ДЕНЬ, НЕДЕЛЯ, ДЕКАДА, МЕСЯЦ, КВАРТАЛ, ПОЛУГОДИЕ, ГОД. У запроса, в отличие от встроенного языка, квартал считается одной функцией.

Группировка по месяцам

Типичная задача — продажи помесячно. Дату приводят к началу месяца и группируют по ней:

ВЫБРАТЬ
	НАЧАЛОПЕРИОДА(Продажи.Период, МЕСЯЦ) КАК Месяц,
	СУММА(Продажи.Сумма) КАК Сумма
ИЗ
	РегистрНакопления.Продажи КАК Продажи
ГДЕ
	Продажи.Период МЕЖДУ &ДатаНач И &ДатаКон
СГРУППИРОВАТЬ ПО
	НАЧАЛОПЕРИОДА(Продажи.Период, МЕСЯЦ)
УПОРЯДОЧИТЬ ПО
	Месяц

Тонкость РАЗНОСТЬДАТ

Функция считает, сколько границ периода лежит между датами, а не сколько полных периодов прошло. РАЗНОСТЬДАТ для 31.01.2024 и 01.02.2024 с периодом МЕСЯЦ вернёт 1, хотя прошёл один день. Для полных месяцев или лет проверяйте результат в коде, как в функции ПолныхЛет выше.

Остатки на дату

Виртуальная таблица Остатки(&Дата) берёт остатки на начало указанного момента. Документы с датой, равной параметру, в расчёт не входят. Чтобы включить движения последнего дня, передайте КонецДня(Дата) или объект Новый Граница(Дата, ВидГраницы.Включая).

Ошибки при работе с датами и как их не допустить

Ниже — ошибки, которые чаще всего всплывают в отчётах и обработках уже после сдачи задачи.

Диагностика: выберите симптом

ТекущаяДата или ТекущаяДатаСеанса

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

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

Проверьте себя
Что вернёт ДобавитьМесяц('20240131', 1)?
Какое значение у КонецДня('20240315')?
Какой ДеньНедели() у воскресенья?

Частые вопросы о датах в 1С

Как в 1С получить дату без времени?
Через НачалоДня(Дата). Время станет 00:00:00. В запросе то же делает НАЧАЛОПЕРИОДА(Дата, ДЕНЬ).
Как сравнить две даты без учёта времени?
Сравните их начала дня: НачалоДня(Д1) = НачалоДня(Д2). Прямое Д1 = Д2 даст «Ложь», если время отличается хотя бы на секунду.
Можно ли хранить в реквизите только время?
Да, задайте составу даты значение «Время». Дата в таком значении будет 01.01.0001, поэтому складывать его с другой датой нужно через секунды: НачалоДня(Д) + Час(Т) * 3600 + Минута(Т) * 60.
Как задать стандартный период «Этот месяц» в коде?
Через объект Новый СтандартныйПериод(ВариантСтандартногоПериода.ЭтотМесяц). Его свойства ДатаНачала и ДатаОкончания дают готовые границы.
Как проверить, високосный ли год?
Посчитайте дни февраля: День(КонецМесяца(Дата(Год, 2, 1))) = 29. Это короче и надёжнее, чем вручную проверять делимость года на 4, 100 и 400.