在 PHP 中,将时间戳(或秒数)转换为时长(如“X天X小时X分X秒”),本质上是一个纯数学量纲转换问题,而不是绝对时间点的格式化。

核心思路是:获取总秒数后,通过逐级整除取余(floor division & modulus)的方式,依次计算出天、小时、分钟和秒。

以下为您提供一个生产就绪、高内聚的 PHP 函数实现:

核心实现代码

  1. /**
  2. * 将秒数转换为可读的时长格式
  3. *
  4. * @param int $totalSeconds 总秒数
  5. * @param bool $includeZeroUnits 是否包含值为0的时间单位(默认false,省略0值)
  6. * @return string 格式化后的时长字符串
  7. */
  8. function formatSecondsToDuration(int $totalSeconds, bool $includeZeroUnits = false): string
  9. {
  10. // 处理负数情况,保证语义一致性
  11. $isNegative = $totalSeconds < 0;
  12. $seconds = abs($totalSeconds);
  13. // 1天 = 86400秒
  14. $days = floor($seconds / 86400);
  15. $seconds %= 86400;
  16. // 1小时 = 3600秒
  17. $hours = floor($seconds / 3600);
  18. $seconds %= 3600;
  19. // 1分钟 = 60秒
  20. $minutes = floor($seconds / 60);
  21. $secs = $seconds % 60;
  22. // 组装结果
  23. $parts = [];
  24. if ($includeZeroUnits || $days > 0) $parts[] = "{$days}天";
  25. if ($includeZeroUnits || $hours > 0) $parts[] = "{$hours}小时";
  26. if ($includeZeroUnits || $minutes > 0) $parts[] = "{$minutes}分";
  27. if ($includeZeroUnits || $secs > 0 || empty($parts)) $parts[] = "{$secs}秒"; // 如果全为0,至少显示0秒
  28. $result = implode('', $parts);
  29. return $isNegative ? "-{$result}" : $result;
  30. }

使用示例

  1. // 示例 1:常规转换
  2. echo formatSecondsToDuration(90061);
  3. // 输出: 1天1小时1分1秒
  4. // 示例 2:省略为0的单位
  5. echo formatSecondsToDuration(3661);
  6. // 输出: 1小时1分1秒
  7. // 示例 3:包含为0的单位
  8. echo formatSecondsToDuration(3661, true);
  9. // 输出: 0天1小时1分1秒
  10. // 示例 4:处理负数(如已超时的倒计时)
  11. echo formatSecondsToDuration(-125);
  12. // 输出: -2分5秒

⚠️ 开发避坑指南

  1. 不要使用 date() 函数date('H:i:s', $seconds) 是将秒数当作自 1970 年以来的绝对时间点来解析的。如果传入 3661,它会解析为 1970-01-01 01:01:01,这完全偏离了“相对时长”的语义。
  2. 必须使用 floor() 向下取整:在处理负数秒数时(例如 -125 秒),floor(-125 / 60) 会得到 -3,配合取余可以正确表达 -2分5秒 的语义。如果使用 (int) 强转或 round(),会导致截断错误。
  3. 时区无关性:时长的计算(如 1天=86400秒)是纯数学逻辑,与时区无关。但如果您是通过两个时间戳相减(如 $end - $start)来获取总秒数,请务必确保两个时间戳处于统一的时区标准下(推荐 UTC)。
  4. 毫秒级时间戳处理:如果您的时间戳是毫秒级(13位),请先除以 1000 转为秒级再进行计算。