forked from mengyxu/noob-components
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
123 lines
3.5 KiB
123 lines
3.5 KiB
import dayjs, { type Dayjs } from "dayjs"; |
|
import customParseFormat from "dayjs/plugin/customParseFormat"; |
|
import timezone from "dayjs/plugin/timezone"; |
|
import utc from "dayjs/plugin/utc"; |
|
import { match, P } from "ts-pattern"; |
|
import { computed, toValue, type MaybeRefOrGetter } from "vue"; |
|
|
|
dayjs.extend(customParseFormat); |
|
dayjs.extend(utc); |
|
dayjs.extend(timezone); |
|
|
|
export type TimestampDisplayType = "iso8601" | "unix" | "unixMillis"; |
|
|
|
export interface TimestampDisplayConfig { |
|
valueFormat?: string; |
|
valueTz?: string; |
|
displayFormat?: string; |
|
locale?: string; |
|
type?: TimestampDisplayType; |
|
} |
|
|
|
export interface TimestampDisplayInput extends TimestampDisplayConfig { |
|
value: string | number; |
|
} |
|
|
|
export type TimestampSimpleConfig = undefined | boolean | string | TimestampDisplayConfig; |
|
|
|
export const DEFAULT_TIMESTAMP_DISPLAY_FORMAT = "YYYY-MM-DD HH:mm:ss"; |
|
|
|
function withDefaultDisplayFormat( |
|
config: TimestampDisplayConfig, |
|
defaultDisplayFormat?: string |
|
): TimestampDisplayConfig { |
|
if (!defaultDisplayFormat || config.displayFormat) { |
|
return config; |
|
} |
|
|
|
return { |
|
...config, |
|
displayFormat: defaultDisplayFormat, |
|
}; |
|
} |
|
|
|
export function normalizeTimestampValue( |
|
timestamp: TimestampSimpleConfig, |
|
defaultDisplayFormat?: string |
|
): TimestampDisplayConfig | null { |
|
return match(timestamp) |
|
.with(P.nullish, () => null) |
|
.with(true, () => withDefaultDisplayFormat({ type: "unixMillis" }, defaultDisplayFormat)) |
|
.with(P.union("iso8601", "unix", "unixMillis"), (type) => withDefaultDisplayFormat({ type }, defaultDisplayFormat)) |
|
.with(P.string, (valueFormat) => withDefaultDisplayFormat({ valueFormat }, defaultDisplayFormat)) |
|
.otherwise((config) => withDefaultDisplayFormat({ ...config }, defaultDisplayFormat)); |
|
} |
|
|
|
export function parseTimestampValue(value: string | number, config: TimestampDisplayConfig): Dayjs { |
|
const numericValue = match(value) |
|
.with(P.string, parseFloat) |
|
.otherwise((n) => n); |
|
|
|
if (!isNaN(numericValue)) { |
|
if (config.type == "unix") return dayjs.unix(numericValue); |
|
if (config.type == "unixMillis") return dayjs(numericValue); |
|
} |
|
|
|
if (config.valueFormat && config.valueTz) { |
|
return dayjs.tz(value, config.valueFormat, config.valueTz); |
|
} |
|
|
|
if (config.valueTz) { |
|
return dayjs.tz(value, config.valueTz); |
|
} |
|
|
|
if (config.valueFormat) { |
|
return dayjs(value, config.valueFormat); |
|
} |
|
|
|
return dayjs(value); |
|
} |
|
|
|
export function formatTimestampDisplay(value: string | number, config: TimestampDisplayConfig): string { |
|
let parsed = parseTimestampValue(value, config); |
|
|
|
if (!parsed.isValid()) { |
|
return String(value); |
|
} |
|
|
|
if (config.locale) { |
|
parsed = parsed.locale(config.locale); |
|
} |
|
|
|
return config.displayFormat ? parsed.format(config.displayFormat) : parsed.format(); |
|
} |
|
|
|
export function formatTimestampFromValue( |
|
value: string | number, |
|
timestamp: TimestampSimpleConfig, |
|
defaultDisplayFormat = DEFAULT_TIMESTAMP_DISPLAY_FORMAT |
|
): string { |
|
const config = normalizeTimestampValue(timestamp, defaultDisplayFormat); |
|
if (!config) { |
|
return String(value); |
|
} |
|
|
|
return formatTimestampDisplay(value, config); |
|
} |
|
|
|
export function useTimestampDisplay(input: MaybeRefOrGetter<TimestampDisplayInput>) { |
|
const parsed = computed(() => { |
|
const resolved = toValue(input); |
|
return parseTimestampValue(resolved.value, resolved); |
|
}); |
|
|
|
const display = computed(() => { |
|
const resolved = toValue(input); |
|
return formatTimestampDisplay(resolved.value, resolved); |
|
}); |
|
|
|
return { |
|
parsed, |
|
display, |
|
}; |
|
}
|
|
|