"3 天前发布"、"剩余 5 天截止"、"2 年前更新"这类距离当前时间的时间差显示,比绝对时间更直观,用户体验更好。织梦的 pubdate 字段存的是时间戳,计算时间差只需用当前时间减去发布时间。本文给出几种典型写法。
一、时间差计算原理
当前时间戳:time() 如 1706899200 发布时间戳:pubdate 如 1706745600 时间差(秒):time() - pubdate=153600 秒 换算: 153600 / 60=2560 分钟 2560 / 60=42.6 小时 42.6 / 24=1.78 天
所有"几天前"都是基于这个差值除以对应单位得到的。
二、写法一:runphp 直接计算
[field:pubdate runphp='yes'] $diff=time() - @me; if($diff < 60) @me='刚刚'; elseif($diff < 3600) @me=floor($diff/60).' 分钟前'; elseif($diff < 86400) @me=floor($diff/3600).' 小时前'; elseif($diff < 2592000) @me=floor($diff/86400).' 天前'; elseif($diff < 31536000) @me=floor($diff/2592000).' 个月前'; else @me=floor($diff/31536000).' 年前'; [/field:pubdate]
三、写法二:封装为自定义函数(推荐)
// /include/extend.func.php
function TimeAgo($time){
$diff=time() - $time;
if($diff < 0) return '未来时间'; // 时间戳大于当前
if($diff < 60) return '刚刚';
if($diff < 3600) return floor($diff/60).' 分钟前';
if($diff < 86400) return floor($diff/3600).' 小时前';
if($diff < 2592000) return floor($diff/86400).' 天前';
if($diff < 31536000) return floor($diff/2592000).' 个月前';
return floor($diff/31536000).' 年前';
}
模板调用:
[field:pubdate function="TimeAgo(@me)"/]
{dede:field.pubdate function="TimeAgo(@me)"/}
四、写法三:超过 N 天显示绝对时间
常见做法是"7 天内显示几天前,7 天后显示标准日期":
function SmartTime($time){
$diff=time() - $time;
if($diff < 86400*7){
// 7 天内用友好时间
if($diff < 60) return '刚刚';
if($diff < 3600) return floor($diff/60).'分钟前';
if($diff < 86400) return floor($diff/3600).'小时前';
return floor($diff/86400).'天前';
} else {
// 7 天后用标准日期
return MyDate('Y-m-d', $time);
}
}
五、距离未来时间(倒计时)
活动页常用"距结束还剩 X 天":
// 自定义字段 endtime 存活动结束时间戳
[field:endtime runphp='yes']
$diff=@me - time();
if($diff <=0){
@me='已结束';
} elseif($diff < 86400){
@me='剩 '.floor($diff/3600).' 小时';
} else {
@me='剩 '.floor($diff/86400).' 天';
}
[/field:endtime]
精确到时分秒的倒计时
function Countdown($endtime){
$diff=$endtime - time();
if($diff <=0) return '已结束';
$d=floor($diff/86400);
$h=floor(($diff%86400)/3600);
$m=floor(($diff%3600)/60);
$s=$diff%60;
return "{$d}天 {$h}时 {$m}分 {$s}秒";
}
六、典型应用场景
1. 列表页友好时间
{dede:arclist typeid='1' row='10'}
<li>
<span class="time">[field:pubdate function="TimeAgo(@me)"/]</span>
<a href="[field:arcurl/]">[field:title/]</a>
</li>
{/dede:arclist}
2. 内容页"最后更新"提示
<p class="update-info">
本文最后更新于 {dede:field.pubdate function="SmartTime(@me)"/}
,请注意内容时效性。
</p>
3. 活动倒计时
<div class="countdown">
距活动结束:{dede:field.endtime function="Countdown(@me)"/}
</div>
4. 新文章标识
[field:pubdate runphp='yes']
$diff=time() - @me;
if($diff < 86400*3){ // 3 天内
@me='<span class="new-tag">NEW</span>';
} else {
@me='';
}
[/field:pubdate]
七、时间差对照表
| 秒数 | 天数 | 显示 |
|---|---|---|
| 60 | 1 分钟 | 刚刚 |
| 3600 | 1 小时 | X 分钟前 |
| 86400 | 1 天 | X 小时前 |
| 259200 | 3 天 | X 天前 |
| 604800 | 7 天 | X 天前 / 切换绝对时间 |
| 2592000 | 30 天 | X 个月前 |
| 31536000 | 365 天 | X 年前 |
八、注意事项
静态页时间差会"冻结":静态 HTML 生成后,里面的"3 天前"就被写死成文本了,不会随时间推移变化。需要实时时间差必须用动态页或用 JS 计算。
JS 动态计算时间差:静态页用 JS 实现实时"几天前":
<span data-time="[field:pubdate/]" class="js-time">[field:pubdate function="MyDate('Y-m-d',@me)"/]</span>
<script>
document.querySelectorAll('.js-time').forEach(function(el){
var t=parseInt(el.getAttribute('data-time')) * 1000;
var diff=Date.now() - t;
var txt;
if(diff < 60000) txt='刚刚';
else if(diff < 3600000) txt=Math.floor(diff/60000)+'分钟前';
else if(diff < 86400000) txt=Math.floor(diff/3600000)+'小时前';
else txt=Math.floor(diff/86400000)+'天前';
el.innerText=txt;
});
</script>
时间戳为 0 的处理:某些文章 pubdate 为 0,TimeAgo 会输出"55 年前"。函数开头加判断:if($time==0) return '未知时间';。
未来时间处理:采集或定时发布时,pubdate 可能大于当前时间,TimeAgo 会输出负数。函数开头加 if($diff < 0) return '即将发布';。
九、应用建议
时间差显示能显著提升用户体验,但要注意静态与动态的差异。纯静态站点建议用 JS 动态计算时间差(保留 HTML 里的时间戳作为 data 属性),既不影响 SEO(搜索引擎抓到的是绝对时间),又能让用户看到实时"几天前"。把 TimeAgo、SmartTime、Countdown 三个函数固化进 extend.func.php,覆盖"过去时间、智能切换、未来倒计时"三种场景。SEO 与体验兼顾的最佳实践是:HTML 里同时输出绝对时间(time 标签)与时间戳(data 属性),JS 把时间戳转成友好显示,搜索引擎仍能读到准确的发布日期。