我正在建立一个时间和价格都在下降的网站。我最关心的是同步时间,以便在所有客户端上尽可能准确。
目前,我正在向客户端发送剩余的毫秒数,然后将其用于为倒数计时器加油,但由于传输和渲染延迟,即使在同一台计算机上使用 2 个浏览器,这也可能会关闭几秒钟。
有没有办法同步客户端的javascript时间和服务器时间,还是我只需要处理这个轻微的延迟?
如果只有一种方法可以准确测量服务器发送数据与客户端接收和呈现数据之间的时间差。
我正在建立一个时间和价格都在下降的网站。我最关心的是同步时间,以便在所有客户端上尽可能准确。
目前,我正在向客户端发送剩余的毫秒数,然后将其用于为倒数计时器加油,但由于传输和渲染延迟,即使在同一台计算机上使用 2 个浏览器,这也可能会关闭几秒钟。
有没有办法同步客户端的javascript时间和服务器时间,还是我只需要处理这个轻微的延迟?
如果只有一种方法可以准确测量服务器发送数据与客户端接收和呈现数据之间的时间差。
即使服务器和客户端上的时间会有所不同,但时间变化的速率应该基本相同。我会将剩余时间发送给客户端,然后让客户端将该时间添加到当前时间,然后让客户端从中计算倒计时。例如:
var timeRemaining = [rendered on page load or queried by ajax]; // in milliseconds
var endTime = new Date(new Date().getTime() + timeRemaining);
// Put this in a setInterval, or however you currently handle it
var countdown = (endTime.getTime() - new Date().getTime()) / 1000;
有一种方法可以使客户端与服务器的时间同步。我写了一个这样做的库:ServerDate。
这是自述文件的一部分:
您可以ServerDate
像使用Date
函数或其实例之一一样使用,例如:
> ServerDate()
"Mon Aug 13 2012 20:26:34 GMT-0300 (ART)"
> ServerDate.now()
1344900478753
> ServerDate.getMilliseconds()
22
还有一种新方法可以获取 ServerDate 对服务器时钟的估计精度(以毫秒为单位):
> ServerDate.toLocaleString() + " ± " + ServerDate.getPrecision() + " ms"
"Tue Aug 14 01:01:49 2012 ± 108 ms"
您可以看到服务器时钟和浏览器时钟之间的差异,以毫秒为单位:
> ServerDate - new Date()
39
您可以测量整个服务器往返所需的时间并除以 2 以获得对时间差的良好估计。请注意:不能保证 IP 包在两个方向上采用相同的路由,但概率相当高。
Date.getTime()
如果毫秒分辨率对您来说足够了,您可以使用。
对此的解决方案是 Javascript——它可以访问客户端上的时区设置。不幸的是,它只能为您提供特定日期的时区偏移量(以分钟为单位),没有时区名称。因此,要确定正确的时区,我们还需要知道是否正在使用夏令时(DST)——这是解决方案的客户端部分:
var now = new Date();
var later = new Date();
// Set time for how long the cookie should be saved
later.setTime(now.getTime() + 365 * 24 * 60 * 60 * 1000);
// Set cookie for the time zone offset in minutes
setCookie("time_zone_offset", now.getTimezoneOffset(), later, "/");
// Create two new dates
var d1 = new Date();
var d2 = new Date();
// Date one is set to January 1st of this year
// Guaranteed not to be in DST for northern hemisphere,
// and guaranteed to be in DST for southern hemisphere
// (If DST exists on client PC)
d1.setDate(1);
d1.setMonth(1);
// Date two is set to July 1st of this year
// Guaranteed to be in DST for northern hemisphere,
// and guaranteed not to be in DST for southern hemisphere
// (If DST exists on client PC)
d2.setDate(1);
d2.setMonth(7);
// If time zone offsets match, no DST exists for this time zone
if(parseInt(d1.getTimezoneOffset())==parseInt(d2.getTimezoneOffset()))
{
setCookie("time_zone_dst", "0", later, "/");
}
// DST exists for this time zone – check if it is currently active
else {
// Find out if we are on northern or southern hemisphere
// Hemisphere is positive for northern, and negative for southern
var hemisphere = parseInt(d1.getTimezoneOffset())-parseInt(d2.getTimezoneOffset());
// Current date is still before or after DST, not containing DST
if((hemisphere>0 && parseInt(d1.getTimezoneOffset())==parseInt(now.getTimezoneOffset())) ||
(hemisphere<0 && parseInt(d2.getTimezoneOffset())==parseInt(now.getTimezoneOffset()))) { setCookie("time_zone_dst", "0", later, "/"); } // DST is active right now with the current date else { setCookie("time_zone_dst", "1", later, "/"); } }
您将结果保存为 cookie,您的 PHP 脚本可以访问这些结果。您应该至少在用户访问的第一页上包含上述代码——我在每个页面上都包含它以识别(并适应)更改,即使会话期间不太可能发生此类更改。
在 PHP 中,您可以使用名为 timezone_name_from_abbr 的新函数提取有效时区,该函数从 PHP 5.1.3 开始可用——它需要时区缩写或时区偏移量(以秒为单位)和夏令时的组合,我们有后一种组合:
$time_zone_name = timezone_name_from_abbr(", -$_COOKIE['time_zone_offset']*60, $_COOKIE['time_zone_dst']);
如果 cookie 中的数据有效,这将为用户提供正确的时区名称 - 请注意,有许多“重复”名称,例如“Europe/Berlin”和“Europe/Zurich”,它们具有准确的相同的时区设置(至少现在是这样),并且您可以获得其中任何一个来获取适当的偏移量和 DST 变量。时区名称列表可以在 php.net 上的支持时区列表中找到。
创建具有给定时区的日期字符串 使用 用户的时区名称,您现在可以使用 PHP 类 DateTimeZone 和 DateTime 最终创建具有正确时区的日期字符串:
// Create time zone class
$time_zone_class = new DateTimeZone($time_zone_name);
// Create new date class with a given date
// Notice that the provided date will be regarded as being in the
// default time zone and converted accordingly
$new_date = new DateTime(‘2007-02-14 15:30:00′, $time_zone_class);
// Print date with the user’s time zone echo $new_date->format(‘Y-m-d H:i:s’);
就是这样!