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.
124 lines
3.5 KiB
124 lines
3.5 KiB
|
3 months ago
|
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,
|
||
|
|
};
|
||
|
|
}
|