| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879 |
- '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<string>('-');
- 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 <span className="text-gray-300">-</span>;
- // 使用 title 属性显示完整的本地时间,方便鼠标悬停查看
- // 注意:这里仅用于 title 属性的展示,不需要像 LocalTime 那样处理 SSR 水合问题
- return (
- <span className={className} title={new Date(date).toLocaleString()}>
- {timeAgo}
- </span>
- );
- }
|