Время на сервере 1С: какой функцией его брать и почему часы расходятся
Содержание
Чтобы получить время сервера 1С, вызовите ТекущаяДата() в серверной процедуре (&НаСервере или &НаСервереБезКонтекста): она вернёт часы операционной системы того компьютера, где работает рабочий процесс 1С. Для дат документов и отборов правильнее брать ТекущаяДатаСеанса() — это время сервера, пересчитанное в часовой пояс сеанса.
Типичная ситуация: бухгалтер в Новосибирске проводит документ, а в журнале стоит московское время. Или кассир видит, что чек «пробит в будущем» на две минуты. Оба случая — про то, чьи часы спрашивает код и в каком поясе их показывает. Всё, что описано дальше, относится к платформе 8.3 и работает в любой конфигурации — и в клиент-серверном, и в файловом варианте.
Клиентское и серверное время: чьи часы видит код
В 1С одновременно идут как минимум двое часов: на компьютере пользователя и на сервере. Если база через веб-публикацию — добавляются часы веб-сервера. А у СУБД свои часы, и они тоже могут не совпадать.
Какой компьютер считается «сервером», зависит от варианта работы:
| Вариант работы | Где выполняется серверный код | Чьё время вернёт ТекущаяДата() на сервере |
|---|---|---|
| Клиент-серверный (кластер 1С) | Рабочий процесс rphost | Компьютер с рабочим процессом |
| Файловый, тонкий клиент напрямую | Тот же компьютер, что и клиент | Компьютер пользователя |
| Файловый через веб-сервер | Модуль расширения веб-сервера | Компьютер веб-сервера |
| Кластер из нескольких рабочих серверов | Любой из рабочих серверов | Тот сервер, куда попал вызов |
Последняя строка — частый источник «плавающих» расхождений. Если в кластере два рабочих сервера и часы на них отличаются на минуту, один и тот же код будет возвращать разное время в зависимости от того, какой процесс обслужил вызов.
Сама дата в 1С — это просто число и время, без часового пояса. Значение 15.03 10:00:00 не знает, московское оно или иркутское. Поэтому решение «какое время писать» принимает код, а не платформа.
Функции для получения времени сервера в коде 1С
На сервере доступны три функции, и они отвечают на разные вопросы.
- 🕐
ТекущаяДата()— местное время компьютера, на котором выполняется код. Часовой пояс сеанса не учитывает. - 🌍
ТекущаяДатаСеанса()— время сервера, переведённое в часовой пояс сеанса. Подходит для дат документов, отборов «за сегодня», сроков. - 🧭
ТекущаяУниверсальнаяДата()— время UTC по часам сервера. Удобно для журналов обмена, меток синхронизации и сравнения событий из разных регионов.
Есть и ТекущаяУниверсальнаяДатаВМиллисекундах() — возвращает число миллисекунд. Её используют для замера длительности операций, а не для записи дат в документы.
Пример: вывести время клиента и сервера рядом
Код для управляемой формы. Команда на клиенте вызывает серверную функцию и выводит всё в окно сообщений:
&НаКлиенте
Процедура ПоказатьВремя(Команда)
ДанныеСервера = ВремяСервера();
ФорматДаты = "ДФ='dd.MM.yyyy HH:mm:ss'";
Сообщить("Клиент, ТекущаяДата(): " + Формат(ТекущаяДата(), ФорматДаты));
Сообщить("Сервер, ТекущаяДата(): " + Формат(ДанныеСервера.ДатаСервера, ФорматДаты));
Сообщить("Сервер, дата сеанса: " + Формат(ДанныеСервера.ДатаСеанса, ФорматДаты));
Сообщить("Сервер, UTC: " + Формат(ДанныеСервера.ДатаUTC, ФорматДаты));
Сообщить("Пояс компьютера сервера: " + ДанныеСервера.ПоясСервера);
Сообщить("Пояс сеанса: " + ДанныеСервера.ПоясСеанса);
Сообщить("Пояс информационной базы: " + Строка(ДанныеСервера.ПоясБазы));
КонецПроцедуры
&НаСервереБезКонтекста
Функция ВремяСервера()
Результат = Новый Структура;
Результат.Вставить("ДатаСервера", ТекущаяДата());
Результат.Вставить("ДатаСеанса", ТекущаяДатаСеанса());
Результат.Вставить("ДатаUTC", ТекущаяУниверсальнаяДата());
Результат.Вставить("ПоясСервера", ЧасовойПояс());
Результат.Вставить("ПоясСеанса", ЧасовойПоясСеанса());
Результат.Вставить("ПоясБазы", ПолучитьЧасовойПоясИнформационнойБазы());
Возврат Результат;
КонецФункции
&НаСервереБезКонтекста здесь выбрана намеренно: форма не передаётся на сервер, вызов лёгкий. Если пояс базы не задан, в последней строке будет пусто — Строка(Неопределено) даёт пустую строку.
Каждый вызов сервера с клиента — это сетевой запрос. Не дёргайте ВремяСервера() в цикле или по таймеру раз в секунду: получите время один раз, а дальше считайте смещение от клиентских часов.
Время сервера на клиенте без лишних вызовов
В конфигурациях на БСП (Бухгалтерия 3.0, ЗУП 3.1, УТ 11 и другие) есть готовые функции общего модуля ОбщегоНазначенияКлиент:
ОбщегоНазначенияКлиент.ДатаСеанса()— дата сеанса на клиенте;ОбщегоНазначенияКлиент.УниверсальнаяДата()— время UTC.
Они не обращаются к серверу каждый раз. При старте сеанса библиотека запоминает разницу между часами клиента и сервера и дальше прибавляет её к клиентскому времени. Точность — до секунд, для подстановки даты в форму этого достаточно.
Какую функцию взять под задачу
| Задача | Что использовать | Почему |
|---|---|---|
| Дата нового документа | ТекущаяДатаСеанса() на сервере | Учтёт пояс филиала, не зависит от часов пользователя |
| Отбор «за сегодня» в запросе | НачалоДня(ТекущаяДатаСеанса()) параметром | Сутки считаются по местному времени |
| Метка обмена или синхронизации | ТекущаяУниверсальнаяДата() | Одинакова для всех регионов |
| Замер скорости кода | ТекущаяУниверсальнаяДатаВМиллисекундах() | Точность до миллисекунды |
| Диагностика часов ОС сервера | ТекущаяДата() на сервере | Показывает «сырое» время компьютера |
| Подстановка даты в форму на клиенте | ОбщегоНазначенияКлиент.ДатаСеанса() | Без лишнего вызова сервера |
Для замера скорости вычтите одно значение миллисекунд из другого: Конец - Начало даст длительность операции. Секундной точности ТекущаяДата() для этого мало — быстрые операции покажут ноль.
Часовые пояса сеанса, базы и сервера: смещения UTC
Есть три уровня часового пояса, и путают их постоянно:
- Пояс компьютера сервера — задаётся в операционной системе. Его возвращает
ЧасовойПояс()без параметров. - Пояс информационной базы — общий для всей базы. Читается
ПолучитьЧасовойПоясИнформационнойБазы(), задаётсяУстановитьЧасовойПоясИнформационнойБазы(). - Пояс сеанса — свой у каждого сеанса. При входе он берётся из пояса базы, а если тот не задан — из пояса компьютера сервера. Меняется
УстановитьЧасовойПоясСеанса().
От пояса сеанса зависит результат ТекущаяДатаСеанса(). Поэтому одна база может работать с филиалами в разных регионах: каждому сеансу ставят свой пояс, и документы получают местное время.
// На сервере, например, при начале работы сеанса
УстановитьЧасовойПоясСеанса("Asia/Novosibirsk");
МестнаяДата = ТекущаяДатаСеанса(); // время в Новосибирске
ДатаUTC = ТекущаяУниверсальнаяДата(); // то же мгновение в UTC
В типовых конфигурациях пояс базы обычно задают не кодом, а в разделе Администрирование, в общих настройках программы. Изменить его может только пользователь с правами администратора.
Перевод между поясами и расчёт смещения
Для пересчёта дат есть функции платформы:
| Функция | Что делает | Пример результата |
|---|---|---|
МестноеВремя(ДатаUTC, Пояс) | UTC → местное время пояса | 12:00 UTC → 15:00 для Europe/Moscow |
УниверсальноеВремя(Дата, Пояс) | Местное время → UTC | 19:00 в Asia/Novosibirsk → 12:00 UTC |
СмещениеСтандартногоВремени(Пояс) | Смещение от UTC в секундах | 10800 для Москвы (3 часа) |
ПредставлениеЧасовогоПояса(Пояс) | Читаемое имя пояса | Строка для показа пользователю |
Проверим арифметику: Новосибирск — UTC+7, значит 19:00 местного минус 7 часов = 12:00 UTC. Москва — UTC+3, 10 800 секунд = 3 × 3600.
Если второй параметр не передать, функции берут пояс сеанса. Это удобно, но в фоновых и регламентных заданиях пояс сеанса может быть не тем, что вы ждёте. Там передавайте пояс явно.
Не храните в базе дату «с поправкой на пояс», вычисленную вручную прибавлением часов. Когда пояс сменится, прибавленные часы останутся в данных навсегда. Храните либо UTC, либо местное время вместе с поясом.
Получение времени через запрос к базе данных
В языке запросов 1С нет функции «текущая дата». Время передают параметром — и это правильный путь, потому что вы сами решаете, какое время подставить:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Реализация.Ссылка КАК Документ,
| РАЗНОСТЬДАТ(Реализация.Дата, &ТекущаяДата, ДЕНЬ) КАК ДнейПрошло
|ИЗ
| Документ.РеализацияТоваровУслуг КАК Реализация
|ГДЕ
| Реализация.Дата >= ДОБАВИТЬКДАТЕ(&ТекущаяДата, ДЕНЬ, -7)";
Запрос.УстановитьПараметр("ТекущаяДата", ТекущаяДатаСеанса());
Выборка = Запрос.Выполнить().Выбрать();
Запрос выбирает реализации за последние 7 дней от даты сеанса. Для отбора «с начала дня» передайте НачалоДня(ТекущаяДатаСеанса()).
Время самой СУБД
Иногда нужно узнать часы сервера баз данных — например, при разборе блокировок или сверке логов СУБД с журналом регистрации. Это делают не из 1С, а в консоли СУБД:
-- Microsoft SQL Server
SELECT SYSDATETIME() AS МестноеВремя,
SYSDATETIMEOFFSET() AS СоСмещением,
GETUTCDATE() AS ВремяUTC;
-- PostgreSQL
SELECT now() AS время_со_смещением,
current_setting('TimeZone') AS пояс_сервера;
Это только чтение, данные базы такие запросы не трогают.
Не пишите и не правьте таблицы 1С напрямую средствами СУБД. Чтение текущего времени безопасно, а любое изменение данных в обход платформы ломает целостность базы.
Сервер СУБД и сервер 1С часто стоят на разных машинах. Если их часы разошлись, сама 1С продолжит работать — даты в документы пишет сервер 1С. Но сверять события по логам станет тяжело.
Как найти, где расходится время
Порядок проверки — от простого к сложному.
- Сравните время в 1С. Запустите код из примера выше. Разница между клиентским и серверным
ТекущаяДата()больше нескольких секунд — проблема в часах компьютеров. Разница ровно в целое число часов — проблема в поясах. - Проверьте часы и пояс ОС сервера Windows. В командной строке:
:: текущий часовой пояс
tzutil /g
:: откуда берётся время и когда была синхронизация
w32tm /query /status
w32tm /query /source
:: принудительная синхронизация (нужны права администратора)
w32tm /resync
- Проверьте сервер на Linux:
timedatectl
Строки Time zone и System clock synchronized: yes покажут пояс и работу синхронизации.
- Проверьте все рабочие серверы кластера, а не только центральный. Время на каждом должно идти от одного источника — обычно от контроллера домена или общего NTP-сервера.
- Сравните пояс сеанса и пояс базы — строки «Пояс сеанса» и «Пояс информационной базы» из примера. Если у сеанса неожиданный пояс, ищите вызов
УстановитьЧасовойПоясСеанса()в модулях сеанса и в расширениях.
В домене Windows рассинхронизация часов больше чем на 5 минут (значение по умолчанию) ломает проверку подлинности Kerberos. Если вместе со «съехавшим» временем перестал работать вход в 1С через доменного пользователя — начинайте с часов.
Если поменяли пояс или время на сервере
Сменили часовой пояс в ОС, а 1С показывает старое время — перезапустите службу агента сервера 1С.
Перезапуск службы оборвёт все сеансы пользователей и фоновые задания. Делайте это в нерабочее время и предупредите людей заранее.
Резкий перевод часов назад на работающем сервере тоже опасен: документы, созданные «в прошлом», встанут в последовательность не в том порядке. Правильнее, чтобы часы подтягивала служба синхронизации, а не ручная правка.
Ошибки при работе со временем сервера и как их исправить
Ещё одна ошибка — на уровне кода: использовать ТекущаяДата() на клиенте для чего-то важного. Пользователь может перевести часы своего компьютера, и документ получит любую дату. Всё, что влияет на учёт, берите на сервере.