Время суток из значения «Дата и время»: приёмы для кода и запросов 1С

· 9 мин

Содержание

Чтобы выделить время из даты в 1С 8.3, вычтите из значения начало его дня: Д - НачалоДня(Д) даёт число секунд от полуночи. Нужны отдельные часы и минуты — берите функции Час(Д), Минута(Д), Секунда(Д). Нужно значение типа «Дата» с одним временем — прибавьте эти секунды к Дата(1, 1, 1).

Какой способ выбрать, зависит от задачи. Для вывода на экран хватит Формат(). Для сравнения и вычислений удобнее секунды. В запросе работают ЧАС(), МИНУТА() и РАЗНОСТЬДАТ(). Всё это общее для платформы 1С:Предприятие 8.3 и не зависит от конфигурации: код одинаково работает в Бухгалтерии, ЗУП, УТ и в своих разработках.

Как платформа хранит дату и время

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

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

  • 📏 Точность — одна секунда. Миллисекунд в значении типа «Дата» нет.
  • 📅 Диапазон — от 01.01.0001 00:00:00 до 31.12.3999 23:59:59.
  • ➖ Разность двух дат — это число секунд, а не дата.
  • ➕ Дата плюс число — дата, сдвинутая на столько секунд.
  • 🕛 Пустая дата — это 01.01.0001 00:00:00, литерал '00010101000000'.

Последний пункт ниже станет главной ловушкой. Значение «только время» платформа хранит как дату 01.01.0001 с нужными часами и минутами. А полночь в таком представлении совпадает с пустой датой.

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

В коде то же самое задаётся квалификатором:

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

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

Значение «только время»: как его получить без функции Время()

Функции Время() во встроенном языке нет, хотя её часто ищут по аналогии с Дата(). Время собирают одним из трёх способов.

Способ 1. Конструктор Дата() с нулевой датой.

Д = ТекущаяДатаСеанса();
ТолькоВремя = Дата(1, 1, 1, Час(Д), Минута(Д), Секунда(Д));

Читается проще всех. Удобен, когда время складывается из отдельных чисел, например из полей «Часы» и «Минуты» на форме.

Способ 2. Сдвиг нулевой даты на секунды от начала дня.

ТолькоВремя = Дата(1, 1, 1) + (Д - НачалоДня(Д));

Один вызов функции вместо трёх. Этот вариант хорош в циклах по большим выборкам.

Способ 3. Приведение через описание типов.

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

Пригодится, когда тип значения заранее неизвестен: ПривестиЗначение отбросит дату и не упадёт на значении другого типа, а вернёт пустое значение.

СпособКогда братьНа что смотреть
Дата(1, 1, 1, Ч, М, С)время собирается из частейчасы 0–23, минуты и секунды 0–59, иначе ошибка
Дата(1, 1, 1) + (Д - НачалоДня(Д))быстрые вычисления в циклеисходное значение должно быть датой
ПривестиЗначениетип на входе не гарантированна чужом типе получите пустую дату, а не ошибку

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

ДатаИВремя = НачалоДня(ДатаДокумента) + (ВремяСобытия - НачалоДня(ВремяСобытия));

Если ВремяСобытия уже хранится как «только время», можно написать короче: НачалоДня(ДатаДокумента) + (ВремяСобытия - Дата(1, 1, 1)).

Часы, минуты и секунды через арифметику

Функции Час(), Минута() и Секунда() возвращают числа. Для большинства задач их достаточно:

Д = '20261007143725';   // 07.10.2026 14:37:25
Ч = Час(Д);      // 14
М = Минута(Д);   // 37
С = Секунда(Д);  // 25

Иногда удобнее держать время одним числом — количеством секунд от полуночи. Так его проще сравнивать, складывать и хранить в реквизите типа «Число».

СекундОтНачалаДня = Д - НачалоДня(Д);           // 52645
Часы    = Цел(СекундОтНачалаДня / 3600);          // 14
Минуты  = Цел((СекундОтНачалаДня % 3600) / 60);   // 37
Секунды = СекундОтНачалаДня % 60;                 // 25

Проверка арифметики: 14 × 3600 + 37 × 60 + 25 = 50 400 + 2 220 + 25 = 52 645 секунд.

Пара полезных констант:

  • ⏱ час — 3 600 секунд;
  • 📆 сутки — 86 400 секунд;
  • 🗓 неделя — 604 800 секунд.

Время в минутах от полуночи — частый формат для графиков работы и расписаний. Считается так: Цел((Д - НачалоДня(Д)) / 60). Для 14:37:25 получится 877.

Если нужны доли секунды, например для замера скорости кода, тип «Дата» не поможет. Используйте ТекущаяУниверсальнаяДатаВМиллисекундах(): она возвращает число, и разность двух вызовов даёт длительность в миллисекундах.

Время из даты в запросе

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

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

Запрос вернёт документы, проведённые после 18:00 за выбранный период. Имя документа здесь из Бухгалтерии 3.0, в своей конфигурации подставьте нужный объект.

Отбор по времени с точностью до минуты удобнее делать через секунды. Передайте в параметр число и сравнивайте с разностью дат:

ГДЕ
	РАЗНОСТЬДАТ(НАЧАЛОПЕРИОДА(Док.Дата, ДЕНЬ), Док.Дата, СЕКУНДА) > &СекундОтсечки

Для отсечки 17:30 параметр равен 17 × 3600 + 30 × 60 = 63 000.

Функции над полем (ЧАС(), РАЗНОСТЬДАТ()) не используют индекс по дате. На больших таблицах сначала ограничьте период обычным условием по полю Дата, а уже потом отбирайте по часам. Иначе СУБД переберёт всю таблицу.

В системе компоновки данных (СКД) вывести только время можно без правки запроса. В параметре поля «Формат» укажите строку ДФ=ЧЧ:мм — в отчёте останутся часы и минуты.

Пустая дата, полночь и чужие типы

Здесь собраны случаи, на которых код с временем ломается чаще всего.

Полночь неотличима от пустой даты. Значение Дата(1, 1, 1, 0, 0, 0) — это одновременно «00:00:00» и пустая дата. Отсюда три следствия:

  1. ЗначениеЗаполнено(ТолькоВремя) для полуночи вернёт Ложь.
  2. Формат() для полуночи вернёт пустую строку.
  3. Проверка обязательного заполнения на форме сочтёт поле пустым.

Если 00:00 — допустимое значение (начало смены, время отправки рейса), не проверяйте его через ЗначениеЗаполнено. Храните рядом признак «Время задано» или держите время числом секунд в реквизите типа «Число».

Пустая исходная дата. НачалоДня('00010101') вернёт ту же пустую дату, разность будет 0. Ошибки не будет, но вы получите «00:00» вместо отсутствующего значения. Проверяйте заполненность до выделения времени:

Если ЗначениеЗаполнено(Д) Тогда
	СекундОтНачалаДня = Д - НачалоДня(Д);
Иначе
	СекундОтНачалаДня = Неопределено;
КонецЕсли;

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

Если ТипЗнч(Значение) = Тип("Дата") Тогда
	// выделяем время
КонецЕсли;

Время пришло строкой. Для строки вида «14:30» разберите её на части:

Части = СтрРазделить("14:30", ":");
ТолькоВремя = Дата(1, 1, 1, Число(Части[0]), Число(Части[1]), 0);

Строку в формате ISO 8601 вида 2026-10-07T14:30:00 надёжнее превратить в дату через XMLЗначение(Тип("Дата"), Строка). Строку из 14 цифр ГГГГММДДччммсс понимает и конструктор Дата("20261007143000").

Число() и Дата() вызывают исключение на некорректной строке. Если данные приходят извне, оберните разбор в Попытка … Исключение и запишите ошибку в журнал, а не роняйте всю загрузку.

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

Сравнение времени, интервалы и вывод на экран

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

Прямое сравнение Д1 > Д2 учитывает и дату. Чтобы сравнить только время, сведите оба значения к секундам от полуночи:

Функция СекундыСуток(Д)
	Возврат Д - НачалоДня(Д);
КонецФункции

Если СекундыСуток(Документ.Дата) > СекундыСуток(ВремяОтсечки) Тогда
	// документ создан позже отсечки
КонецЕсли;

Значения «только время» (с датой 01.01.0001) можно сравнивать между собой напрямую: дата у них одинаковая.

Длительность интервала и переход через полночь

Разность двух значений «только время» — длительность в секундах. Если смена начинается в 22:00 и кончается в 06:00, разность выйдет отрицательной: −57 600. Добавьте сутки:

Длительность = КонецСмены - НачалоСмены;
Если Длительность < 0 Тогда
	Длительность = Длительность + 86400;   // −57 600 + 86 400 = 28 800, то есть 8 часов
КонецЕсли;

Форматы вывода

ЗадачаВыражениеРезультат для 14:07:05
время по локальному форматуФормат(Д, "ДЛФ=В")14:07:05
часы и минуты, 24 часаФормат(Д, "ДФ=ЧЧ:мм")14:07
с секундамиФормат(Д, "ДФ=ЧЧ:мм:сс")14:07:05
полночь не пропадаетФормат(Т, "ДФ=ЧЧ:мм; ДП='00:00'")для 00:00 — «00:00»

В строке формата регистр важен: ММ — месяц, мм — минуты; ЧЧ — часы от 0 до 23, чч — в 12-часовом формате. Перепутанный регистр — частая причина «странного» времени вроде 14:10, когда на часах 14:37 (выведен месяц октябрь).

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

Длительность больше суток

Формат() с ДФ для длительности не подходит: 30 часов он покажет как 06:00 следующего дня. Соберите строку сами:

Функция ДлительностьСтрокой(Секунд)
	Часы    = Цел(Секунд / 3600);
	Минуты  = Цел((Секунд % 3600) / 60);
	Сек     = Секунд % 60;
	Возврат СтрШаблон("%1:%2:%3",
		Формат(Часы, "ЧН=0; ЧГ=0"),
		Формат(Минуты, "ЧЦ=2; ЧВН=; ЧН=00"),
		Формат(Сек, "ЧЦ=2; ЧВН=; ЧН=00"));
КонецФункции

// ДлительностьСтрокой(108125) → "30:02:05"

Проверка: 30 × 3600 + 2 × 60 + 5 = 108 000 + 120 + 5 = 108 125. ЧГ=0 убирает пробел-разделитель групп у больших часов, ЧВН= добавляет ведущий ноль к минутам и секундам, а ЧН не даёт нулю превратиться в пустую строку.

Проверьте себя
Что вернёт выражение Д - НачалоДня(Д)?
Почему Формат(Т, "ДФ=ЧЧ:мм") может вернуть пустую строку?
Как найти длительность смены с 22:00 до 06:00 в секундах?

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

Можно ли хранить время в реквизите справочника?
Да. Создайте реквизит типа «Дата» и в свойстве «Состав даты» выберите «Время». В базе он хранится как дата 01.01.0001 с выбранным временем, а на форме пользователь видит только часы и минуты.
Как получить текущее время без даты?
Код Дата(1, 1, 1) + (ТекущаяДатаСеанса() - НачалоДня(ТекущаяДатаСеанса())). Лучше сначала сохранить ТекущаяДатаСеанса() в переменную: два вызова на границе секунды могут вернуть разные значения.
Как округлить время до часа или до 15 минут?
До начала часа — функция НачалоЧаса(Д). До 15 минут вниз — НачалоДня(Д) + Цел((Д - НачалоДня(Д)) / 900) * 900, где 900 — секунд в 15 минутах.
Чем НачалоДня() отличается от НАЧАЛОПЕРИОДА(..., ДЕНЬ)?
Результат одинаковый. НачалоДня() — функция встроенного языка для кода модулей, НАЧАЛОПЕРИОДА() — функция языка запросов. В тексте запроса функции встроенного языка не работают, и наоборот.
Как прибавить к дате 2 часа 30 минут?
Прибавьте секунды: Д + 2 * 3600 + 30 * 60, то есть Д + 9000. В запросе то же делают через ДОБАВИТЬКДАТЕ(Поле, МИНУТА, 150).