FrontTools/FormatTimeTool.ts
Rain 3ab1f2db24 [入库]初次入库各种工具
- DBManager DB创建管理器
- FormatTimeTool
- ImageViewer工具
- InputArear工具
- OverlayPage工具
- 下拉刷新容器工具
- 视频查看器工具
2026-04-02 16:09:00 +08:00

120 lines
3.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 自动将任意精度的时间戳转换为毫秒级时间戳
* 支持:秒(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}`;
}