-
Notifications
You must be signed in to change notification settings - Fork 52
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
2dc8ea5
commit 20e5e46
Showing
6 changed files
with
310 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1 @@ | ||
export * from './logger.js' | ||
export * from './packageManager.js' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
import { isDef, isString } from './helper.js' | ||
|
||
export interface DateInfo { | ||
type: 'date' | 'time' | 'full' | ||
value: Date | null | ||
} | ||
|
||
const TIME_REG = | ||
/(?:(\d{2,4})[/-](\d{1,2})[/-](\d{1,2}))?\s*(?:(\d{1,2}):(\d{1,2})(?::(\d{1,2})(?::(\d{3}))?)?)?/u | ||
|
||
/** | ||
* Get Date info from user input, return null when input is invalid | ||
* | ||
* 从用户输入中获取日期信息,输入无效时返回 null | ||
*/ | ||
export const parseDate = (date: unknown): DateInfo | null => { | ||
if (date instanceof Date) { | ||
if (date.valueOf() === null) return null | ||
|
||
const isDate = | ||
date.getHours() === 0 && | ||
date.getMinutes() === 0 && | ||
date.getSeconds() === 0 && | ||
date.getMilliseconds() === 0 | ||
|
||
return { | ||
type: isDate ? 'date' : 'full', | ||
value: date, | ||
} | ||
} | ||
|
||
if (isString(date)) { | ||
const result = new Date(date) | ||
|
||
if (result.valueOf()) { | ||
const isDate = | ||
result.getHours() === 0 && | ||
result.getMinutes() === 0 && | ||
result.getSeconds() === 0 && | ||
result.getMilliseconds() === 0 | ||
|
||
return { | ||
type: isDate ? 'date' : 'full', | ||
value: result, | ||
} | ||
} else { | ||
const match = TIME_REG.exec(date.trim()) | ||
|
||
if (match) { | ||
const [year, month, day, hour, minute, second] = match | ||
.slice(1) | ||
.map((item) => (isDef(item) ? parseInt(item) : item)) | ||
|
||
if (isDef(year) && isDef(month) && isDef(day)) { | ||
const isDate = !isDef(hour) && !isDef(minute) && !isDef(second) | ||
|
||
return { | ||
type: isDate ? 'date' : 'full', | ||
value: isDate | ||
? new Date( | ||
year && Number(year) < 100 ? year + 2000 : year, | ||
month - 1, | ||
day, | ||
) | ||
: new Date( | ||
year && Number(year) < 100 ? year + 2000 : year, | ||
month - 1, | ||
day, | ||
hour, | ||
minute, | ||
hour && minute && !second ? 0 : second, | ||
), | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
return null | ||
} | ||
|
||
/** | ||
* Date sorter from latest to oldest | ||
* | ||
* @description Invalid date will appear at last | ||
* | ||
* 最新到最旧的日期排序器 | ||
* | ||
* @description 无效日期将出现在最后 | ||
*/ | ||
export const dateSorter = ( | ||
valueA: Date | number | string | undefined, | ||
valueB: Date | number | string | undefined, | ||
): number => { | ||
const dateA = parseDate( | ||
typeof valueA === 'number' ? new Date(valueA) : valueA, | ||
)?.value | ||
const dateB = parseDate( | ||
typeof valueB === 'number' ? new Date(valueB) : valueB, | ||
)?.value | ||
|
||
if (!dateA) return dateB ? 1 : 0 | ||
if (!dateB) return -1 | ||
|
||
return dateB.getTime() - dateA.getTime() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
export * from './date.js' | ||
export * from './helper.js' | ||
export * from './url.js' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,189 @@ | ||
import { describe, expect, it } from 'vitest' | ||
import { dateSorter, parseDate } from '../../src/shared/date.js' | ||
|
||
const getCurrentDate = (date: Date): Date => | ||
new Date(date.getTime() + new Date().getTimezoneOffset() * 60 * 1000) | ||
|
||
describe('getDate()', () => { | ||
it('Should return null', () => { | ||
expect(parseDate(undefined)).toEqual(null) | ||
}) | ||
|
||
describe('Should parse day', () => { | ||
it('date string', () => { | ||
expect(parseDate('2020-04-04T00:00:00.000Z')).toEqual({ | ||
type: 'date', | ||
value: new Date('2020-04-04T00:00:00.000Z'), | ||
}) | ||
|
||
expect(parseDate('2020-04-04T12:00:00.000Z')).toEqual({ | ||
type: 'full', | ||
value: new Date('2020-04-04T12:00:00.000Z'), | ||
}) | ||
}) | ||
|
||
it('date', () => { | ||
expect(parseDate('1918-01-01')).toEqual({ | ||
value: getCurrentDate(new Date('1918-01-01')), | ||
type: 'date', | ||
}) | ||
}) | ||
|
||
it('simple date like string', () => { | ||
expect(parseDate('2018-1-1')).toEqual({ | ||
value: getCurrentDate(new Date('2018-01-01')), | ||
type: 'date', | ||
}) | ||
}) | ||
|
||
it('date like string with splash', () => { | ||
expect(parseDate('1918/01/01')).toEqual({ | ||
value: getCurrentDate(new Date('1918-01-01')), | ||
type: 'date', | ||
}) | ||
|
||
expect(parseDate('2018/1/1')).toEqual({ | ||
value: getCurrentDate(new Date('2018-01-01')), | ||
type: 'date', | ||
}) | ||
}) | ||
|
||
it('date string with spaces', () => { | ||
expect(parseDate(' 1918-01-01')).toEqual({ | ||
value: getCurrentDate(new Date('1918-01-01')), | ||
type: 'date', | ||
}) | ||
}) | ||
|
||
it('date like string with spaces', () => { | ||
expect(parseDate(' 2018-1-1 ')).toEqual({ | ||
value: getCurrentDate(new Date('2018-01-01')), | ||
type: 'date', | ||
}) | ||
}) | ||
|
||
it('date like string with splash and spaces', () => { | ||
expect(parseDate(' 2018/1/1 ')).toEqual({ | ||
value: getCurrentDate(new Date('2018-01-01')), | ||
type: 'date', | ||
}) | ||
}) | ||
|
||
it('date like string with spaces and short year', () => { | ||
expect(parseDate('18-01-01')).toEqual({ | ||
value: getCurrentDate(new Date('2018-01-01')), | ||
type: 'date', | ||
}) | ||
}) | ||
|
||
it('date like string with splash and spaces and short year', () => { | ||
expect(parseDate('18/01/01 ')).toEqual({ | ||
value: getCurrentDate(new Date('2018-01-01')), | ||
type: 'date', | ||
}) | ||
}) | ||
}) | ||
|
||
it('Should parse whole date', () => { | ||
expect(parseDate('2018/12/1 12:30')).toEqual({ | ||
value: new Date('2018-12-01 12:30'), | ||
type: 'full', | ||
}) | ||
|
||
expect(parseDate('18/12/01 12:30')).toEqual({ | ||
value: new Date('2018-12-01 12:30'), | ||
type: 'full', | ||
}) | ||
|
||
expect(parseDate(' 2018/12/01 12:30:00 ')).toEqual({ | ||
value: new Date('2018-12-01 12:30'), | ||
type: 'full', | ||
}) | ||
|
||
expect(parseDate(' 2018-12-01 12:30:00 ')).toEqual({ | ||
value: new Date('2018-12-01 12:30'), | ||
type: 'full', | ||
}) | ||
|
||
expect(parseDate(' 2018-12-1 12:30:00 ')).toEqual({ | ||
value: new Date('2018-12-01 12:30'), | ||
type: 'full', | ||
}) | ||
}) | ||
}) | ||
|
||
describe('dateSorter()', () => { | ||
it('should return 0 if both dates are the same', () => { | ||
const date = new Date('2022-01-01') | ||
|
||
expect(dateSorter(date, date)).toBe(0) | ||
|
||
expect( | ||
dateSorter( | ||
new Date('2020-04-04T00:00:00.000Z'), | ||
new Date('2020-04-04T00:00:00.000Z'), | ||
), | ||
).toBe(0) | ||
}) | ||
|
||
it('should return a positive number if dateA is older than dateB', () => { | ||
const dateA = new Date('2022-01-01') | ||
const dateB = new Date('2022-01-02') | ||
|
||
expect(dateSorter(dateA, dateB)).toBeGreaterThan(0) | ||
|
||
expect( | ||
dateSorter( | ||
new Date('2020-04-04T00:00:00.000Z'), | ||
new Date('2020-05-05T00:00:00.000Z'), | ||
), | ||
).toBeGreaterThan(0) | ||
}) | ||
|
||
it('should return a negative number if dateA is newer than dateB', () => { | ||
const dateA = new Date('2022-01-02') | ||
const dateB = new Date('2022-01-01') | ||
|
||
expect(dateSorter(dateA, dateB)).toBeLessThan(0) | ||
expect( | ||
dateSorter( | ||
new Date('2020-05-05T00:00:00.000Z'), | ||
new Date('2020-04-04T00:00:00.000Z'), | ||
), | ||
).toBeLessThan(0) | ||
}) | ||
|
||
it('should return 1 if dateA is undefined', () => { | ||
const dateB = new Date('2022-01-01') | ||
|
||
expect(dateSorter(undefined, dateB)).toBe(1) | ||
}) | ||
|
||
it('should return -1 if dateB is undefined', () => { | ||
const dateA = new Date('2022-01-01') | ||
|
||
expect(dateSorter(dateA, undefined)).toBe(-1) | ||
}) | ||
|
||
it('should return 0 if both dates are undefined', () => { | ||
expect(dateSorter(undefined, undefined)).toBe(0) | ||
}) | ||
|
||
it('should be a correct date sorter', () => { | ||
const dates = [ | ||
'2021-01-01', | ||
'2022-04-05 08:00:00', | ||
undefined, | ||
'04:38:45', | ||
'2022-03-08', | ||
] | ||
|
||
expect(dates.sort(dateSorter)).toEqual([ | ||
'2022-04-05 08:00:00', | ||
'2022-03-08', | ||
'2021-01-01', | ||
'04:38:45', | ||
undefined, | ||
]) | ||
}) | ||
}) |