-
-
Notifications
You must be signed in to change notification settings - Fork 2.4k
/
index.ts
92 lines (82 loc) · 3.22 KB
/
index.ts
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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
import type { MaybeComputedRef } from '@vueuse/shared'
import { resolveUnref } from '@vueuse/shared'
import { computed } from 'vue-demi'
export type DateLike = Date | number | string | undefined
export interface UseDateFormatOptions {
/**
*
*/
customMeridiem?: (hours: number, minutes: number, isLowercase?: boolean, hasPeriod?: boolean) => string
}
const REGEX_PARSE = /* #__PURE__ */ /^(\d{4})[-/]?(\d{1,2})?[-/]?(\d{0,2})[Tt\s]*(\d{1,2})?:?(\d{1,2})?:?(\d{1,2})?[.:]?(\d+)?$/
const REGEX_FORMAT = /* #__PURE__ */ /\[([^\]]+)]|Y{1,4}|M{1,4}|D{1,2}|d{1,4}|H{1,2}|h{1,2}|a{1,2}|A{1,2}|m{1,2}|s{1,2}|Z{1,2}|SSS/g
const defaultMeridiem = (hours: number, minutes: number, isLowercase?: boolean, hasPeriod?: boolean) => {
let m = (hours < 12 ? 'AM' : 'PM')
if (hasPeriod)
m = m.split('').reduce((acc, curr) => acc += `${curr}.`, '')
return isLowercase ? m.toLowerCase() : m
}
export const formatDate = (date: Date, formatStr: string, options: UseDateFormatOptions) => {
const years = date.getFullYear()
const month = date.getMonth()
const days = date.getDate()
const hours = date.getHours()
const minutes = date.getMinutes()
const seconds = date.getSeconds()
const milliseconds = date.getMilliseconds()
const day = date.getDay()
const meridiem = options.customMeridiem ?? defaultMeridiem
const matches: Record<string, () => string | number> = {
YY: () => String(years).slice(-2),
YYYY: () => years,
M: () => month + 1,
MM: () => `${month + 1}`.padStart(2, '0'),
D: () => String(days),
DD: () => `${days}`.padStart(2, '0'),
H: () => String(hours),
HH: () => `${hours}`.padStart(2, '0'),
h: () => `${hours % 12 || 12}`.padStart(1, '0'),
hh: () => `${hours % 12 || 12}`.padStart(2, '0'),
m: () => String(minutes),
mm: () => `${minutes}`.padStart(2, '0'),
s: () => String(seconds),
ss: () => `${seconds}`.padStart(2, '0'),
SSS: () => `${milliseconds}`.padStart(3, '0'),
A: () => meridiem(hours, minutes),
AA: () => meridiem(hours, minutes, false, true),
a: () => meridiem(hours, minutes, true),
aa: () => meridiem(hours, minutes, true, true),
d: () => day,
}
return formatStr.replace(REGEX_FORMAT, (match, $1) => $1 || matches[match]())
}
export const normalizeDate = (date: DateLike) => {
if (date === null)
return new Date(NaN) // null is invalid
if (date === undefined)
return new Date()
if (date instanceof Date)
return new Date(date)
if (typeof date === 'string' && !/Z$/i.test(date)) {
const d = date.match(REGEX_PARSE) as any
if (d) {
const m = d[2] - 1 || 0
const ms = (d[7] || '0').substring(0, 3)
return new Date(d[1], m, d[3]
|| 1, d[4] || 0, d[5] || 0, d[6] || 0, ms)
}
}
return new Date(date)
}
/**
* Get the formatted date according to the string of tokens passed in.
*
* @see https://vueuse.org/useDateFormat
* @param date
* @param formatStr
* @param options
*/
export function useDateFormat(date: MaybeComputedRef<DateLike>, formatStr: MaybeComputedRef<string> = 'HH:mm:ss', options: UseDateFormatOptions = {}) {
return computed(() => formatDate(normalizeDate(resolveUnref(date)), resolveUnref(formatStr), options))
}
export type UseDateFormatReturn = ReturnType<typeof useDateFormat>