120 lines
3.6 KiB
TypeScript
120 lines
3.6 KiB
TypeScript
|
|
/**
|
|||
|
|
* 自动将任意精度的时间戳转换为毫秒级时间戳
|
|||
|
|
* 支持:秒(10位)、毫秒(13位)、微秒(16位)、纳秒(19位)
|
|||
|
|
*/
|
|||
|
|
function normalizeTimestamp(ts: number): number {
|
|||
|
|
if (ts <= 0) return ts;
|
|||
|
|
|
|||
|
|
const len = Math.floor(ts).toString().length;
|
|||
|
|
|
|||
|
|
if (len <= 10) {
|
|||
|
|
return ts * 1000;
|
|||
|
|
} else if (len <= 13) {
|
|||
|
|
return ts;
|
|||
|
|
} else if (len <= 16) {
|
|||
|
|
return Math.floor(ts / 1000);
|
|||
|
|
} else {
|
|||
|
|
return Math.floor(ts / 1000000);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 格式化时间戳为友好的显示格式(用于聊天/消息列表等)
|
|||
|
|
* - 当天、昨天:显示详细时间 HH:MM(昨天带「昨天」前缀)
|
|||
|
|
* - 大于昨天且在七天内:显示「X天前」
|
|||
|
|
* - 超过七天且本年:显示 MM/DD
|
|||
|
|
* - 非本年:显示 YY/MM/DD
|
|||
|
|
* 自动识别时间戳精度,支持秒/毫秒/微秒/纳秒级时间戳
|
|||
|
|
*/
|
|||
|
|
export function formatTime(ts: number): string {
|
|||
|
|
const MS = 1;
|
|||
|
|
const MINUTE = MS * 1000 * 60;
|
|||
|
|
const HOUR = MINUTE * 60;
|
|||
|
|
const DAY = HOUR * 24;
|
|||
|
|
|
|||
|
|
const normalizedTs = normalizeTimestamp(ts);
|
|||
|
|
const now = Date.now();
|
|||
|
|
const diff = now - normalizedTs;
|
|||
|
|
|
|||
|
|
if (diff <= 0) return '未来';
|
|||
|
|
if (diff < MINUTE) return '刚刚';
|
|||
|
|
|
|||
|
|
const target = new Date(normalizedTs);
|
|||
|
|
const today = new Date(now);
|
|||
|
|
|
|||
|
|
const pad = (n: number) => String(n).padStart(2, '0');
|
|||
|
|
const hm = `${pad(target.getHours())}:${pad(target.getMinutes())}`;
|
|||
|
|
|
|||
|
|
const isSameDay = (a: Date, b: Date) =>
|
|||
|
|
a.getFullYear() === b.getFullYear() &&
|
|||
|
|
a.getMonth() === b.getMonth() &&
|
|||
|
|
a.getDate() === b.getDate();
|
|||
|
|
|
|||
|
|
if (isSameDay(today, target)) return hm;
|
|||
|
|
|
|||
|
|
const yesterday = new Date(today);
|
|||
|
|
yesterday.setDate(today.getDate() - 1);
|
|||
|
|
if (isSameDay(yesterday, target)) return `昨天 ${hm}`;
|
|||
|
|
|
|||
|
|
// 按日历天数算「X天前」,避免「前天」因不足 48 小时被算成 1 天
|
|||
|
|
const todayStart = new Date(today.getFullYear(), today.getMonth(), today.getDate()).getTime();
|
|||
|
|
const targetStart = new Date(target.getFullYear(), target.getMonth(), target.getDate()).getTime();
|
|||
|
|
const calendarDaysAgo = Math.floor((todayStart - targetStart) / DAY);
|
|||
|
|
if (calendarDaysAgo >= 2 && calendarDaysAgo <= 7) return `${calendarDaysAgo}天前`;
|
|||
|
|
|
|||
|
|
const MM = pad(target.getMonth() + 1);
|
|||
|
|
const DD = pad(target.getDate());
|
|||
|
|
if (target.getFullYear() !== today.getFullYear()) {
|
|||
|
|
const YY = String(target.getFullYear()).slice(-2);
|
|||
|
|
return `${YY}/${MM}/${DD}`;
|
|||
|
|
}
|
|||
|
|
return `${MM}/${DD}`;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 信息流用时间格式(Feed 专用)
|
|||
|
|
* - 1 分钟内:刚刚
|
|||
|
|
* - 1 分钟~1 小时:xx分钟前
|
|||
|
|
* - 1 小时~1 天:xx小时前
|
|||
|
|
* - 1 天~1 周:x天前
|
|||
|
|
* - 超过 1 周、今年内:MM/DD
|
|||
|
|
* - 不是今年:YYYY/MM/DD
|
|||
|
|
*/
|
|||
|
|
export function formatFeedTime(ts: number): string {
|
|||
|
|
const MS = 1;
|
|||
|
|
const MINUTE = MS * 1000 * 60;
|
|||
|
|
const HOUR = MINUTE * 60;
|
|||
|
|
const DAY = HOUR * 24;
|
|||
|
|
const WEEK = DAY * 7;
|
|||
|
|
|
|||
|
|
const normalizedTs = normalizeTimestamp(ts);
|
|||
|
|
const now = Date.now();
|
|||
|
|
const diff = now - normalizedTs;
|
|||
|
|
|
|||
|
|
if (diff <= 0) return '刚刚';
|
|||
|
|
if (diff < MINUTE) return '刚刚';
|
|||
|
|
if (diff < HOUR) {
|
|||
|
|
const m = Math.floor(diff / MINUTE);
|
|||
|
|
return `${m}分钟前`;
|
|||
|
|
}
|
|||
|
|
if (diff < DAY) {
|
|||
|
|
const h = Math.floor(diff / HOUR);
|
|||
|
|
return `${h}小时前`;
|
|||
|
|
}
|
|||
|
|
if (diff < WEEK) {
|
|||
|
|
const d = Math.floor(diff / DAY);
|
|||
|
|
return `${d}天前`;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const target = new Date(normalizedTs);
|
|||
|
|
const today = new Date(now);
|
|||
|
|
const pad = (n: number) => String(n).padStart(2, '0');
|
|||
|
|
const MM = pad(target.getMonth() + 1);
|
|||
|
|
const DD = pad(target.getDate());
|
|||
|
|
|
|||
|
|
if (target.getFullYear() !== today.getFullYear()) {
|
|||
|
|
return `${target.getFullYear()}/${MM}/${DD}`;
|
|||
|
|
}
|
|||
|
|
return `${MM}/${DD}`;
|
|||
|
|
}
|