При разработке на старой платформе 1С:Предприятие 7.7 мы часто сталкиваемся с существенным ограничением: базовый тип данных Дата содержит только саму дату, без времени. Из-за этого возникает потребность придумывать собственные форматы и алгоритмы для сохранения точного времени создания документов, фиксации событий или расчета разницы между двумя моментами. В этой статье мы подробно разберем, как лучше всего хранить дату и время, проанализируем различные подходы и рассмотрим готовые функции.
Один из самых простых и популярных способов — хранить дату и время в виде текстовой строки. Наиболее удобным форматом для этого является объединение элементов от большего к меньшему: год, месяц, день, часы, минуты, секунды. Например: ГГГГ_ММ_ДД_ЧЧ_ММ_СС (или без подчеркиваний — ГГГГММДДЧЧММСС).
Рассмотрим преимущества такого подхода. Во-первых, такие строки естественным образом поддаются лексикографической сортировке. Событие, произошедшее позже, при сортировке по алфавиту всегда окажется ниже. Во-вторых, этот формат легко читается человеком без дополнительных преобразований. По сути, он очень близок к международному стандарту ISO 8601, который в современных системах выглядит как YYYY-MM-DDThh:mm:ss.
Посмотрим на пример кода, который позволяет преобразовать такую строку в число для расчетов:
Функция ДатаВЧисло(ДВ)
// ДВ передается в формате ГГГГ_ММ_ДД_ЧЧ_ММ_СС
ГГГГ = Число(Лев(ДВ,4));
МС = Число(Сред(ДВ,6,2));
ДД = Число(Сред(ДВ,9,2));
ЧЧ = Число(Сред(ДВ,12,2));
ММ = Число(Сред(ДВ,15,2));
СС = Число(Прав(ДВ,2));
// Переводим дату в секунды
ЧДата = Число(Дата(ГГГГ,МС,ДД)) * 86400;
ЧВремя = ЧЧ * 3600 + ММ * 60 + СС;
Возврат (ЧДата + ЧВремя);
КонецФункции
Хотя строковый формат удобен для восприятия, он неэффективен с точки зрения хранения в базе данных. Если по этому полю нужно делать частые выборки (например, искать документы за определенный час), строковые индексы будут работать медленнее числовых. Гораздо более грамотным решением будет перевод даты и времени в абсолютное число секунд.
Проанализируем этот метод. Мы можем взять определенную "точку отсчета". Чаще всего в мире IT используется так называемое UNIX-время — количество секунд, прошедших с 1 января 1970 года. Другой вариант — считать секунды с Рождества Христова (или 01.01.0001, как это делается "под капотом" в платформе 1С 8.х).
Разберем пример функции, которая формирует уникальную временную позицию ("ХроноКод") на оси времени:
// Формирует уникальный код позиции на оси времени (в секундах)
Функция глХроноПозиция(ДатаХ, ВремяХ) Экспорт
Перем ЧасХ, МинХ, СекХ;
_ДатаХ = Число(ДатаХ);
// Парсим строку времени формата "ЧЧ:ММ:СС"
ЧасХ = Число(Лев(ВремяХ, 2));
МинХ = Число(Сред(ВремяХ, 4, 2));
СекХ = Число(Прав(ВремяХ, 2));
// 86400 - секунд в сутках, 3600 - секунд в часе
Возврат _ДатаХ * 86400 + ЧасХ * 3600 + МинХ * 60 + СС;
КонецФункции
А вот функция для обратного преобразования числа в привычную связку даты и времени:
Функция глПозицияХроно(Знач ПозицияХ, ДатаХ=0, ВремяХ="00:00:00") Экспорт
_ДатаХ = Цел(ПозицияХ / 86400);
ПозицияХ = ПозицияХ - (_ДатаХ * 86400);
ЧасХ = Цел(ПозицияХ / 3600);
ПозицияХ = ПозицияХ - (ЧасХ * 3600);
МинХ = Цел(ПозицияХ / 60);
СекХ = ПозицияХ - (МинХ * 60);
ДатаХ = Дата(_ДатаХ);
ВремяХ = Формат(ЧасХ,"Ч(0)2") + ":" + Формат(МинХ,"Ч(0)2") + ":" + Формат(СекХ,"Ч(0)2");
Возврат "" + ДатаХ + " " + ВремяХ;
КонецФункции
Имея дату и время, переведенные в единое числовое значение (секунды), мы избавляемся от сложной математики при расчете разницы. Выясним причину: чтобы узнать, сколько дней, часов и минут прошло между двумя событиями, достаточно просто вычесть одно значение из другого.
Рассмотрим по шагам алгоритм извлечения дней, часов и минут из полученной разницы:
Процедура РассчитатьРазницу(ДатаЧисло1, ДатаЧисло2)
Разница = ДатаЧисло1 - ДатаЧисло2;
Если Разница < 0 Тогда
Разница = -Разница;
КонецЕсли;
КоличествоДней = Цел(Разница / 86400);
Остаток = Разница - (КоличествоДней * 86400);
КоличествоЧасов = Цел(Остаток / 3600);
Остаток = Остаток - (КоличествоЧасов * 3600);
КоличествоМинут = Цел(Остаток / 60);
КоличествоСекунд = Остаток % 60;
Сообщить("Прошло: " + КоличествоДней + " дн. " + КоличествоЧасов + " ч. " + КоличествоМинут + " мин.");
КонецПроцедуры
Разберем еще несколько критически важных моментов, которые обязательно нужно учитывать при архитектурном планировании хранения времени в системе:
DATETIME. Искусственное разделение в 7.7 — это лишь ограничение самой платформы, которое обходится методами, описанными выше.Дата изначально включает в себя время до секунды. Вычисление разницы там осуществляется простым математическим вычитанием Дата1 - Дата2.Подводя итог: если вам требуется просто визуальная фиксация события — склеивайте дату и время в строку ГГГГММДДЧЧММСС. Но если вам необходима максимальная производительность, сортировка в запросах и расчет интервалов — обязательно переводите дату и время в абсолютное числовое значение (количество секунд) с помощью пользовательских функций.