yeg
2026-09-28 2c96ead3fcfe5df3ab1c46ec13ec4f681fd16d82
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
/**
 * 业务时间解析:只接受毫秒时间戳或 ISO-8601 文本,缺失或非法时间不伪装为当前时间。
 *
 * <p>同时接受两种形态,是因为后端目前并不统一:手写 Map 的时间字段是毫秒数,
 * 而 Instant 类型的 VO 属性走 ISO 文本(见 KNOWN-GAPS「时间字段两种形态」)。
 */
export function businessTime(value: unknown): number | null {
  if (typeof value === 'number') {
    return Number.isFinite(value) && Number.isFinite(new Date(value).getTime()) ? value : null
  }
  if (typeof value === 'string' && value.trim()) {
    const parsed = new Date(value.trim()).getTime()
    return Number.isFinite(parsed) ? parsed : null
  }
  return null
}
 
/** 将业务时间按浏览器本地时区展示,保留毫秒精度。 */
export function formatBusinessTime(value: unknown): string {
  const time = businessTime(value)
  if (time === null) return '-'
  const date = new Date(time)
  const pad = (part: number, length = 2) => String(part).padStart(length, '0')
  return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}.${pad(date.getMilliseconds(), 3)}`
}
 
/** 只展示到分钟的紧凑时间,用于设备列表与候选列表。 */
export function formatBusinessMinute(value: unknown): string {
  const date = businessDate(value)
  if (date === null) return '-'
  return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}`
}
 
/** 只展示月日与时分秒,用于实时监控卡片。 */
export function formatBusinessClock(value: unknown): string {
  const date = businessDate(value)
  if (date === null) return '-'
  return `${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`
}
 
function businessDate(value: unknown): Date | null {
  const time = businessTime(value)
  return time === null ? null : new Date(time)
}
 
function pad(part: number): string {
  return String(part).padStart(2, '0')
}