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