'use client'; import { useState, useEffect } from 'react'; interface TimeAgoProps { date: string | Date | null | undefined; className?: string; } export default function TimeAgo({ date, className = '' }: TimeAgoProps) { const [timeAgo, setTimeAgo] = useState('-'); useEffect(() => { if (!date) return; const calculateTimeAgo = () => { let dateObj: Date; // === 核心修复逻辑 === if (typeof date === 'string') { // 1. 兼容空格格式 let normalizedDate = date.replace(' ', 'T'); // 2. 如果没有时区标识,强制追加 'Z',将其视为 UTC 时间 if (!normalizedDate.endsWith('Z') && !normalizedDate.includes('+')) { normalizedDate += 'Z'; } dateObj = new Date(normalizedDate); } else { dateObj = new Date(date); } // 检查日期有效性 if (isNaN(dateObj.getTime())) { setTimeAgo('-'); return; } const past = dateObj.getTime(); const now = new Date().getTime(); const diffInSeconds = Math.floor((now - past) / 1000); // 处理未来时间(可能是本地时间偏差或服务器时间超前) if (diffInSeconds < 0) { setTimeAgo('刚刚'); return; } if (diffInSeconds < 60) { setTimeAgo(`${diffInSeconds}秒前`); } else if (diffInSeconds < 3600) { setTimeAgo(`${Math.floor(diffInSeconds / 60)}分钟前`); } else if (diffInSeconds < 86400) { setTimeAgo(`${Math.floor(diffInSeconds / 3600)}小时前`); } else if (diffInSeconds < 2592000) { // 30天 setTimeAgo(`${Math.floor(diffInSeconds / 86400)}天前`); } else if (diffInSeconds < 31536000) { // 365天 setTimeAgo(`${Math.floor(diffInSeconds / 2592000)}个月前`); } else { setTimeAgo(`${Math.floor(diffInSeconds / 31536000)}年前`); } }; calculateTimeAgo(); // 每分钟更新一次文本 const interval = setInterval(calculateTimeAgo, 60000); return () => clearInterval(interval); }, [date]); if (!date) return -; // 使用 title 属性显示完整的本地时间,方便鼠标悬停查看 // 注意:这里仅用于 title 属性的展示,不需要像 LocalTime 那样处理 SSR 水合问题 return ( {timeAgo} ); }