При разработке в 1С часто возникает задача получить текущую дату. Обычно для этого используется функция ТекущаяДата(). Однако многие разработчики сталкиваются с ситуацией, когда эта функция, вызванная в серверном общем модуле, возвращает не время на компьютере пользователя, а системное время сервера 1С. Разберемся, почему так происходит и как получить именно локальную дату пользователя.
Проблема заключается в клиент-серверной архитектуре платформы 1С. Код в 1С может выполняться в разных контекстах: на клиенте (компьютере пользователя) и на сервере. Функция ТекущаяДата() всегда возвращает системную дату той машины, на которой она в данный момент выполняется.
ТекущаяДата() возвращает разное время?Чтобы понять корень проблемы, проанализируем контексты выполнения кода в 1С:
&НаКлиенте): Этот код выполняется непосредственно на компьютере пользователя. Если вы вызовете ТекущаяДата() в процедуре или функции с директивой &НаКлиенте или в модуле формы без специальных директив, вы получите системную дату и время именно с этого компьютера.&НаСервере): Этот код выполняется на сервере "1С:Предприятия". Сюда относятся процедуры с директивой &НаСервере, код в общих модулях с установленным флагом "Сервер", а также выполнение регламентных и фоновых заданий. Соответственно, вызов ТекущаяДата() в таком коде вернет системную дату и время сервера. Эта дата также известна как "дата сеанса".Таким образом, когда вы в серверном общем модуле пытаетесь получить дату, вы по определению работаете в серверном контексте, и платформа физически не может напрямую обратиться к компьютеру пользователя для получения его локального времени. Это сделано в том числе из соображений безопасности и для обеспечения целостности данных.
Единственный правильный и надежный способ получить на сервере локальную дату пользователя — это сначала получить ее на клиенте, а затем передать на сервер в качестве параметра серверной процедуры или функции. Посмотрим на этот процесс по шагам.
Внутри серверной процедуры эта дата будет доступна через переменную, объявленную в ее параметрах, и с ней можно будет работать дальше.
Рассмотрим, как это реализуется в режиме управляемых форм. Допустим, у нас есть форма, на которой размещена кнопка. Нам нужно при нажатии на эту кнопку выполнить на сервере некую операцию, используя точное время с компьютера пользователя.
Для этого в модуле формы создадим обработчик нажатия кнопки и серверную процедуру.
&НаКлиенте
Процедура ВыполнитьСДатойКлиента(Команда)
// Шаг 1: Получаем текущую системную дату с компьютера, где запущен клиент 1С
ДатаКлиента = ТекущаяДата();
// Выведем сообщение, чтобы убедиться, что дата получена верно
Сообщить("Сейчас на компьютере пользователя: " + Формат(ДатаКлиента, "ДЛФ=DT"));
// Шаг 2 и 3: Вызываем серверную процедуру, передавая дату как параметр
ОбработатьДанныеНаСервере(ДатаКлиента);
КонецПроцедуры
&НаСервере
Процедура ОбработатьДанныеНаСервере(ДатаСКлиента)
// Эта процедура выполняется уже на сервере 1С
// Параметр "ДатаСКлиента" содержит значение, которое мы получили на клиенте
ДатаСервера = ТекущаяДата();
Сообщить("На сервере получена дата клиента: " + Формат(ДатаСКлиента, "ДЛФ=DT"));
Сообщить("Для сравнения, дата на сервере сейчас: " + Формат(ДатаСервера, "ДЛФ=DT"));
// ... здесь можно выполнять дальнейшие действия с датой клиента ...
// Например, записать ее в какой-нибудь нетиповой реквизит документа
// или использовать в алгоритме расчета.
КонецПроцедуры
При выполнении этого кода мы увидим, что ДатаКлиента соответствует времени на локальной машине, а ДатаСервера — времени на сервере, и эти значения могут отличаться.
Для конфигураций на обычных формах (неуправляемых) логика остается абсолютно такой же, меняется лишь синтаксис и способ организации кода. В обычных формах нет директив компиляции &НаКлиенте и &НаСервере. Контекст выполнения определяется местоположением кода:
Чтобы передать дату с клиента на сервер, нужно из процедуры в модуле формы вызвать экспортную процедуру из серверного общего модуля.
Пример для обычных форм:
1. В модуле формы документа или обработки создаем обработчик нажатия кнопки:
// Код в модуле формы (выполняется на клиенте)
Процедура КнопкаВыполнитьНажатие(Кнопка)
// Получаем дату компьютера пользователя
ДатаКлиента = ТекущаяДата();
Сообщить("Текущая дата на клиенте: " + ДатаКлиента);
// Вызываем экспортную процедуру из общего серверного модуля
// и передаем в нее полученную дату
ОбщийМодульСерверный.ВыполнитьОперациюСДатой(ДатаКлиента);
КонецПроцедуры
2. В общем модуле с установленным флагом "Сервер" (назовем его, например, ОбщийМодульСерверный) создаем принимающую процедуру:
// Код в общем модуле "ОбщийМодульСерверный" (установлен флаг "Сервер")
// Процедура должна быть экспортной, чтобы ее можно было вызвать из модуля формы
Процедура ВыполнитьОперациюСДатой(ДатаСКлиента) Экспорт
// Этот код выполняется на сервере
ДатаНаСервере = ТекущаяДата();
Сообщить("На сервер пришла дата от клиента: " + ДатаСКлиента);
Сообщить("Дата на самом сервере: " + ДатаНаСервере);
КонецПроцедуры
Таким образом, несмотря на разницу в синтаксисе, принцип остается неизменным: получить на клиенте, передать на сервер.
Важно понимать ограничения данного подхода. Получить дату клиента можно только тогда, когда есть сам "клиент", то есть интерактивный сеанс пользователя.
ТекущаяДата() возвращает дату с учетом часового пояса машины, на которой выполняется. Если сервер и клиент находятся в разных часовых поясах, это может привести к путанице. Для задач, требующих точной синхронизации времени, рекомендуется использовать универсальное время (UTC) с помощью функции ТекущаяУниверсальнаяДата() и при необходимости конвертировать его в нужный часовой пояс.В заключение, запомним простое правило: если вам в серверном коде нужна дата с компьютера пользователя, ее всегда нужно сначала получить в клиентском коде и передать на сервер в качестве параметра. Прямой доступ к локальному времени пользователя из серверного модуля невозможен по архитектурным соображениям платформы "1С:Предприятие".