Текущее время в 1С 8.3: где его взять в коде и как проверить
Содержание
Текущее время в 1С берут функцией ТекущаяДатаСеанса() — она возвращает дату и время с учётом часового пояса сеанса. Для измерения длительности операции есть ТекущаяУниверсальнаяДатаВМиллисекундах(), а проверить значение прямо во время работы можно в отладчике через окно «Вычислить выражение» или командой Сообщить().
Проблема почти всегда одна: код возвращает «не то» время — то на пару часов отличается от ожидаемого, то зависит от того, где он выполнился. Ниже разберём, какая функция за что отвечает, чем клиентское время отличается от серверного и как проверить фактическое значение без догадок.
Какую функцию выбрать под вашу задачу
Прежде чем писать код, определитесь, какое именно время вам нужно. От этого зависит выбор функции — и большинство ошибок со временем именно здесь.
ТекущаяДатаСеанса(). Это основная функция для бизнес-логики.ТекущаяУниверсальнаяДата() — всегда возвращает время по Гринвичу (UTC).ТекущаяУниверсальнаяДатаВМиллисекундах() в начале и в конце, разница — длительность в миллисекундах.ТекущаяДата() — но сначала прочитайте про разницу клиента и сервера ниже.ТекущаяДата и ТекущаяДатаСеанса: в чём разница
Это две разные функции, и путаница между ними — причина большинства «съехавших» дат.
ТекущаяДата() возвращает дату и время компьютера, на котором исполняется код. Часовой пояс сеанса она не учитывает — берёт то, что показывают системные часы машины.
ТекущаяДатаСеанса() возвращает время сервера, пересчитанное в часовой пояс сеанса. Именно её используют в типовых конфигурациях для подстановки даты в документы, записи в регистры и расчёта остатков «на сейчас».
Правило простое: в бизнес-логике — всегда ТекущаяДатаСеанса(). ТекущаяДата() оставьте для случаев, когда нужно именно системное время конкретной машины.
Обе функции доступны и на клиенте, и на сервере. Проверить, что возвращает каждая, можно одной строкой:
Сообщить("ТекущаяДата: " + ТекущаяДата());
Сообщить("ТекущаяДатаСеанса: " + ТекущаяДатаСеанса());
Если эти два значения расходятся больше, чем на разницу часовых поясов, значит часы сервера и клиента не синхронизированы — это отдельная проблема, о ней в конце.
Клиент, сервер и часовой пояс сеанса
В клиент-серверном варианте код выполняется в двух местах, и время там берётся из разных источников.
- На клиенте
ТекущаяДата()читает часы операционной системы рабочего места пользователя. - На сервере
ТекущаяДата()читает часы компьютера, где запущена служба сервера 1С.
Если рабочее место в Калининграде, а сервер в Москве, одна и та же функция ТекущаяДата() вернёт разное время в зависимости от того, в клиентском или серверном методе её вызвали. Поэтому для документов и движений и нужна ТекущаяДатаСеанса(): она всегда считает от серверного времени и приводит его к часовому поясу сеанса — независимо от того, где стоит компьютер пользователя.
Отдельно стоит веб-клиент. Браузер пользователя — это клиентская часть, и в клиентском методе ТекущаяДата() там опирается на часы компьютера, с которого открыли базу. В тонком клиенте — то же самое. Единственный способ гарантировать одинаковый результат для всех пользователей, независимо от их устройств и браузеров, — считать время на сервере или через ТекущаяДатаСеанса().
Часовой пояс сеанса обычно задаётся не в коде, а в настройках информационной базы — в разделе Администрирование типовой конфигурации, в блоке общих параметров и часовых поясов. Прежде чем искать ошибку в коде, проверьте эту настройку: часто «неправильное» время — это просто незаданный или ошибочный пояс базы.
Часовой пояс сеанса можно прочитать функцией ЧасовойПояс() — она вернёт строку вида Europe/Moscow:
Сообщить("Часовой пояс сеанса: " + ЧасовойПояс());
Установить часовой пояс для сеанса (например, под регион подразделения) можно процедурой УстановитьЧасовойПоясСеанса() — но вызывается она только на сервере.
Как проверить время в отладчике
Когда нужно не вычислять время в коде, а именно посмотреть, что видит программа в конкретной точке, подойдёт отладчик Конфигуратора.
- Запустите конфигурацию в режиме отладки.
- Поставьте точку останова (клик по серому полю слева от строки или
F9) там, где хотите проверить время. - Когда выполнение остановится, откройте меню
Отладка → Вычислить выражение. - Введите
ТекущаяДатаСеанса()и нажмите «Рассчитать» — отладчик покажет текущее значение.
Второй способ — окно «Табло»: добавьте туда выражение ТекущаяДатаСеанса(), и значение будет пересчитываться на каждой остановке.
ТекущаяДата() в окне «Вычислить выражение» вернёт время той машины, где исполняется отлаживаемый контекст: при отладке серверного модуля — время сервера, клиентского — время клиента. Учитывайте это, когда сравниваете результат с часами на своём экране.
Если отладчик недоступен (например, на рабочей базе без отладки), достаточно временно вставить Сообщить(ТекущаяДатаСеанса()) в нужный метод. Для фоновых и регламентных заданий, где окно сообщений не видно, пишите значение в журнал регистрации через ЗаписьЖурналаРегистрации().
Как администратору проверить серверное время
Иногда задача не в коде, а в том, чтобы убедиться: часы сервера идут верно. Писать для этого обработку не обязательно.
Самый быстрый способ — открыть журнал регистрации (Администрирование → Журнал регистрации в типовой конфигурации) и посмотреть время свежих событий, например собственного входа в систему. Это время проставляет сервер, поэтому оно отражает именно серверные часы, а не часы вашего рабочего места. Сравните его с эталонным временем — если расхождение больше секунды-двух, часы сервера сбиты и их пора синхронизировать.
Второй ориентир — время создания только что проведённого документа: оно подставляется функцией ТекущаяДатаСеанса(), то есть показывает серверное время в поясе сеанса.
Универсальное и местное время, смещения
Когда данные уходят во внешнюю систему или хранятся для обмена между регионами, время приводят к единому стандарту — универсальному (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. Тогда ТекущаяДатаСеанса() считает от надёжного серверного времени, и расхождения с часами на экране пользователя перестают влиять на учёт.
Если база работает в нескольких регионах, не задавайте пояс жёстко в коде — опирайтесь на пояс сеанса, а его настраивайте централизованно для базы. Один и тот же код тогда корректно отработает и в Москве, и во Владивостоке, а при переезде сервера в другой часовой пояс учётные данные не придётся пересчитывать вручную.
Частые вопросы
Чем `ТекущаяДатаСеанса()` лучше `ТекущаяДата()`?
ТекущаяДатаСеанса() считает от серверного времени и приводит его к часовому поясу сеанса, поэтому результат не зависит от часов конкретного рабочего места. ТекущаяДата() возвращает время той машины, где исполнился код, и часовой пояс сеанса игнорирует.Как в языке запросов получить текущую дату?
ТекущаяДатаСеанса() и передают в запрос параметром с помощью УстановитьПараметр.Как измерить, сколько миллисекунд выполнялся код?
ТекущаяУниверсальнаяДатаВМиллисекундах() до и после участка и вычтите первое значение из второго. Разность — длительность в миллисекундах; само число датой не является.Почему клиент и сервер показывают разное время?
ТекущаяДата(), которая читает часы разных компьютеров. Для единого результата используйте ТекущаяДатаСеанса().Как хранить время, чтобы оно не «поехало» при переносе базы?
ТекущаяУниверсальнаяДата()), а в местное переводите функцией МестноеВремя() только при выводе пользователю. Тогда смена пояса сервера не меняет сохранённые данные.