Saltar al contenido

La mejor manera de sincronizar el reloj javascript del lado del cliente con la fecha del servidor

Serena, parte de este equipo, nos hizo el favor de redactar este escrito porque domina a la perfección dicho tema.

Solución:

Puede calcular la hora exacta con NTP (Network Time Protocol) en sus códigos,

trato de explicarte:

  1. Tenemos ClientTime al enviar la solicitud (por ejemplo, 4/3/2012 13: 56: 10.123)
  2. Envías ClientTime al servidor
  3. Tenemos Tiempo de viaje por solicitud, lo llamé Tiempo requerido (por ejemplo: tarda 5 segundos)
  4. En el servidor, calculamos el tiempo de diferencia entre el servidor y el cliente (por ejemplo: It ServerTime – ClientTime = ServerClientDifferenceTimeWithRequestTime), ahora debe esta Diferencia incluyendo el tiempo de solicitud de ida y vuelta en el paso 3, luego debe eliminar el tiempo de ida y vuelta de la Diferencia
  5. Respuesta de envío de servidor que incluye ServerClientDifferenceTimeWithRequestTime y ServerTime
  6. Tenemos Tiempo de viaje por respuesta, lo llamé Tiempo de respuesta (por ejemplo: tarda 3 segundos)
  7. En el cliente, calculamos el tiempo de diferencia entre el servidor y el cliente de nuevo (por ejemplo: It ServerTime – ClientTime = ServerClientDifferenceTimeWithResponseTime), nuevamente: ahora debería esta Diferencia incluyendo el tiempo de respuesta de ida y vuelta en el paso 6
  8. Ahora tenemos tiempo en el cliente
  9. Debe calcular ecuaciones simples en el cliente:

X (tiempo sincronizado) = Now + (ServerClientDifferenceTimeWithRequestTime - RquestTime)

X (tiempo sincronizado) = Now + (ServerClientDifferenceTimeWithResponseTime - ResponseTime)

Now - ClientTime = RquestTime + ResponseTime =>

Now - (ServerClientDiffRq - RquestTime) = Now - (ServerClientDiffRs - ResponseTime)

si lo resuelves, encontraste esto:

ResponseTime = (ServerClientDifferenceTimeWithRequestTime - Now + ClientTime + - ServerClientDifferenceTimeWithResponseTime )/2

y luego puede encontrar la hora sincronizada o la hora del servidor en el cliente con esta ecuación:

X (tiempo sincronizado) = Now + (ServerClientDifferenceTimeWithResponseTime - ResponseTime)

Muestro un código simple, pero cuando quieras escribirlo, no olvides usar las funciones de fecha y hora UTC …

Lado del servidor (por ejemplo php, c #):

PHP:

header('Content-Type: application/json; charset=utf-8');
$clientTime = $_GET["ct"] * 1; //for php 5.2.1 or up: (float)$_GET["ct"];
$serverTimestamp = round(microtime(true)*1000); // (new DateTime())->getTimestamp();
$serverClientRequestDiffTime = $serverTimestamp - $clientTime;
echo ""diff":$serverClientRequestDiffTime,"serverTimestamp":$serverTimestamp";

C#:

long clientTime = long.Parse(Request.Form["ct"]);
long serverTimestamp = (DateTime.Now.Ticks-(new DateTime(1970,1,1) - DateTime.MinValue).Ticks) / 10000;
long serverClientRequestDiffTime = serverTimestamp - clientTime;
Response.Write(""diff":"+serverClientRequestDiffTime+","serverTimestamp":"+serverTimestamp+"");

Lado del cliente (Javascript con Jquery):

var clientTimestamp = (new Date()).valueOf();
$.getJSON('http://yourhost.com/getdatetimejson/?ct='+clientTimestamp, function( data ) 
    var nowTimeStamp = (new Date()).valueOf();
    var serverClientRequestDiffTime = data.diff;
    var serverTimestamp = data.serverTimestamp;
    var serverClientResponseDiffTime = nowTimeStamp - serverTimestamp;
    var responseTime = (serverClientRequestDiffTime - nowTimeStamp + clientTimestamp - serverClientResponseDiffTime )/2

    var syncedServerTime = new Date((new Date()).valueOf() + (serverClientResponseDiffTime - responseTime));
    alert(syncedServerTime);
);

Estas dos funciones de Javascript deberían hacer el truco por ti.

var offset = 0;
function calcOffset() 
    var xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
    xmlhttp.open("GET", "http://stackoverflow.com/", false);
    xmlhttp.send();

    var dateStr = xmlhttp.getResponseHeader('Date');
    var serverTimeMillisGMT = Date.parse(new Date(Date.parse(dateStr)).toUTCString());
    var localMillisUTC = Date.parse(new Date().toUTCString());

    offset = serverTimeMillisGMT -  localMillisUTC;


function getServerTime() 
    var date = new Date();

    date.setTime(date.getTime() + offset);

    return date;

EDITAR: eliminado “.replace (/ ^ (.)[sS]/, “$ 1”) “.

calcOffset () calcula el desplazamiento de la hora del servidor y compensa GMT / UTC.

getServerTime () para obtener el desplazamiento de la hora local para que coincida con los servidores, utilizando la zona horaria local.

Si calcOffset () tarda mucho en ejecutarse, es posible que pierda algunos segundos de precisión. Quizás se pueda tener en cuenta el tiempo de ejecución …

Si le preocupa que la compensación calculada se vuelva incorrecta cuando la hora local o la hora del servidor cambien hacia o desde el horario de verano, podría volver a calcular un poco después de cada hora de reloj, el sistema compensará los cambios en el horario de verano. Puede que sea necesario esperar hasta que tanto el reloj local como el del servidor hayan pasado la hora.

El ejemplo solo funciona en IE debido a “Msxml2.XMLHTTP”, creo …

Descubrí que el algoritmo de @ mehdi-yeganeh anterior no me dio resultados útiles, pero la idea es sólida: usar el algoritmo NTP (o al menos una versión débil) para sincronizar los relojes del servidor y del cliente.

Esta es mi implementación final, usa los encabezados de respuesta del servidor si están disponibles para mayor precisión (corríjame si me equivoco, mis propias pruebas dicen que esto es bastante preciso).

lado del navegador (javascript):

// the NTP algorithm
// t0 is the client's timestamp of the request packet transmission,
// t1 is the server's timestamp of the request packet reception,
// t2 is the server's timestamp of the response packet transmission and
// t3 is the client's timestamp of the response packet reception.
function ntp(t0, t1, t2, t3) 
    return 
        roundtripdelay: (t3 - t0) - (t2 - t1),
        offset: ((t1 - t0) + (t2 - t3)) / 2
    ;


// calculate the difference in seconds between the client and server clocks, use
// the NTP algorithm, see: http://en.wikipedia.org/wiki/Network_Time_Protocol#Clock_synchronization_algorithm
var t0 = (new Date()).valueOf();

$.ajax(
    url: '/ntp',
    success: function(servertime, text, resp) 
        // NOTE: t2 isn't entirely accurate because we're assuming that the server spends 0ms on processing.
        // (t1 isn't accurate either, as there's bound to have been some processing before that, but we can't avoid that)
        var t1 = servertime,
            t2 = servertime,
            t3 = (new Date()).valueOf();

        // we can get a more accurate version of t2 if the server's response
        // contains a Date header, which it generally will.
        // EDIT: as @Ariel rightly notes, the HTTP Date header only has 
        // second resolution, thus using it will actually make the calculated
        // result worse. For higher accuracy, one would thus have to 
        // return an extra header with a higher-resolution time. This 
        // could be done with nginx for example:
        // http://nginx.org/en/docs/http/ngx_http_core_module.html
        // var date = resp.getResponseHeader("Date");
        // if (date) 
        //     t2 = (new Date(date)).valueOf();
        // 

        var c = ntp(t0, t1, t2, t3);

        // log the calculated value rtt and time driff so we can manually verify if they make sense
        console.log("NTP delay:", c.roundtripdelay, "NTP offset:", c.offset, "corrected: ", (new Date(t3 + c.offset)));
    
);

del lado del servidor (php, pero podría ser cualquier cosa):

Su servidor en la ruta ‘GET / ntp’ debería devolver algo como:

echo (string) round(microtime(true) * 1000);

Si tiene PHP> 5.4, puede guardar una llamada a microtime () y hacerla un poco más precisa con:

echo (string) round($_SERVER['REQUEST_TIME_FLOAT'] * 1000);

NOTA

Esta forma podría verse como una especie de gueto, hay algunas otras respuestas de Stack Overflow que podrían guiarlo hacia una mejor solución:

  • Cómo sincronizar una cuenta atrás de JavaScript con la hora del servidor
  • Sincronizar el tiempo de JS entre varios dispositivos
  • En particular, esta solución se ha ofrecido varias veces: https://github.com/NodeGuy/ServerDate. Parece que esto es un poco más de trabajo para configurar, pero debería proporcionar una mejor precisión.

Aquí puedes ver las reseñas y valoraciones de los usuarios

Si para ti ha resultado útil este artículo, nos gustaría que lo compartas con más juniors y nos ayudes a difundir nuestro contenido.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *