Дата в 1С 8.3: как платформа её хранит, вводит и выводит
Содержание
Дата в 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».
Локализованный формат ДЛФ сам подставит русский порядок ДМГ и падежное название месяца — его стоит предпочитать для печатных форм, чтобы не зашивать язык руками.
Как дата вводится в режиме «Предприятие»
В пользовательском режиме дату вводят тремя способами, и все они дают одно и то же внутреннее значение:
- Набрать цифры с клавиатуры — платформа сама расставит разделители по маске поля.
- Открыть календарь кнопкой в правой части поля даты.
- Вставить из буфера — платформа распознает дату, если она в ожидаемом формате.
Формат ввода и вывода в поле зависит от региональных настроек информационной базы. Их задаёт администратор: Администрирование → Общие настройки (региональные установки), либо они берутся из настроек на уровне информационной базы в конфигураторе. Для русской локали это ДД.ММ.ГГГГ.
Если на разных рабочих местах даты показываются то как 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.
ДАТАВРЕМЯ(год,мес,день) — это полночь, 00:00:00. Документы с ненулевым временем отсекаются. Используйте КОНЕЦПЕРИОДА(Дата, ДЕНЬ) или 23:59:59.НачалоДня(Дата1) = НачалоДня(Дата2)."" или с 0. Пустая дата — это '00010101', сравнивайте с ней.M (месяц) и m (минуты). Для даты нужен ДФ=dd.MM.yyyy с заглавной M.Короткий свод правил, которые закрывают большинство случаев:
- сравниваете даты как «день» — обе приводите через
НачалоДня(); - задаёте период в запросе — верхняя граница через
КОНЕЦПЕРИОДА(..., ДЕНЬ); - выводите на печать — берите
ДЛФ, чтобы не зашивать язык и порядок ДМГ; - работаете с несколькими поясами — храните UTC, показывайте местное.
Частые вопросы
Почему дата в 1С всегда с временем, даже если время мне не нужно?
00:00:00 и не показывается в форме.Как записать пустую дату в коде?
'00010101'. Это нижняя граница диапазона дат, 01.01.0001 00:00:00, которую платформа считает незаполненным значением.Чем `ТекущаяДата()` отличается от `ТекущаяДатаСеанса()`?
ТекущаяДата() возвращает время компьютера, где исполняется код (на сервере — время сервера). ТекущаяДатаСеанса() учитывает часовой пояс сеанса пользователя, поэтому для бизнес-логики надёжнее она.Как вывести дату прописью — «15 января 2024 г.»?
Формат(Дата, "ДЛФ=DD"). Платформа сама подставит русский порядок и название месяца в нужном падеже.Почему диапазон в запросе теряет документы за последний день?
ДАТАВРЕМЯ(год, месяц, день) — это полночь. Всё, что позже 00:00:00 этого дня, в условие МЕЖДУ … И … не попадает. Задавайте конец дня: КОНЕЦПЕРИОДА(Дата, ДЕНЬ).