Tengo la tarea de mostrar el reloj digital (con precisión de minutos) en la página HTML en una zona horaria fija (MSK o MSD, según la fecha actual). Me gustaría evitar depender del reloj del sistema del cliente, por lo que se requiere cierta sincronización con el servidor. El servidor HTTP envía el encabezado de fecha en cada respuesta para que podamos enviar una solicitud AJAX GET o HEAD a cualquier URL de nuestro sitio para obtener la fecha del servidor, calcular la diferencia con la fecha del cliente y usarla al actualizar el reloj con setTimeout (). Existen otros problemas: cambio de zona horaria para la configuración de la luz del día, contabilidad de latencia para conexiones muy lentas.

¿Alguna idea de esta tarea de la manera más simple? Prefiero resolverlo sin programación del lado del servidor.

62
n0s 28 oct. 2009 a las 19:20

6 respuestas

La mejor respuesta

Debe recordar el tiempo del cliente entre readyState == 2 y readyState == 3 si va a usar ajax, porque la hora del servidor se establecerá en algún momento entre el momento de la solicitud recibida y la respuesta preparada

9
Victor Kotseruba 28 oct. 2009 a las 18:00

Sincronizaría la hora durante la inicialización con Internet Time Server.

http://tf.nist.gov/service/its.htm

-2
Cheok Yan Cheng 28 oct. 2009 a las 16:51

Gracias a @Mehdi Yeganeh y @Fedearne. Implemento mi función para usar tanto la lógica como su trabajo.

https://gist.github.com/ethaizone/6abb1d437dbe406fbed6

0
EThaizone Jo 8 mar. 2016 a las 11:22

Solo solicitaría la actualización del servidor cada 30 segundos más o menos, si requiere precisión solo al minuto. No confíe en absoluto en el tiempo del cliente, pero use su reloj del sistema para mantener el reloj preciso entre actualizaciones. ¿Creo que respondiste tu propia pregunta?

Sería útil si entendiéramos mejor lo que realmente estás tratando de hacer.

Si simplemente desea que un reloj muestre la hora en el servidor, que luego se ajusta a una determinada zona horaria, hágalo en el lado del cliente con compensaciones. Maneje el horario de verano en las zonas horarias, es aplicable utilizando la fecha que recibe del servidor también. Si desea determinar la latencia, probablemente necesite un pequeño script en el servidor para calcular la diferencia. Pero como anteriormente, ayudaría a comprender mejor el problema. Si la precisión es solo al minuto, la latencia parece menos crítica.

0
snicker 28 oct. 2009 a las 16:44

Descubrí que el algoritmo de @ mehdi-yeganeh anterior no me dio resultados útiles, pero la idea es acertada: 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, utiliza 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)));
    }
});

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 hacerlo un poco más preciso con:

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

NOTA

De esta manera podría verse como una especie de ghetto, hay otras respuestas de Stack Overflow que podrían guiarlo hacia una mejor solución:

26
Community 23 may. 2017 a las 12:34

Estas dos funciones de Javascript deberían ayudarte.

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: eliminó ".replace (/ ^ (. ) [\ s \ S] /," $ 1 ")".

CalcOffset () calcula el desplazamiento desde 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 tiempo en ejecutarse, puede perder algunos segundos de precisión. Tal vez el tiempo de ejecución podría tenerse en cuenta ...

Si le preocupa que la compensación calculada se vuelva incorrecta cuando la hora local o la hora del servidor cambian hacia o desde el horario de verano, podría volver a calcular un poco después de cada hora, el sistema compensará los cambios en el horario de verano. Puede ser 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 .....

38
Fedearne 30 oct. 2009 a las 09:08