86 lines
2.5 KiB
TypeScript
86 lines
2.5 KiB
TypeScript
const ISO_DATE_TIME_PATTERN =
|
|
/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})?$/
|
|
|
|
export function isIsoDateTimeString(value: unknown): value is string {
|
|
return typeof value === 'string' && ISO_DATE_TIME_PATTERN.test(value.trim())
|
|
}
|
|
|
|
export function formatDateTime(value: string | null | undefined, fallback = '-') {
|
|
const normalized = String(value || '').trim()
|
|
|
|
if (!normalized) {
|
|
return fallback
|
|
}
|
|
|
|
const date = new Date(normalized)
|
|
|
|
if (Number.isNaN(date.getTime())) {
|
|
return normalized.replace('T', ' ').replace('Z', '')
|
|
}
|
|
|
|
const year = date.getFullYear()
|
|
const month = String(date.getMonth() + 1).padStart(2, '0')
|
|
const day = String(date.getDate()).padStart(2, '0')
|
|
const hours = String(date.getHours()).padStart(2, '0')
|
|
const minutes = String(date.getMinutes()).padStart(2, '0')
|
|
const seconds = String(date.getSeconds()).padStart(2, '0')
|
|
|
|
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`
|
|
}
|
|
|
|
export function normalizeDateTimeValue(value: unknown): unknown {
|
|
if (Array.isArray(value)) {
|
|
return value.map((item) => normalizeDateTimeValue(item))
|
|
}
|
|
|
|
if (value && typeof value === 'object') {
|
|
return Object.fromEntries(
|
|
Object.entries(value).map(([key, currentValue]) => [
|
|
key,
|
|
normalizeDateTimeValue(currentValue),
|
|
]),
|
|
)
|
|
}
|
|
|
|
if (isIsoDateTimeString(value)) {
|
|
return formatDateTime(value, '')
|
|
}
|
|
|
|
return value
|
|
}
|
|
|
|
export function stringifyDisplayJson(value: unknown, space = 2) {
|
|
return JSON.stringify(normalizeDateTimeValue(value), null, space)
|
|
}
|
|
|
|
/** 抢单大厅发布耗时格式化(仅内部打手可见):发布 <1m / 发布 5m / 发布 1h 20m / 发布 1d 4h */
|
|
export function formatPublishedElapsedTime(
|
|
value: string | null | undefined,
|
|
nowMs = Date.now(),
|
|
): string {
|
|
const normalized = String(value || '').trim()
|
|
if (!normalized) return ''
|
|
|
|
const date = new Date(normalized)
|
|
const time = date.getTime()
|
|
if (Number.isNaN(time)) return ''
|
|
|
|
const diffSeconds = Math.max(0, Math.floor((nowMs - time) / 1000))
|
|
|
|
if (diffSeconds < 60) {
|
|
return '发布 <1m'
|
|
}
|
|
const diffMinutes = Math.floor(diffSeconds / 60)
|
|
if (diffMinutes < 60) {
|
|
return `发布 ${diffMinutes}m`
|
|
}
|
|
const diffHours = Math.floor(diffMinutes / 60)
|
|
const remMinutes = diffMinutes % 60
|
|
if (diffHours < 24) {
|
|
return remMinutes > 0 ? `发布 ${diffHours}h ${remMinutes}m` : `发布 ${diffHours}h`
|
|
}
|
|
const diffDays = Math.floor(diffHours / 24)
|
|
const remHours = diffHours % 24
|
|
return remHours > 0 ? `发布 ${diffDays}d ${remHours}h` : `发布 ${diffDays}d`
|
|
}
|