需先用filter_var($var, FILTER_VALIDATE_INT)验证是否为合法整数时间戳,再判断其是否小于time()且大于0,二者缺一不可。

判断变量是否为有效过去时间戳
PHP 里没有内置函数直接说“这个变量是不是过去的时间戳”,得自己组合验证。核心是两步:先确认它是合法的整数型时间戳,再确认它小于当前时间。
常见错误是只用 is_int($var) 或 is_numeric($var) —— 前者会漏掉字符串形式的数字(如 "1609459200"),后者又会把 "123abc" 这种也判为真。
- 用
filter_var($var, FILTER_VALIDATE_INT)验证是否为整数(支持字符串数字) - 再用
$var 判定是否为“过去”(含当前秒) - 额外加个范围检查更稳妥:
$var >= 0 && $var ,排除负数或远超合理范围的值(比如大于 2147483647 的 64 位时间戳在部分旧系统上可能出问题)
区分“过去时间戳”和“过去时间点”
很多人混淆这两个概念:1609459200 是一个时间戳,它代表 2021-01-01 00:00:00 UTC;但判断它“是否过去”,必须结合当前系统时间。同一时间戳,在服务器时间不准、或时区设置异常时,可能被误判。
典型陷阱:
立即学习“PHP免费学习笔记(深入)”;
- 服务器时间比实际晚几分钟 →
time()返回值偏小 → 合法的“刚过”的时间戳被当成“未来” - 代码运行在 Docker 容器中且未同步宿主机时钟 →
time()不可信 - 用了
date_default_timezone_set("Asia/Shanghai")但没意识到time()本身始终返回 Unix 时间戳(UTC 秒数),不受时区影响 —— 所以时区设置不影响判断逻辑,但会影响后续date()格式化结果
封装成可复用的判断函数
直接写一堆条件容易重复出错,建议封装。注意别用 strtotime() 做转换来判断——它会把很多非时间戳字符串(如 "now"、"+1 day")也转成整数,导致误判。
function is_past_timestamp($var): bool
{
if (!is_scalar($var)) {
return false;
}
$int = filter_var($var, FILTER_VALIDATE_INT);
if ($int === false) {
return false;
}
return $int >= 0 && $int <= time();
}这个函数能安全处理:1609459200、"1609459200"、0(Unix 元年)、time() - 1;但会拒绝 null、[]、"2021-01-01"、-1、9999999999(远超当前时间)。
需要考虑毫秒级时间戳?
如果来源是 JavaScript 的 Date.now(),拿到的是毫秒级时间戳(如 1609459200000),直接传给上面函数会失败 —— 因为它远大于 time()(秒级)。这时候不能简单除以 1000 再判断,得先识别格式。
- 长度为 13 位的纯数字字符串 / 整数,大概率是毫秒时间戳
- 可用
strlen((string)$var) === 13 && ctype_digit((string)$var)快速筛查 - 转换后记得用
intval($var / 1000)(不是(int)($var / 1000),避免浮点截断误差) - 但注意:毫秒时间戳超过
PHP_INT_MAX时(如 64 位系统下 13 位数一般没问题),filter_var可能失效,此时应优先用字符串方式校验
真正难的不是写对一行判断,而是搞清数据从哪来、有没有被隐式类型转换污染、以及服务器时间是否可信 —— 这些地方一松懈,is_past_timestamp() 就会变成“看似工作、实则漏判”的幽灵逻辑。











