【问题标题】:Normalize time on the client-side (javascript)在客户端标准化时间(javascript)
【发布时间】:2019-12-31 00:13:30
【问题描述】:

问题:

对于内部计算机时钟关闭的用户,您如何规范化 javascript 中的客户端时间戳?请注意,我处理的是 UTC 时间。

上下文:

我有一个 AWS ElasticSearch 实例,其中设置了几个批处理和节流操作,这使得服务器端时间戳不可靠(因为数据可能无序进入,并且顺序很重要)。因此,我需要让我的客户端时间戳更可靠。

约束:

我无法发出任何服务器端请求(需要将 HTTP 请求保持在最低限度),但我可以包含在我的 javascript 首次加载到客户端时生成的服务器端时间戳.


尝试的解决方案:

外部定义的变量:

  • serverTimestamp - UTC 时间戳(以毫秒为单位),在加载 javascript 时在服务器端生成。
  • getCookie - 获取给定键的 cookie 值的函数(如果未找到,则为空字符串)。

文件的缓存控制设置为 "public,max-age=300,must-revalidate"(所以 5 分钟)。

const getTimestamp = (function() {
    // This cookie is set on the `unload` event, and so should be greater than
    // the server-side timestamp when set.
    /** @type {!number} */
    const cookieTimestamp = parseInt(getCookie("timestamp_cookie"), 10) || 0;
    // This timestamp _should_ be a maximum of 5 minutes behind on page load
    // (cache lasts 5 min for this file).
    /** @type {!number} */
    const storedTimestamp = cookieTimestamp > serverTimestamp ?
                            cookieTimestamp : serverTimestamp;
    return function () {
        /** @type {!number} */
        const timestamp = Date.now();
        // This timestamp should be, at a *maximum*, 5-6 minutes behind
        // (assuming the user doesn't have caching issues)
        /** @type {!number} */
        const backupTimestamp = storedTimestamp
            + parseFloat(window.performance.now().toFixed(0));
        // Now let's check to see if the user's clock is
        // either too fast, or too slow:
        if (
            // Timestamp is smaller than the stored one.
            // This means the user's clock is too slow.
            timestamp < backupTimestamp
            // Timestamp is more than 6 minutes ahead. User's clock is too fast.
            // (Using 6 minutes instead of 5 to have 1 minute of padding)
            || (timestamp - backupTimestamp) > 360000
        ) {
            return backupTimestamp;
        } else {
            // Seems like the user's clock isn't too fast or too slow
            // (or just maximum 1 minute fast)
            return timestamp;
        }
    }
})();

解决问题:

使用上面的getTimestamp 函数,运行(new Date(getTimestamp())).getUTCDate() 会在第二天为某些用户返回,而getUTCHours 似乎在边缘情况下到处都是。我无法自行诊断问题。

【问题讨论】:

  • 不要用时间戳标记从 GMT 开始的日期,如果需要,您可以翻译成您当地的 TZ?
  • 我实际上正在尝试将所有内容保持在 GMT / UTC 中。我不希望这特定于任何时区——我正在尝试跨奇怪的时区/浏览器标准化时间。
  • 使用 Date.toUTCString() 代替 Date.toString():stackoverflow.com/questions/17545708/…
  • 您不能依赖客户端时间,因为它可以更改。您将不得不依靠您控制时间的服务器。在 PHP 中你会做类似&lt;?php date_default_timezone_set('UTC'); $o = new StdClass; if(isset($_POST['get_time'])){ /* make sure AJAX get_time is set */ $o-&gt;time = time(); echo json_encode($o); /* now you have object with time property for javascript AJAX argument */ } ?&gt;
  • 您需要什么精度(毫秒、秒、分钟?);你是否足够信任客户?即,如果客户端操纵 javascript 或发布错误数据,您的系统可能发生的最坏情况是什么? NTP 的存在是因为很难准确地进行分布式时间同步,但如果您不太关心秒数,并且对修复关闭一天左右的客户端时钟更感兴趣,那么@symcbean 解决方案可能就足够了。我很犹豫,因为你说“顺序很重要”!我对您的最终解决方案感兴趣,希望看到您将其发布为答案。

标签: javascript


【解决方案1】:

坚持客户端的时间戳 - 不要为日期/时间烦恼。将服务器端和客户端时钟之间的增量存储在客户端上。使用消息发送客户端时间戳和增量,然后在服务器上重建日期/时间。

然后,您可以在服务器端就如何处理时钟同步中的抖动和跳跃做出明智的决定。

【讨论】:

  • 哦,保存时钟之间的增量是一个有趣的想法。也许我可以开始保存该信息以查看增量可以有多大,以及此问题发生的频率。
【解决方案2】:

您不应依赖客户来保证时间。您的 JavaScript 可能类似于:

var fd = new FormData, xhr = new XMLHttpRequest;
fd.append('get_time', '1'); xhr.open('POST', 'gettime.php');
xhr.onload = function(response){
  var obj = JSON.parse(response.responseText);
  console.log(obj.time);
}
xhr.send(fd);

如果使用 PHP:

<?php // gettime.php
date_default_timezone_set('UTC'); $o = new StdClass;
if(isset($_POST['get_time'])){
  $o->time = time();
  echo json_encode($o);
}
?>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-23
    • 1970-01-01
    • 1970-01-01
    • 2020-05-16
    • 2013-10-14
    • 1970-01-01
    相关资源
    最近更新 更多