|
|
|
|
|
/** 业务时间统一按北京时间(Asia/Shanghai,无夏令时)处理。 */
|
|
|
|
|
|
|
|
|
|
|
|
const SHANGHAI = 'Asia/Shanghai'
|
|
|
|
|
|
|
|
|
|
|
|
function pad(n: number): string {
|
|
|
|
|
|
return String(n).padStart(2, '0')
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* API ISO / 任意可解析时间 → 日期时间选择器模型(北京时间 `YYYY-MM-DD HH:mm:ss`)。
|
|
|
|
|
|
*/
|
|
|
|
|
|
export function toShanghaiPickerValue(iso: string | null | undefined): string | null {
|
|
|
|
|
|
if (!iso) return null
|
|
|
|
|
|
const d = new Date(iso)
|
|
|
|
|
|
if (Number.isNaN(d.getTime())) return null
|
|
|
|
|
|
|
|
|
|
|
|
const parts = new Intl.DateTimeFormat('en-GB', {
|
|
|
|
|
|
timeZone: SHANGHAI,
|
|
|
|
|
|
year: 'numeric',
|
|
|
|
|
|
month: '2-digit',
|
|
|
|
|
|
day: '2-digit',
|
|
|
|
|
|
hour: '2-digit',
|
|
|
|
|
|
minute: '2-digit',
|
|
|
|
|
|
second: '2-digit',
|
|
|
|
|
|
hourCycle: 'h23',
|
|
|
|
|
|
}).formatToParts(d)
|
|
|
|
|
|
|
|
|
|
|
|
const get = (type: Intl.DateTimeFormatPartTypes): string =>
|
|
|
|
|
|
parts.find((p) => p.type === type)?.value ?? '00'
|
|
|
|
|
|
|
|
|
|
|
|
const hour = get('hour') === '24' ? '00' : get('hour')
|
|
|
|
|
|
return `${get('year')}-${get('month')}-${get('day')} ${hour}:${get('minute')}:${get('second')}`
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 选择器值(按北京时间理解)→ API ISO8601(带偏移,避免被当成 UTC)。
|
|
|
|
|
|
*/
|
|
|
|
|
|
export function fromShanghaiPickerValue(s: string | null | undefined): string | null {
|
|
|
|
|
|
const t = (s ?? '').trim()
|
|
|
|
|
|
if (!t) return null
|
|
|
|
|
|
const m = t.match(/^(\d{4})-(\d{2})-(\d{2})[ T](\d{2}):(\d{2})(?::(\d{2}))?/)
|
|
|
|
|
|
if (!m) return null
|
|
|
|
|
|
const [, y, mo, d, h, mi, sec = '00'] = m
|
|
|
|
|
|
return `${y}-${mo}-${d}T${h}:${mi}:${sec}+08:00`
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** 列表/详情展示用北京时间。 */
|
|
|
|
|
|
export function formatShanghaiDateTime(iso: string | null | undefined, empty = '—'): string {
|
|
|
|
|
|
const v = toShanghaiPickerValue(iso)
|
|
|
|
|
|
if (!v) return empty
|
|
|
|
|
|
return v.replace(/:\d{2}$/, '') // YYYY-MM-DD HH:mm
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export function formatShanghaiDateTimeFull(iso: string | null | undefined, empty = '—'): string {
|
|
|
|
|
|
return toShanghaiPickerValue(iso) ?? empty
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** 调试/校验用 */
|
|
|
|
|
|
export function shanghaiOffsetLabel(): string {
|
|
|
|
|
|
return `${SHANGHAI} (UTC+8)`
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export { pad }
|