Дата в 1С 8.3: как платформа её хранит, вводит и выводит

· 8 мин

Содержание

Дата в 1С 8.3 — это единый тип, который хранит и день, и время в одном значении. Пустая дата здесь не «ничего», а конкретный момент 01.01.0001 00:00:00. В коде дату пишут не кавычками-строкой, а литералом '20240115120000' — год, месяц, день, часы, минуты, секунды подряд. А то, что вы видите на экране в виде 15.01.2024, — это уже результат форматирования по региональным настройкам, а не способ хранения.

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

Что такое тип «Дата» и как значение лежит в базе

Тип «Дата» в 1С всегда содержит обе составляющие — календарную дату и время с точностью до секунды. Отдельного типа «только время» в платформе нет: если время не задано, оно равно 00:00:00 (началу суток).

Диапазон значений — с 01.01.0001 00:00:00 по 31.12.3999 23:59:59. Выйти за эти границы нельзя, попытка приведёт к ошибке.

Пустое (незаполненное) значение даты — это нижняя граница диапазона, 01.01.0001 00:00:00. Поэтому проверять дату на пустоту сравнением со строкой "" бессмысленно: надо сравнивать с пустой датой.

Если Док.ДатаОплаты = '00010101' Тогда
    Сообщить("Дата оплаты не заполнена");
КонецЕсли;

Короткий литерал '00010101' равен '00010101000000' — время просто опускается и считается нулевым. Это удобный способ записать «пустую» дату в коде.

Состав даты у реквизита

Когда вы создаёте реквизит типа «Дата» в конфигураторе, у типа есть свойство Состав даты с тремя вариантами:

  • Дата — хранится только календарная часть, время всегда 00:00:00;
  • Время — значимо только время, дата фиксирована;
  • Дата и время — хранятся обе части.

Выбор влияет на то, как поле показывается в форме и какой календарь/часы предлагаются при вводе. Само внутреннее значение по-прежнему несёт обе составляющие — просто незначимая часть обнуляется.

Порядок ДМГ, разделители и функция Формат

Порядок «день-месяц-год» и разделитель . — это не свойство самой даты, а свойство её представления. Одно и то же значение можно вывести как 15.01.2024, 2024-01-15 или 15 января 2024 г. — меняется только форматная строка.

За вывод отвечает функция Формат(). Для дат у неё два основных параметра форматной строки:

  • ДФ — формат даты из букв-масок;
  • ДЛФ — локализованный формат (платформа сама подставит язык и порядок компонентов).
Формат('20240115123000', "ДФ=dd.MM.yyyy")      // 15.01.2024
Формат('20240115123000', "ДФ=dd.MM.yy HH:mm")  // 15.01.24 12:30
Формат('20240115123000', "ДЛФ=D")              // 15.01.2024 (короткая)
Формат('20240115123000', "ДЛФ=DD")             // 15 января 2024 г.
Формат('20240115123000', "ДЛФ=T")              // 12:30:00

Буквы в маске ДФ легко перепутать, и это даёт неверный результат без ошибки:

БукваЧто означает
dдень
Mмесяц (заглавная M)
yгод
Hчасы в 24-часовом формате
hчасы в 12-часовом формате
mминуты (строчная m)
sсекунды

Главная ловушка: месяц — заглавная M, минуты — строчная m. Если написать mm.MM.yyyy, в позиции дня окажутся минуты, и 15 января превратится в «00.01.2024».

Локализованный формат ДЛФ сам подставит русский порядок ДМГ и падежное название месяца — его стоит предпочитать для печатных форм, чтобы не зашивать язык руками.

Как дата вводится в режиме «Предприятие»

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

  1. Набрать цифры с клавиатуры — платформа сама расставит разделители по маске поля.
  2. Открыть календарь кнопкой в правой части поля даты.
  3. Вставить из буфера — платформа распознает дату, если она в ожидаемом формате.

Формат ввода и вывода в поле зависит от региональных настроек информационной базы. Их задаёт администратор: Администрирование → Общие настройки (региональные установки), либо они берутся из настроек на уровне информационной базы в конфигураторе. Для русской локали это ДД.ММ.ГГГГ.

Если на разных рабочих местах даты показываются то как 15.01.2024, то как 01/15/2024, проверьте не 1С, а региональные настройки Windows и настройки региональных установок базы — расхождение идёт оттуда, а не из хранимого значения.

Если у реквизита состав даты — «Дата», поле не предложит ввод времени; если «Дата и время» — рядом появится ввод часов и минут.

Работа с датой в коде: литералы и встроенные функции

В встроенном языке дату задают литералом в одинарных кавычках — без вызова функций и без разбора строки:

ДатаДокумента = '20240115';           // 15.01.2024 00:00:00
МоментВремени = '20240115143000';     // 15.01.2024 14:30:00

Разложить дату на части и собрать обратно помогают встроенные функции. Они работают с типом «Дата» напрямую:

Год('20240115')        // 2024
Месяц('20240115')      // 1
День('20240115')       // 15
Час('20240115143000')  // 14

Для сдвига границ периода есть отдельная группа функций — они возвращают дату, а не меняют исходную:

  • НачалоДня(Дата) — то же число, время 00:00:00;
  • КонецДня(Дата) — то же число, время 23:59:59;
  • НачалоМесяца(Дата), КонецМесяца(Дата);
  • НачалоГода(Дата), КонецГода(Дата);
  • НачалоКвартала(Дата), КонецКвартала(Дата).

Прибавить или отнять месяцы корректнее всего через ДобавитьМесяц() — она учитывает разную длину месяцев:

ДобавитьМесяц('20240131', 1)   // 29.02.2024, а не 31.02
ДобавитьМесяц('20240115', -3)  // 15.10.2023

Дни, часы и секунды прибавляют арифметикой: дата — это, по сути, число секунд, поэтому Дата + 86400 даёт следующие сутки, а Дата2 - Дата1 — разницу в секундах.

ЗавтраВЭтоЖеВремя = ТекущаяДата() + 86400;   // +1 сутки
РазницаВДнях = (Дата2 - Дата1) / 86400;      // разница в днях

Даты в запросах: константы, периоды и границы

В языке запросов свои конструкции для дат — литерал кода там не работает . Дату-константу задают функцией ДАТАВРЕМЯ:

ВЫБРАТЬ
    Продажи.Контрагент,
    Продажи.Сумма
ИЗ
    Документ.РеализацияТоваровУслуг КАК Продажи
ГДЕ
    Продажи.Дата МЕЖДУ ДАТАВРЕМЯ(2024, 1, 1) И ДАТАВРЕМЯ(2024, 1, 31, 23, 59, 59)

Полезные функции запроса для работы с датой:

  • НАЧАЛОПЕРИОДА(Поле, МЕСЯЦ) и КОНЕЦПЕРИОДА(Поле, ДЕНЬ) — сдвиг к границе периода (ГОД, КВАРТАЛ, МЕСЯЦ, НЕДЕЛЯ, ДЕНЬ, ЧАС и т. д.);
  • ДОБАВИТЬКДАТЕ(Поле, МЕСЯЦ, 3) — прибавить интервал;
  • РАЗНОСТЬДАТ(Дата1, Дата2, ДЕНЬ) — разница в выбранных единицах;
  • ГОД(Поле), МЕСЯЦ(Поле), ДЕНЬ(Поле) — извлечь компонент.

Самая частая ошибка интервалов — верхняя граница. Если написать Дата <= ДАТАВРЕМЯ(2024, 1, 31), в выборку не попадут документы за 31 января с ненулевым временем, потому что ДАТАВРЕМЯ(2024,1,31) — это 31.01.2024 00:00:00. Берите конец дня: КОНЕЦПЕРИОДА(..., ДЕНЬ) или явно 23:59:59.

Время и часовые пояса: универсальное против местного

Значение даты в 1С не хранит информацию о часовом поясе — это «наивное» локальное время. Пояс учитывается только тогда, когда вы его явно запрашиваете.

Что получать для текущего момента:

  • ТекущаяДата() — дата-время компьютера, где исполняется код (в серверном контексте — время сервера);
  • ТекущаяДатаСеанса() — текущее время с учётом часового пояса сеанса пользователя;
  • ТекущаяУниверсальнаяДата() — время по UTC.

Для пересчёта между поясами есть пара функций:

МестноеВремя(УниверсальнаяДата, ЧасовойПоясСеанса())
УниверсальноеВремя(МестноеВремя, ЧасовойПоясСеанса())

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

Расхождение между временем клиента и сервера — классический источник путаницы в клиент-серверном варианте. Ориентируйтесь на ТекущаяДатаСеанса() для бизнес-логики: она привязана к поясу сеанса, а не к тому, где физически стоит сервер.

Частые ошибки с датами и как их не допустить

Почти все проблемы с датами сводятся к тому, что забыли про скрытую компоненту времени или про то, что пустая дата — это 01.01.0001.

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

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

  • сравниваете даты как «день» — обе приводите через НачалоДня();
  • задаёте период в запросе — верхняя граница через КОНЕЦПЕРИОДА(..., ДЕНЬ);
  • выводите на печать — берите ДЛФ, чтобы не зашивать язык и порядок ДМГ;
  • работаете с несколькими поясами — храните UTC, показывайте местное.

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

Почему дата в 1С всегда с временем, даже если время мне не нужно?
Тип «Дата» в платформе единый и всегда несёт обе составляющие. Если время не нужно, у реквизита выставляют состав даты «Дата» — тогда время хранится как 00:00:00 и не показывается в форме.
Как записать пустую дату в коде?
Литералом '00010101'. Это нижняя граница диапазона дат, 01.01.0001 00:00:00, которую платформа считает незаполненным значением.
Чем `ТекущаяДата()` отличается от `ТекущаяДатаСеанса()`?
ТекущаяДата() возвращает время компьютера, где исполняется код (на сервере — время сервера). ТекущаяДатаСеанса() учитывает часовой пояс сеанса пользователя, поэтому для бизнес-логики надёжнее она.
Как вывести дату прописью — «15 января 2024 г.»?
Через локализованный формат: Формат(Дата, "ДЛФ=DD"). Платформа сама подставит русский порядок и название месяца в нужном падеже.
Почему диапазон в запросе теряет документы за последний день?
Верхняя граница ДАТАВРЕМЯ(год, месяц, день) — это полночь. Всё, что позже 00:00:00 этого дня, в условие МЕЖДУ … И … не попадает. Задавайте конец дня: КОНЕЦПЕРИОДА(Дата, ДЕНЬ).