Текущее время в 1С 8.3: где его взять в коде и как проверить

· 9 мин

Содержание

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

Проблема почти всегда одна: код возвращает «не то» время — то на пару часов отличается от ожидаемого, то зависит от того, где он выполнился. Ниже разберём, какая функция за что отвечает, чем клиентское время отличается от серверного и как проверить фактическое значение без догадок.

Какую функцию выбрать под вашу задачу

Прежде чем писать код, определитесь, какое именно время вам нужно. От этого зависит выбор функции — и большинство ошибок со временем именно здесь.

Какое время вам нужно?

ТекущаяДата и ТекущаяДатаСеанса: в чём разница

Это две разные функции, и путаница между ними — причина большинства «съехавших» дат.

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

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

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

Обе функции доступны и на клиенте, и на сервере. Проверить, что возвращает каждая, можно одной строкой:

Сообщить("ТекущаяДата:       " + ТекущаяДата());
Сообщить("ТекущаяДатаСеанса: " + ТекущаяДатаСеанса());

Если эти два значения расходятся больше, чем на разницу часовых поясов, значит часы сервера и клиента не синхронизированы — это отдельная проблема, о ней в конце.

Клиент, сервер и часовой пояс сеанса

В клиент-серверном варианте код выполняется в двух местах, и время там берётся из разных источников.

  • На клиенте ТекущаяДата() читает часы операционной системы рабочего места пользователя.
  • На сервере ТекущаяДата() читает часы компьютера, где запущена служба сервера 1С.

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

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

Часовой пояс сеанса обычно задаётся не в коде, а в настройках информационной базы — в разделе Администрирование типовой конфигурации, в блоке общих параметров и часовых поясов. Прежде чем искать ошибку в коде, проверьте эту настройку: часто «неправильное» время — это просто незаданный или ошибочный пояс базы.

Часовой пояс сеанса можно прочитать функцией ЧасовойПояс() — она вернёт строку вида Europe/Moscow:

Сообщить("Часовой пояс сеанса: " + ЧасовойПояс());

Установить часовой пояс для сеанса (например, под регион подразделения) можно процедурой УстановитьЧасовойПоясСеанса() — но вызывается она только на сервере.

Как проверить время в отладчике

Когда нужно не вычислять время в коде, а именно посмотреть, что видит программа в конкретной точке, подойдёт отладчик Конфигуратора.

  1. Запустите конфигурацию в режиме отладки.
  2. Поставьте точку останова (клик по серому полю слева от строки или F9) там, где хотите проверить время.
  3. Когда выполнение остановится, откройте меню Отладка → Вычислить выражение.
  4. Введите ТекущаяДатаСеанса() и нажмите «Рассчитать» — отладчик покажет текущее значение.

Второй способ — окно «Табло»: добавьте туда выражение ТекущаяДатаСеанса(), и значение будет пересчитываться на каждой остановке.

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

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

Как администратору проверить серверное время

Иногда задача не в коде, а в том, чтобы убедиться: часы сервера идут верно. Писать для этого обработку не обязательно.

Самый быстрый способ — открыть журнал регистрации (Администрирование → Журнал регистрации в типовой конфигурации) и посмотреть время свежих событий, например собственного входа в систему. Это время проставляет сервер, поэтому оно отражает именно серверные часы, а не часы вашего рабочего места. Сравните его с эталонным временем — если расхождение больше секунды-двух, часы сервера сбиты и их пора синхронизировать.

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

Универсальное и местное время, смещения

Когда данные уходят во внешнюю систему или хранятся для обмена между регионами, время приводят к единому стандарту — универсальному (UTC).

ТекущаяУниверсальнаяДата() возвращает текущее время по Гринвичу, без привязки к часовому поясу. Из универсального в местное и обратно переводят парой функций:

  • МестноеВремя(УниверсальнаяДата, ЧасовойПояс) — переводит UTC в местное время указанного пояса. Если пояс не указан, берётся пояс сеанса.
  • УниверсальноеВремя(МестнаяДата, ЧасовойПояс) — обратный перевод, из местного в UTC.
ВремяUTC   = ТекущаяУниверсальнаяДата();
ВремяМСК   = МестноеВремя(ВремяUTC, "Europe/Moscow");
ВремяВладивосток = МестноеВремя(ВремяUTC, "Asia/Vladivostok");

Сообщить("UTC:        " + ВремяUTC);
Сообщить("Москва:     " + ВремяМСК);
Сообщить("Владивосток:" + ВремяВладивосток);

Если нужно узнать само смещение пояса относительно UTC, его отдаёт функция СмещениеСтандартногоВремени(). Для поясов, где действует переход на летнее время, отдельно считается СмещениеЛетнегоВремени(). Обе возвращают число — количество секунд. Для Москвы стандартное смещение составит 10800 секунд, то есть три часа:

Смещение = СмещениеСтандартногоВремени("Europe/Moscow");
Сообщить("Смещение от UTC: " + (Смещение / 3600) + " ч");

Такой подход снимает головную боль с часовыми поясами: храните и передавайте UTC, а переводите в местное время только для показа пользователю. Тогда данные не «поедут» при переносе базы на сервер в другом регионе. На практике это особенно заметно в журналах и протоколах действий: если метки времени записаны в UTC, записи с разных серверов и регионов выстраиваются в единую ленту без ручного пересчёта поясов.

Замер времени выполнения в миллисекундах

Отдельная задача — не узнать «который час», а понять, сколько длился кусок кода. Для профайлинга точности секунд не хватает, поэтому используют функцию с миллисекундами.

ТекущаяУниверсальнаяДатаВМиллисекундах() возвращает число — количество миллисекунд. Само по себе это число датой не является, но разность двух замеров даёт длительность:

Начало = ТекущаяУниверсальнаяДатаВМиллисекундах();

// ... код, который замеряем ...

Длительность = ТекущаяУниверсальнаяДатаВМиллисекундах() - Начало;
Сообщить("Выполнено за " + Длительность + " мс");

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

Важно замерять один и тот же участок в одинаковых условиях: первый прогон часто медленнее из-за прогрева кэшей, поэтому ориентируйтесь на несколько повторов, а не на единичный результат.

Для глубокого анализа у платформы есть собственные инструменты: встроенный замер производительности в отладчике Конфигуратора показывает время по каждой строке кода, а технологический журнал фиксирует длительность обращений к СУБД. Но когда нужно просто понять, какой из двух блоков тяжелее, пары вызовов ТекущаяУниверсальнаяДатаВМиллисекундах() достаточно — не придётся настраивать логирование.

Типичный приём — обернуть замером не одну операцию, а цикл из нескольких тысяч повторов, и поделить результат на число итераций. Так уходит погрешность: отдельный вызов может уложиться в доли миллисекунды, и округление исказит картину, а усреднённое по циклу время уже показательно.

Текущая дата в запросе: передаём параметром

Частый вопрос: как получить «сейчас» внутри запроса к базе. Короткий ответ: в языке запросов 1С нет функции текущего времени. Дату передают параметром из кода.

Запрос = Новый Запрос;
Запрос.Текст =
    "ВЫБРАТЬ
    |   Остатки.Номенклатура,
    |   Остатки.КоличествоОстаток
    |ИЗ
    |   РегистрНакопления.ТоварыНаСкладах.Остатки(&МоментВремени) КАК Остатки";

Запрос.УстановитьПараметр("МоментВремени", ТекущаяДатаСеанса());
Результат = Запрос.Выполнить();

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

Передавать в параметр лучше именно ТекущаяДатаСеанса(), а не ТекущаяДата(): тогда выборка «на сегодня» совпадёт с датами, которые проставлены в документах той же функцией.

Отдельный нюанс — виртуальные таблицы остатков. В них момент времени задаётся параметром в скобках, как в примере выше. Если нужны остатки «на текущий момент, включая последние движения», передавайте Неопределено вместо даты — платформа возьмёт самый поздний момент. А если важна именно граница периода (конец дня, месяца), оберните текущую дату функцией КонецДня() или КонецМесяца() уже в коде, прежде чем класть значение в параметр. Так вы явно управляете тем, какие записи попадут в выборку, и не зависите от того, в какую секунду запустился отчёт.

Частые ошибки со временем и синхронизация часов

Проблемы со временем почти всегда сводятся к нескольким типовым причинам.

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

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

Если база работает в нескольких регионах, не задавайте пояс жёстко в коде — опирайтесь на пояс сеанса, а его настраивайте централизованно для базы. Один и тот же код тогда корректно отработает и в Москве, и во Владивостоке, а при переезде сервера в другой часовой пояс учётные данные не придётся пересчитывать вручную.

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

Чем `ТекущаяДатаСеанса()` лучше `ТекущаяДата()`?
ТекущаяДатаСеанса() считает от серверного времени и приводит его к часовому поясу сеанса, поэтому результат не зависит от часов конкретного рабочего места. ТекущаяДата() возвращает время той машины, где исполнился код, и часовой пояс сеанса игнорирует.
Как в языке запросов получить текущую дату?
Отдельной функции «сейчас» в запросе нет. Текущую дату вычисляют в коде через ТекущаяДатаСеанса() и передают в запрос параметром с помощью УстановитьПараметр.
Как измерить, сколько миллисекунд выполнялся код?
Вызовите ТекущаяУниверсальнаяДатаВМиллисекундах() до и после участка и вычтите первое значение из второго. Разность — длительность в миллисекундах; само число датой не является.
Почему клиент и сервер показывают разное время?
Либо не синхронизированы системные часы машин (решается настройкой NTP), либо код на клиенте и сервере вызывает ТекущаяДата(), которая читает часы разных компьютеров. Для единого результата используйте ТекущаяДатаСеанса().
Как хранить время, чтобы оно не «поехало» при переносе базы?
Храните универсальное время (ТекущаяУниверсальнаяДата()), а в местное переводите функцией МестноеВремя() только при выводе пользователю. Тогда смена пояса сервера не меняет сохранённые данные.