Как лучше хранить дату и время в 1С 7.7: решения и примеры кода

Программист 1С v7.7 IT и автоматизация бизнеса
← На главную

При разработке на старой платформе 1С:Предприятие 7.7 мы часто сталкиваемся с существенным ограничением: базовый тип данных Дата содержит только саму дату, без времени. Из-за этого возникает потребность придумывать собственные форматы и алгоритмы для сохранения точного времени создания документов, фиксации событий или расчета разницы между двумя моментами. В этой статье мы подробно разберем, как лучше всего хранить дату и время, проанализируем различные подходы и рассмотрим готовые функции.

Хранение в виде форматированной строки

Один из самых простых и популярных способов — хранить дату и время в виде текстовой строки. Наиболее удобным форматом для этого является объединение элементов от большего к меньшему: год, месяц, день, часы, минуты, секунды. Например: ГГГГ_ММ_ДД_ЧЧ_ММ_СС (или без подчеркиваний — ГГГГММДДЧЧММСС).

Рассмотрим преимущества такого подхода. Во-первых, такие строки естественным образом поддаются лексикографической сортировке. Событие, произошедшее позже, при сортировке по алфавиту всегда окажется ниже. Во-вторых, этот формат легко читается человеком без дополнительных преобразований. По сути, он очень близок к международному стандарту ISO 8601, который в современных системах выглядит как YYYY-MM-DDThh:mm:ss.

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


Функция ДатаВЧисло(ДВ)
    // ДВ передается в формате ГГГГ_ММ_ДД_ЧЧ_ММ_СС
    ГГГГ = Число(Лев(ДВ,4));
    МС   = Число(Сред(ДВ,6,2));
    ДД   = Число(Сред(ДВ,9,2));
    ЧЧ   = Число(Сред(ДВ,12,2));
    ММ   = Число(Сред(ДВ,15,2));
    СС   = Число(Прав(ДВ,2));
    
    // Переводим дату в секунды
    ЧДата  = Число(Дата(ГГГГ,МС,ДД)) * 86400; 
    ЧВремя = ЧЧ * 3600 + ММ * 60 + СС;
    
    Возврат (ЧДата + ЧВремя);
КонецФункции

Использование абсолютного числа (секунды и UNIX-время)

Хотя строковый формат удобен для восприятия, он неэффективен с точки зрения хранения в базе данных. Если по этому полю нужно делать частые выборки (например, искать документы за определенный час), строковые индексы будут работать медленнее числовых. Гораздо более грамотным решением будет перевод даты и времени в абсолютное число секунд.

Проанализируем этот метод. Мы можем взять определенную "точку отсчета". Чаще всего в мире 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;
    
    Сообщить("Прошло: " + КоличествоДней + " дн. " + КоличествоЧасов + " ч. " + КоличествоМинут + " мин.");
КонецПроцедуры

Важные нюансы: базы данных и часовые пояса

Разберем еще несколько критически важных моментов, которые обязательно нужно учитывать при архитектурном планировании хранения времени в системе:

  1. Различия файловой (DBF) и SQL версий. В файловой версии базы данных 1С 7.7 дата аппаратно хранится в отдельном поле (8 байт), а время нужно класть в отдельное строковое поле. Однако, если база переведена на MS SQL Server, система под капотом способна хранить полноценный тип DATETIME. Искусственное разделение в 7.7 — это лишь ограничение самой платформы, которое обходится методами, описанными выше.
  2. Часовые пояса (Timezones). Если ваша база распределена географически или интегрируется с веб-сайтами и внешними API, хранить локальное время пользователя — грубая ошибка. Всегда переводите время в UTC (Всемирное координированное время) перед записью в реквизит или регистр. В локальный часовой пояс время должно конвертироваться только в момент вывода информации на экран для конкретного пользователя.
  3. Эволюция платформы. Полезно знать, что если вы планируете миграцию на 1С:Предприятие 8.x, весь описанный выше ручной парсинг вам больше не понадобится. В современных версиях платформы тип Дата изначально включает в себя время до секунды. Вычисление разницы там осуществляется простым математическим вычитанием Дата1 - Дата2.

Подводя итог: если вам требуется просто визуальная фиксация события — склеивайте дату и время в строку ГГГГММДДЧЧММСС. Но если вам необходима максимальная производительность, сортировка в запросах и расчет интервалов — обязательно переводите дату и время в абсолютное числовое значение (количество секунд) с помощью пользовательских функций.

← На главную