created_at(服务器时间)有时比clicked_at(客户端时间)早——这是为什么?

前端开发 2026-07-11

我在跟踪网站上的按钮点击,并在数据库中保存两类时间信息:客户端点击时间服务器端插入时间

前端(JavaScript)

我这样捕获点击时间戳:

clicked_at: Date.now() // milliseconds

后端(PHP)

在服务器端,我将其转换并存储:

if (isset($clicked_at) && is_numeric($clicked_at)) {
    $clicked_at = date("Y-m-d H:i:s", $clicked_at / 1000);
}

$created_at = date("Y-m-d H:i:s");

数据库示例

created_at  = 2026-03-27 16:22:03
clicked_at  = 2026-03-27 16:22:04

问题

在某些情况下,clicked_at(客户端时间)晚于created_at(服务器时间),尽管从逻辑上讲,点击发生在服务器接收到请求之前。

预期

clicked_at <= created_at

实际

clicked_at > created_at

附加信息

  • 客户端使用 navigator.sendBeacon()fetch() 发送数据
  • 服务器时区设置为 Asia/Kolkata
  • clicked_at 是使用 Date.now()(客户端机器时间)生成的

问题:

为什么会这样?在客户端和服务器之间正确处理或规范化时间戳的方式是什么?

我应该:

  1. 相信客户端时间(clicked_at)?
  2. 相信服务器时间(created_at)?
  3. 还是计算延迟并进行调整?

如有关于跟踪准确事件时间的最佳实践的建议,将不胜感激。

解决方案

在某些情况下,clicked_at(客户端时间)晚于created_at(服务器时间)

这可能有两个主要原因:

  1. 并非所有计算机的时钟时间完全相同,因此它们会生成不同的时间戳
  2. 客户端(浏览器)提供的任何数据都可能被修改

因此,clicked_at 应被视为来自不可信信息源的信息。

三种常见的处理方法随之浮现:

彻底不要依赖客户端

把到达服务器的请求作为点击的时间戳:

$created_at = date("Y-m-d H:i:s");
$clicked_at = $created_at;

如果你把数据存储在 clicks 表或类似结构中,这可能会使 clicked_at 时间字段变得冗余,因此你可以完全移除它,只使用 created_at

验证输入

允许指定点击时间,但仅允许逻辑上有效的值:

$created_at = date("Y-m-d H:i:s");
if (isset($clicked_at) && is_numeric($clicked_at)) {
    $now_ms = microtime(true) * 1000;
    $diff = $now_ms - $clicked_at;

    if ($diff < 0) {                     # Is future dated
         $clicked_at = $created_at;
    } elseif ($diff > 60000) {           # Too old (e.g. >60s)
        $clicked_at = $created_at;
    } else {                             # Goldilocks zone - use provided value
        $clicked_at = date("Y-m-d H:i:s", intval($clicked_at / 1000));
    }
}

通过这种方式,你可以容忍一些延迟报告(网络延迟、请求重试),而不会导致数据不一致。

存储提交的值

就照你现在做的做,但不要把它视为唯一的真相来源。值可以稍后进行规范化(例如在查询时),并且保留原始值可以提供有用的信号(例如很久以前的点击时间),用于纠正/识别不真实的流量。

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章