Время без даты в 1С 8.3: вычитание НачалоДня, Формат и РАЗНОСТЬДАТ

· 9 мин

Содержание

Чтобы выделить время из даты в 1С 8.3, вычтите из значения начало его дня: Секунды = Дата - НачалоДня(Дата). Получится число секунд с полуночи. Если время нужно именно значением типа «Дата», прибавьте эти секунды к пустой дате: Время = Дата(1, 1, 1) + (Дата - НачалоДня(Дата)). А если нужна строка для вывода, хватит Формат(Дата, "ДФ=ЧЧ:мм:сс").

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

Как устроен тип «Дата» и где в нём хранится время

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

Что из этого следует на практике:

  • 📅 «Дата без времени» — это та же дата, у которой время равно 00:00:00.
  • ⏰ «Время без даты» — это дата 01.01.0001 с нужными часами, минутами и секундами.
  • 🕛 Значение 01.01.0001 00:00:00 — пустая дата. Её возвращает Дата(1, 1, 1).
  • ⏱ Миллисекунд в значении типа «Дата» нет. Для замеров есть отдельная функция ТекущаяУниверсальнаяДатаВМиллисекундах(), она возвращает число.

Что именно пользователь увидит и сможет ввести в реквизите, задаёт квалификатор даты в Конфигураторе. Вариантов три:

КвалификаторЧто показывает полеЧто лежит в базе
Дататолько деньдата с временем 00:00:00
Времятолько часы и минуты/секундыдата 01.01.0001 + время
Дата и времявсё целикомполное значение

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

ОписаниеВремени = Новый ОписаниеТипов("Дата", , , Новый КвалификаторыДаты(ЧастиДаты.Время));
ТЗ.Колонки.Добавить("ВремяНачала", ОписаниеВремени, "Время начала");

Квалификатор влияет на отображение и ввод. Записывая значение в реквизит с квалификатором «Время» из кода, сразу передавайте дату 01.01.0001 с нужным временем — так значение одинаково отобразится в форме и будет корректно сравниваться в запросах.

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

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

Способ 1. Вычитание начала дня

Разность двух дат в 1С — это число секунд. На этом построен самый короткий приём:

Д = Дата(2026, 10, 7, 14, 35, 20);

СекундСПолуночи = Д - НачалоДня(Д);          // 52520
ВремяКакДата = Дата(1, 1, 1) + СекундСПолуночи; // 01.01.0001 14:35:20

Проверка: 14 × 3600 + 35 × 60 + 20 = 50 400 + 2 100 + 20 = 52 520 секунд.

Число секунд удобно для сравнения и арифметики. Дата 01.01.0001 ЧЧ:мм:сс — для записи в реквизит с квалификатором «Время» и для вывода через Формат.

Способ 2. Сборка из компонентов

Тот же результат даёт конструктор Дата() с шестью параметрами:

ВремяКакДата = Дата(1, 1, 1, Час(Д), Минута(Д), Секунда(Д));

Код длиннее, зато нагляднее. Его легко поменять, например отбросить секунды: Дата(1, 1, 1, Час(Д), Минута(Д), 0).

Способ 3. Строка через Формат

Когда время нужно только показать — в сообщении, имени файла, печатной форме, — не надо ничего вычислять:

Строка1 = Формат(Д, "ДФ=ЧЧ:мм:сс"); // "14:35:20"
Строка2 = Формат(Д, "ДФ=ЧЧ:мм");    // "14:35"
Строка3 = Формат(Д, "ДЛФ=В");       // время в формате по умолчанию

В форматной строке ДФ регистр букв важен:

СимволЧто выводит
ЧЧчасы 00–23 с ведущим нулём
Ччасы 0–23 без ведущего нуля
чччасы в 12-часовом формате
ммминуты (строчная «м»)
сссекунды
ММмесяц (заглавная «М») — частая путаница с минутами

Формат(Д, "ДФ=ЧЧ:ММ") выведет не часы и минуты, а часы и месяц. Строка «14:10» в октябре выглядит правдоподобно, поэтому ошибку замечают не сразу.

Какой способ выбрать

ЗадачаСпособРезультат
Сравнить время двух событийвычитание начала днячисло
Записать в реквизит «Время»Дата(1,1,1) + секунды или сборкадата 01.01.0001
Показать пользователюФормат с ДФстрока
Посчитать длительностьразность датчисло секунд

Обнулить дату и оставить только время — и обратная задача

Обнулить дату с сохранением времени — это и есть способ 1: Дата(1, 1, 1) + (Д - НачалоДня(Д)). Обратная задача — обнулить время и оставить день — решается ещё проще: НачалоДня(Д).

Часто нужно склеить два значения: день из одного поля, время из другого. Например, в форме есть поле «Дата встречи» с квалификатором «Дата» и поле «Время встречи» с квалификатором «Время»:

ДатаВстречи  = Дата(2026, 10, 7);           // 07.10.2026 00:00:00
ВремяВстречи = Дата(1, 1, 1, 11, 30, 0);    // 01.01.0001 11:30:00

Начало = НачалоДня(ДатаВстречи) + (ВремяВстречи - Дата(1, 1, 1));
// 07.10.2026 11:30:00

НачалоДня() у даты встречи — страховка: если там всё же окажется время, оно не сложится с временем встречи.

Ещё несколько функций, которые «обрезают» дату до нужной точности:

  • ✂️ НачалоЧаса(Д) — отбросить минуты и секунды.
  • ✂️ НачалоМинуты(Д) — отбросить секунды.
  • 🔚 КонецДня(Д) — тот же день, 23:59:59.
  • 🔚 КонецЧаса(Д), КонецМинуты(Д) — аналогично для часа и минуты.

Часы, минуты, секунды: работа с частями даты и времени

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

ФункцияПример для 07.10.2026 14:35:20
Год(Д)2026
Месяц(Д)10
День(Д)7
Час(Д)14
Минута(Д)35
Секунда(Д)20
ДеньНедели(Д)3 (среда, понедельник = 1)
ДеньГода(Д)280

Проверка дня года: январь–сентябрь 2026 года — 273 дня (31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30), плюс 7 дней октября = 280.

Сдвинуть время на часы и минуты

Прибавление числа к дате сдвигает её на столько же секунд:

ЧерезПолтораЧаса = Д + 90 * 60;   // 16:05:20
ВчераВТоЖеВремя  = Д - 86400;     // 06.10.2026 14:35:20

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

Перевести секунды в «ЧЧ:мм» и обратно

Время в число секунд: Час(Д) * 3600 + Минута(Д) * 60 + Секунда(Д).

Обратно, если секунд меньше суток (86 400), удобно использовать пустую дату:

Секунд = 5400;
Текст = Формат(Дата(1, 1, 1) + Секунд, "ДФ=ЧЧ:мм"); // "01:30"

Длительность больше суток так не покажешь: 90 000 секунд превратятся в «01:00» следующего дня. Для таких случаев считайте вручную:

Секунд = 90000;
Часов  = Цел(Секунд / 3600);              // 25
Минут  = Цел((Секунд - Часов * 3600) / 60); // 0
Текст  = СтрШаблон("%1 ч %2 мин", Формат(Часов, "ЧН=0; ЧГ=0"), Формат(Минут, "ЧН=0; ЧГ=0"));
// "25 ч 0 мин"

ЧН=0 нужен, чтобы ноль вывелся цифрой, а не пустой строкой. ЧГ=0 убирает пробел-разделитель групп разрядов.

Сравнить только время двух дат

Если события из разных дней надо сравнить по времени, сравнивайте секунды с полуночи:

Раньше = (Д1 - НачалоДня(Д1)) < (Д2 - НачалоДня(Д2));

Прямое Д1 < Д2 сравнит ещё и дни.

Проверить, попадает ли время в интервал, в том числе через полночь

Типичная задача — понять, создан ли документ в ночную смену с 22:00 до 06:00. Интервал переходит через полночь, поэтому простое «больше начала и меньше конца» не сработает: ни одно время не будет одновременно больше 22:00 и меньше 06:00.

Функция ВремяВИнтервале(Д, НачалоЧас, КонецЧас)
    Сек = Д - НачалоДня(Д);
    С   = НачалоЧас * 3600;
    По  = КонецЧас * 3600;
    Если С <= По Тогда
        Возврат Сек >= С И Сек < По;      // обычный интервал, например 9–18
    Иначе
        Возврат Сек >= С Или Сек < По;    // через полночь, например 22–6
    КонецЕсли;
КонецФункции

Для 23:15 функция вернёт Истина при интервале 22–6: 83 700 секунд больше 79 200. Для 07:00 — Ложь: 25 200 меньше 79 200 и при этом не меньше 21 600.

Выделение времени из даты в запросе 1С

В языке запросов свой набор функций. Части даты достают так же: ЧАС(), МИНУТА(), СЕКУНДА(), ДЕНЬНЕДЕЛИ(). Для обрезки и сдвига — НАЧАЛОПЕРИОДА(), КОНЕЦПЕРИОДА(), ДОБАВИТЬКДАТЕ() и РАЗНОСТЬДАТ().

Время как число секунд

ВЫБРАТЬ
    Док.Ссылка,
    Док.Дата,
    РАЗНОСТЬДАТ(НАЧАЛОПЕРИОДА(Док.Дата, ДЕНЬ), Док.Дата, СЕКУНДА) КАК СекундСПолуночи
ИЗ
    Документ.РеализацияТоваровУслуг КАК Док

Время как дата 01.01.0001

Хочется написать ДАТАВРЕМЯ(1, 1, 1, ЧАС(Док.Дата), МИНУТА(Док.Дата), 0), но так нельзя. Функция ДАТАВРЕМЯ в запросе принимает только числа-литералы, а не поля и выражения. Запрос с полями внутри не выполнится.

Рабочий вариант — прибавить секунды к пустой дате:

ДОБАВИТЬКДАТЕ(
    ДАТАВРЕМЯ(1, 1, 1),
    СЕКУНДА,
    РАЗНОСТЬДАТ(НАЧАЛОПЕРИОДА(Док.Дата, ДЕНЬ), Док.Дата, СЕКУНДА)
) КАК ВремяДокумента

Отбор по времени суток

Например, документы, созданные вне рабочего времени — до 9:00 или после 18:00:

ВЫБРАТЬ
    Док.Ссылка,
    Док.Дата
ИЗ
    Документ.РеализацияТоваровУслуг КАК Док
ГДЕ
    Док.Дата МЕЖДУ &НачалоПериода И &КонецПериода
    И (ЧАС(Док.Дата) < 9 ИЛИ ЧАС(Док.Дата) >= 18)

Параметры периода задайте в коде через НачалоДня и КонецДня:

Запрос.УстановитьПараметр("НачалоПериода", НачалоДня(ДатаС));
Запрос.УстановитьПараметр("КонецПериода", КонецДня(ДатаПо));

Имя документа в примерах — из типовых конфигураций на БСП. Подставьте свой объект метаданных.

Ошибки при работе со временем и скорость запросов

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

Почему функции в условии ГДЕ замедляют запрос

Условие ГДЕ ЧАС(Док.Дата) < 9 вычисляется для каждой строки. Индекс по полю «Дата» при этом не помогает: СУБД не может найти нужные строки по индексу, если поле обёрнуто в функцию. На таблице в миллионы документов это полный просмотр.

Как сделать быстрее:

  1. Сначала ограничьте период простым условием Док.Дата МЕЖДУ &НачалоПериода И &КонецПериода. Это условие использует индекс.
  2. Отбор по часу добавляйте вторым условием — он отработает уже по небольшой выборке.
  3. Не пишите НАЧАЛОПЕРИОДА(Док.Дата, ДЕНЬ) = &День. Замените на Док.Дата МЕЖДУ &НачалоДня И &КонецДня и вычислите границы в коде.
  4. Если отбор по времени суток нужен постоянно и на больших объёмах, храните время отдельным реквизитом (например, с квалификатором «Время») и при необходимости сделайте его индексируемым.

В СКД вычислять время в запросе часто не нужно вовсе. Для вывода достаточно задать полю ресурса или группировки свойство «Формат» со строкой ДФ=ЧЧ:мм.

Частые вопросы

Как получить текущее время без даты?
Возьмите текущую дату сеанса и отбросьте день: Дата(1, 1, 1) + (ТекущаяДатаСеанса() - НачалоДня(ТекущаяДатаСеанса())). Для строки достаточно Формат(ТекущаяДатаСеанса(), "ДФ=ЧЧ:мм").
Можно ли хранить в 1С время с миллисекундами?
Нет, тип «Дата» хранит время с точностью до секунды. Если миллисекунды нужны, храните их отдельным реквизитом-числом или сохраняйте результат ТекущаяУниверсальнаяДатаВМиллисекундах().
Как получить время из строки «14:35»?
Разберите строку на части и соберите дату: Части = СтрРазделить("14:35", ":"), затем Дата(1, 1, 1, Число(Части[0]), Число(Части[1]), 0). Для неверного ввода оберните преобразование в Попытка.
Как посчитать, сколько часов прошло между двумя датами?
Вычтите одну дату из другой и разделите на 3600: (Д2 - Д1) / 3600. В запросе — РАЗНОСТЬДАТ(Д1, Д2, ЧАС), но она отбрасывает неполные часы, поэтому для точности берите секунды и делите сами.
Как перевести время в UTC и обратно?
Для этого есть УниверсальноеВремя(Д) и МестноеВремя(Д). Вторым параметром можно передать часовой пояс, иначе берётся пояс сеанса.