Как сравнить системное время клиента и сервера в 1С и заблокировать вход при большом расхождении?

Программист 1С v8.3 (Управляемые формы)
← На главную

Работая с системой 1С:Предприятие, мы часто сталкиваемся с задачами, требующими точной синхронизации данных. Одной из таких критически важных задач является корректное время в документах и операциях. Представьте ситуацию, когда из-за сбоев системных часов сервера документы выписываются с неправильной датой, что приводит к серьезным проблемам в учете. В этой статье мы подробно разберем, как получить время на клиенте и сервере в 1С, сравнить его и при значительном расхождении заблокировать вход пользователя в программу, предотвращая дальнейшие ошибки.

Выясняем суть проблемы: почему важно синхронизировать время

Основная причина возникновения проблем с временем часто кроется в аппаратных сбоях серверного оборудования, например, из-за севшей батарейки CMOS на материнской плате сервера. Хотя эта батарейка используется часами реального времени преимущественно при выключенном компьютере, ее неисправность или другие аппаратные проблемы могут приводить к постоянному "отставанию" или "убеганию" времени даже во время работы сервера. Это, в свою очередь, становится причиной того, что документы в 1С выписываются с ошибочными датами, нарушая хронологию учета и вызывая путаницу.

Нашей задачей является создание механизма со стороны 1С, который не позволит пользователям работать в системе, если системное время их компьютера значительно отличается от времени сервера. Это будет своего рода "предохранитель", пока основная аппаратная проблема не будет решена системным администратором.

Где и как выполнять проверку в 1С

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

Далее мы рассмотрим, какие функции в 1С позволяют получать текущее время и как их правильно использовать для сравнения времени на клиентской и серверной сторонах.

Различные методы получения времени в 1С

Для корректного сравнения времени очень важно понимать, как работают различные функции даты и времени в 1С. От их правильного выбора зависит точность нашей проверки.

  1. ТекущаяДата():

    Эта функция возвращает системное время того компьютера, на котором она выполняется. Если мы вызовем её на клиенте, получим системное время клиента. Если вызовем в серверном модуле, она вернёт системное время сервера. Использование этой функции для прямого сравнения системных часов клиента и сервера возможно, но не рекомендуется в клиент-серверной архитектуре без учета часовых поясов, так как она возвращает местное время, которое может отличаться из-за разных часовых поясов, даже если абсолютное время совпадает.

  2. ТекущаяДатаСеанса():

    Данная функция является предпочтительной для большинства операций внутри одного сеанса. Она всегда получает текущее время с сервера, но приводит его к часовому поясу, установленному в настройках сеанса пользователя. Это обеспечивает единообразие времени для всех операций в рамках сеанса одного пользователя. Однако, для задачи сравнения *системных часов* клиента и сервера, эта функция не подходит, так как она всегда отражает время сервера (пусть и с коррекцией часового пояса сеанса), и её вызов на клиенте по сути тоже вернёт время сервера.

  3. ТекущаяУниверсальнаяДата() (UTC):

    Это наиболее надёжный и правильный способ для сравнения системного времени. Функция ТекущаяУниверсальнаяДата() возвращает время по Гринвичу (UTC, Coordinated Universal Time), которое является универсальным и не зависит от локальных часовых поясов. Сравнивая универсальное время, полученное на клиенте, с универсальным временем, полученным на сервере, мы можем определить точное расхождение системных часов, полностью исключив влияние часовых поясов. Этот подход является наиболее рекомендуемым для нашей задачи.

Реализация проверки и блокировки входа в 1С

Мы будем размещать наш код в модуле сеанса, в обработчике события ПриНачалеРаботыСистемы(). Наша общая логика будет состоять из следующих шагов:

  1. Получить системное время клиента.
  2. Получить системное время сервера.
  3. Вычислить абсолютную разницу между этими двумя временами.
  4. Если разница превышает допустимый порог (например, 10-15 минут), выдать предупреждение пользователю и завершить работу программы.

Давайте рассмотрим два основных подхода к реализации.

Подход 1: Стандартное сравнение (без учета часовых поясов)

Этот метод будет работать корректно, если мы гарантируем, что все пользователи и сервер находятся в одном часовом поясе. В этом случае мы можем сравнивать местное системное время, полученное функцией ТекущаяДата().

Разберем шаги подробнее:

  1. Получаем время сервера: Мы вызываем серверную функцию, которая, будучи выполненной на сервере, использует ТекущаяДата() для получения системного времени сервера.
  2. Получаем время клиента: На клиентской стороне мы также используем ТекущаяДата(), которая вернет системное время клиентского компьютера.
  3. Вычисляем разницу: Затем мы находим разницу между этими двумя датами. Для этого мы можем просто вычесть одну дату из другой. Важно получить абсолютное значение разницы, чтобы не зависеть от того, какое время "больше". Функция Abs() поможет нам в этом, вернув модуль разницы в секундах.
  4. Сравниваем с допустимым отклонением: Мы устанавливаем пороговое значение, например, 10 минут, что равно 600 секундам. Если абсолютная разница в секундах превышает этот порог, значит, время значительно расходится.
  5. Блокируем вход: В случае значительного расхождения мы информируем пользователя о проблеме и завершаем работу программы с помощью функции ЗавершитьРаботуСистемы().

Пример кода для реализации в модуле сеанса:


&НаКлиенте
Процедура ПриНачалеРаботыСистемы()
    
    // Получаем текущее системное время на сервере
    ДатаСервера = ПолучитьСистемноеВремяСервера();
    
    // Получаем текущее системное время на клиенте
    ДатаКлиента = ТекущаяДата();
    
    // Вычисляем разницу в секундах (модуль Abs нужен, чтобы разница всегда была положительной)
    РазницаВСекундах = Abs(ДатаКлиента - ДатаСервера);
    
    // Устанавливаем допустимое отклонение (например, 10 минут = 600 секунд)
    ДопустимоеОтклонение = 600; 
    
    Если РазницаВСекундах > ДопустимоеОтклонение Тогда
        Предупреждение("Время на вашем компьютере значительно отличается от времени на сервере! 
        |Для корректной работы необходимо синхронизировать время.
        |Программа будет закрыта.");
        
        ЗавершитьРаботуСистемы(Ложь); // Параметр Ложь означает, что пользователю будет задан вопрос о завершении
    КонецЕсли;
    
КонецПроцедуры

&НаСервереБезКонтекста
Функция ПолучитьСистемноеВремяСервера()
    // Эта функция выполняется на сервере и возвращает его системное время
    Возврат ТекущаяДата(); 
КонецФункции

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

Подход 2: Наиболее надежное сравнение (с использованием UTC)

Этот метод является наиболее правильным и универсальным. Он будет работать корректно, даже если в будущем появятся клиенты из других часовых поясов, поскольку сравнивает абсолютное время, не привязанное к локальным настройкам. Мы будем использовать функцию ТекущаяУниверсальнаяДата().

Разберем шаги подробнее:

  1. Получаем универсальное время сервера: Мы вызываем серверную функцию, которая использует ТекущаяУниверсальнаяДата() для получения времени сервера в формате UTC.
  2. Получаем универсальное время клиента: На клиентской стороне мы также используем ТекущаяУниверсальнаяДата(), которая вернет время клиентского компьютера в формате UTC.
  3. Вычисляем разницу: Вычисляем абсолютную разницу между этими двумя датами в секундах.
  4. Сравниваем с допустимым отклонением: Аналогично предыдущему подходу, сравниваем полученную разницу с допустимым порогом.
  5. Блокируем вход: Если разница превышает порог, выдаем предупреждение и завершаем работу программы.

Пример кода для реализации в модуле сеанса:


&НаКлиенте
Процедура ПриНачалеРаботыСистемы()
    
    // Получаем универсальное время на сервере
    ДатаСервераUTC = ПолучитьУниверсальноеВремяСервера();
    
    // Получаем универсальное время на клиенте
    ДатаКлиентаUTC = ТекущаяУниверсальнаяДата();
    
    // Вычисляем разницу в секундах
    РазницаВСекундах = Abs(ДатаКлиентаUTC - ДатаСервераUTC);
    
    ДопустимоеОтклонение = 600; // 10 минут
    
    Если РазницаВСекундах > ДопустимоеОтклонение Тогда
        Предупреждение("Системные часы вашего компьютера и сервера не синхронизированы! 
        |Пожалуйста, исправьте время на вашем компьютере.
        |Программа будет закрыта.");
        
        ЗавершитьРаботуСистемы(Ложь);
    КонецЕсли;
    
КонецПроцедуры

&НаСервереБезКонтекста
Функция ПолучитьУниверсальноеВремяСервера()
    // Эта функция выполняется на сервере и возвращает его универсальное время (UTC)
    Возврат ТекущаяУниверсальнаяДата();
КонецФункции

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

Дополнительные рекомендации и устранение корневой причины

  1. Принудительное завершение работы:

    Если в вашем случае требуется безусловное завершение работы программы без вопросов к пользователю (например, для повышения строгости контроля), вы можете использовать параметр Истина в функции ЗавершитьРаботуСистемы(Истина). Однако, чаще всего, вариант с предупреждением и возможностью пользователя отказаться (ЗавершитьРаботуСистемы(Ложь)) является более дружелюбным.

  2. Устранение проблемы на стороне сервера:

    Критически важно помнить, что блокировка входа в 1С при расхождении времени — это лишь временное решение или "костыль", как это было упомянуто в обсуждении. Основная проблема заключается в аппаратной неисправности сервера, которая приводит к сбою системных часов. Системному администратору необходимо в кратчайшие сроки:

    • Проверить и заменить батарейку CMOS на материнской плате сервера, если она неисправна.
    • Настроить принудительную и регулярную синхронизацию времени сервера с внешним NTP-сервером (Network Time Protocol). Это стандартная практика, которая обеспечивает высокую точность системных часов сервера. Современные операционные системы имеют встроенные средства для такой синхронизации.

    Только комплексный подход, включающий как решение на стороне 1С, так и устранение корневой причины на серверном уровне, обеспечит стабильную и корректную работу вашей информационной системы.

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

← На главную