← Назад к вопросам

Как получить разницу во времени между тем которое прислал сервер и Date.now?

1.0 Junior🔥 81 комментариев
#JavaScript Core

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Разница между временем сервера и клиента

Это практическая задача, которая часто возникает при работе с real-time функциями: чатами, таймерами, синхронизацией данных. Клиент и сервер могут иметь разные системные часы, и нужно это учитывать.

Проблема

Если просто сравнить Date.now() (время клиента) с временем сервера, получим неправильный результат. Причины:

  • Системные часы на разных машинах могут различаться на несколько минут/часов
  • Пользователь может специально или случайно изменить системное время
  • Часовые пояса разные

Решение: получить offset

Стратегия: когда сервер отправляет время, мы вычисляем разницу между его временем и текущим Date.now(). Эту разницу сохраняем и используем для всех последующих вычислений.

Шаг 1: получить время сервера

// Запрашиваем текущее время у сервера
const response = await fetch('/api/time');
const data = await response.json();
const serverTime = new Date(data.timestamp).getTime(); // Время в миллисекундах
const clientTime = Date.now();

// Вычисляем offset (разницу)
const timeOffset = serverTime - clientTime;

// Сохраняем в localStorage или переменную
window.timeOffset = timeOffset;

Шаг 2: использовать это для получения текущего серверного времени

// Функция для получения текущего времени сервера в любой момент
function getServerTime() {
  return Date.now() + window.timeOffset;
}

// Пример использования
console.log(getServerTime()); // Текущее время сервера

Полный пример

// API endpoint на сервере возвращает текущее время
// GET /api/time -> { "timestamp": "2026-04-02T12:30:45Z" }

class ServerTime {
  constructor() {
    this.offset = 0;
  }

  // Синхронизировать часы с сервером
  async sync() {
    const response = await fetch('/api/time');
    const data = await response.json();
    
    const serverTime = new Date(data.timestamp).getTime();
    const clientTime = Date.now();
    
    // offset = сколько миллисекунд отставляет/опережает клиент
    this.offset = serverTime - clientTime;
    
    console.log(`Синхронизация: offset = ${this.offset}ms`);
  }

  // Получить текущее время сервера
  now() {
    return Date.now() + this.offset;
  }

  // Получить дату сервера
  getDate() {
    return new Date(this.now());
  }
}

// Использование
const serverTime = new ServerTime();
await serverTime.sync();

console.log(serverTime.now());      // Текущее время сервера в ms
console.log(serverTime.getDate()); // Текущая дата сервера

Практический пример: таймер обратного отсчёта

class CountdownTimer {
  constructor(expiresAt, onExpire) {
    this.expiresAt = new Date(expiresAt).getTime();
    this.onExpire = onExpire;
    this.intervalId = null;
  }

  // Получить оставшееся время (в секундах)
  getRemainingSeconds() {
    const remaining = this.expiresAt - (Date.now() + window.timeOffset);
    return Math.max(0, Math.floor(remaining / 1000));
  }

  start() {
    this.intervalId = setInterval(() => {
      const remaining = this.getRemainingSeconds();
      
      console.log(`Осталось: ${remaining}s`);
      
      if (remaining <= 0) {
        this.stop();
        this.onExpire();
      }
    }, 1000);
  }

  stop() {
    clearInterval(this.intervalId);
  }
}

// Использование
// Сервер отправил: { "expiresAt": "2026-04-02T13:00:00Z" }
const timer = new CountdownTimer('2026-04-02T13:00:00Z', () => {
  console.log('Время истекло!');
});
timer.start();

Повторная синхронизация

Ответ пользователя может развивать проект долгое время. Часы дрейфуют (медленно разбегаются). Периодически пересинхронизируй:

// Синхронизировать каждые 5 минут
setInterval(() => {
  serverTime.sync();
}, 5 * 60 * 1000);

Обработка задержки сети

Для более точной синхронизации можно учесть задержку сети (latency):

async function syncWithLatency() {
  const clientTime1 = Date.now();
  const response = await fetch('/api/time');
  const clientTime2 = Date.now();
  
  const data = await response.json();
  const serverTime = new Date(data.timestamp).getTime();
  
  // Предполагаем, что сервер ответил в середине этого времени
  const latency = (clientTime2 - clientTime1) / 2;
  const estimatedServerTime = serverTime + latency;
  
  window.timeOffset = estimatedServerTime - clientTime2;
}

Когда это нужно

  • Таймеры и countdown — для аукционов, сессий
  • Real-time синхронизация — чаты, совместное редактирование
  • Истечение токенов — проверка, не истёк ли JWT
  • Оптимистичные обновления — когда нужно знать точное время

Заключение

Три шага:

  1. Запроси время у сервера: GET /api/time
  2. Вычисли разницу: offset = serverTime - Date.now()
  3. Используй: getServerTime() = Date.now() + offset

Периодически пересинхронизируй для компенсации дрейфа часов.

Как получить разницу во времени между тем которое прислал сервер и Date.now? | PrepBro