n0s*_*n0s 57 javascript ajax timezone clock-synchronization
我有一个任务是在某个固定时区(MSK或MSD - 取决于当前日期)的HTML页面上显示数字时钟(具有分钟精度).我想避免依赖客户端系统时钟,因此需要与服务器进行一些同步.HTTP服务器在每个响应中发送Date头,因此我们可以向我们站点的任何URL发送AJAX GET或HEAD请求以获取服务器日期,计算与客户端日期的差异,并在使用setTimeout()更新时钟时使用它.还有其他问题:日光设置的时区切换,非常慢的连接的延迟计算.
对这项任务的任何想法都是最简单的方法吗?我更愿意在没有服务器端编程的情况下解决它.
Fed*_*rne 38
这两个Javascript函数应该可以帮到你.
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;
}
Run Code Online (Sandbox Code Playgroud)
编辑:删除".replace(/ ^(.)[\ s\S] /,"$ 1")".
calcOffset()计算服务器时间的偏移量并补偿GMT/UTC.
getServerTime()使用本地时区获取与服务器匹配的本地时间偏移量.
如果calcOffset()花费时间执行,则可能会失去一些秒精度.也许可以考虑执行时间....
如果您担心当本地时间或服务器时间更改为夏令时或从夏令时变为计算的偏移时,您可以在每个时钟小时后重新计算一个litle,系统将补偿dayligt节省时间的变化.可能需要等到本地和服务器时钟都过了一小时.
该示例仅适用于IE,因为"Msxml2.XMLHTTP"我认为......
Meh*_*neh 34
您可以使用代码中的NTP(网络时间协议)计算确切时间,
我试着为你解释一下:
X(SyncedTime) =Now + (ServerClientDifferenceTimeWithRequestTime - RquestTime)
X(SyncedTime) =Now + (ServerClientDifferenceTimeWithResponseTime - ResponseTime)
Now - ClientTime = RquestTime + ResponseTime =>
Now - (ServerClientDiffRq - RquestTime) = Now - (ServerClientDiffRs - ResponseTime)
如果你解决了,你发现了这个:
ResponseTime = (ServerClientDifferenceTimeWithRequestTime - Now + ClientTime + - ServerClientDifferenceTimeWithResponseTime )/2
然后您可以使用以下等式在客户端中找到同步时间或服务器时间:
X(SyncedTime) =Now + (ServerClientDifferenceTimeWithResponseTime - ResponseTime)
我显示简单的代码但是当你想要写它时不要忘记使用UTC日期和时间函数...
服务器端(例如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}";
Run Code Online (Sandbox Code Playgroud)
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+"}");
Run Code Online (Sandbox Code Playgroud)
客户端(Javascript与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);
});
Run Code Online (Sandbox Code Playgroud)
Akt*_*tau 26
我发现上面的@mehdi-yeganeh算法没有给我有用的结果但是这个想法是合理的:使用NTP算法(或者至少是它的弱版本)来同步服务器和客户端时钟.
这是我的最终实现,它使用服务器响应头(如果可用的话)以获得额外的准确性(如果我错了,请纠正我,我自己的测试说这是非常准确的).
// 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)));
}
});
Run Code Online (Sandbox Code Playgroud)
您在'GET/ntp'路线上的服务器应该返回如下内容:
echo (string) round(microtime(true) * 1000);
Run Code Online (Sandbox Code Playgroud)
如果您的PHP> 5.4,那么您可以保存对microtime()的调用并使其更准确:
echo (string) round($_SERVER['REQUEST_TIME_FLOAT'] * 1000);
Run Code Online (Sandbox Code Playgroud)
这种方式可能被视为一种贫民区,还有一些其他Stack Overflow答案可以指导您找到更好的解决方案: