| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111 |
- /**
- * 时间格式化 —— **全项目唯一实现**
- *
- * 依据《数据访问层设计.md》§五硬约束 6:存量有 4 份重复的日期格式化,
- * v2 只允许这一处。组件里禁止自建 `toLocaleDateString` 之类的逻辑。
- *
- * 🔴 云函数返回的时间可能是 `{ __type: 'Date', iso }` 对象(Parse 序列化形式),
- * `String()` 会得到 `[object Object]` —— 必须统一经 `tsOf` 归一。
- */
- /** 归一任意时间形态为毫秒时间戳;无法解析返回 NaN */
- export function tsOf(value: unknown): number {
- if (value == null) return NaN;
- if (typeof value === 'number') return value;
- if (value instanceof Date) return value.getTime();
- if (typeof value === 'string') {
- const t = Date.parse(value);
- return Number.isNaN(t) ? NaN : t;
- }
- if (typeof value === 'object') {
- const obj = value as Record<string, unknown>;
- // Parse 的 Date 形式:{ __type: 'Date', iso: '...' }
- if (typeof obj['iso'] === 'string') return Date.parse(obj['iso']);
- if (typeof obj['__type'] === 'string' && typeof obj['value'] === 'string') {
- return Date.parse(obj['value']);
- }
- }
- return NaN;
- }
- function pad(n: number): string {
- return n < 10 ? `0${n}` : String(n);
- }
- function dateOf(value: unknown): Date | null {
- const t = tsOf(value);
- return Number.isNaN(t) ? null : new Date(t);
- }
- /** `10:42` */
- export function fmtTime(value: unknown): string {
- const d = dateOf(value);
- if (!d) return '—';
- return `${pad(d.getHours())}:${pad(d.getMinutes())}`;
- }
- /** `2026-10-14` */
- export function fmtDate(value: unknown): string {
- const d = dateOf(value);
- if (!d) return '—';
- return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`;
- }
- /** `2026-10-14 10:42` */
- export function fmtDateTime(value: unknown): string {
- const d = dateOf(value);
- if (!d) return '—';
- return `${fmtDate(value)} ${fmtTime(value)}`;
- }
- /** `10 月 14 日,星期三` */
- export function fmtDayLabel(value: unknown): string {
- const d = dateOf(value);
- if (!d) return '—';
- const week = ['日', '一', '二', '三', '四', '五', '六'][d.getDay()];
- return `${d.getMonth() + 1} 月 ${d.getDate()} 日,星期${week}`;
- }
- /** 列表里用的相对时间:今天 → `10:42`;昨天 → `昨天 16:30`;更早 → `10-13` */
- export function fmtRelTime(value: unknown, now = new Date()): string {
- const d = dateOf(value);
- if (!d) return '—';
- const sameDay = (a: Date, b: Date) =>
- a.getFullYear() === b.getFullYear() &&
- a.getMonth() === b.getMonth() &&
- a.getDate() === b.getDate();
- if (sameDay(d, now)) return fmtTime(value);
- const yesterday = new Date(now);
- yesterday.setDate(now.getDate() - 1);
- if (sameDay(d, yesterday)) return `昨天 ${fmtTime(value)}`;
- if (d.getFullYear() === now.getFullYear()) {
- return `${pad(d.getMonth() + 1)}-${pad(d.getDate())}`;
- }
- return fmtDate(value);
- }
- /** 事件流的分组键(同一天归为一组) */
- export function dayKeyOf(value: unknown): string {
- const d = dateOf(value);
- if (!d) return '未知时间';
- const today = new Date();
- const yesterday = new Date(today);
- yesterday.setDate(today.getDate() - 1);
- const same = (a: Date, b: Date) =>
- a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();
- if (same(d, today)) return '今天';
- if (same(d, yesterday)) return '昨天';
- return fmtDate(value);
- }
- /** 相对时长(用于「已阻塞 436h」这类表达) */
- export function fmtDuration(hours?: number): string {
- if (hours == null || Number.isNaN(hours)) return '—';
- if (hours < 1) return `${Math.round(hours * 60)} 分钟`;
- if (hours < 48) return `${Math.round(hours)} 小时`;
- return `${Math.round(hours / 24)} 天`;
- }
|