created_at(服务器时间)有时比clicked_at(客户端时间)早——这是为什么?
我在跟踪网站上的按钮点击,并在数据库中保存两类时间信息:客户端点击时间和服务器端插入时间。
前端(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()(客户端机器时间)生成的
问题:
为什么会这样?在客户端和服务器之间正确处理或规范化时间戳的方式是什么?
我应该:
- 相信客户端时间(
clicked_at)? - 相信服务器时间(
created_at)? - 还是计算延迟并进行调整?
如有关于跟踪准确事件时间的最佳实践的建议,将不胜感激。
解决方案
在某些情况下,clicked_at(客户端时间)晚于created_at(服务器时间)
这可能有两个主要原因:
- 并非所有计算机的时钟时间完全相同,因此它们会生成不同的时间戳
- 客户端(浏览器)提供的任何数据都可能被修改
因此,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导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。