Skip to content

Commit

Permalink
feat(date): 新增 intervalToRestrictiveDuration
Browse files Browse the repository at this point in the history
  • Loading branch information
fjc0k committed Jul 9, 2020
1 parent 4db1e5c commit cfdcc45
Show file tree
Hide file tree
Showing 4 changed files with 270 additions and 0 deletions.
97 changes: 97 additions & 0 deletions src/date/__snapshots__/intervalToRestrictiveDuration.test.ts.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`intervalToRestrictiveDuration target 为 day 时表现正常 1`] = `
Object {
"days": 367,
"hours": 0,
"milliseconds": 200,
"minutes": 0,
"months": 0,
"seconds": 0,
"years": 0,
}
`;

exports[`intervalToRestrictiveDuration target 为 hour 时表现正常 1`] = `
Object {
"days": 0,
"hours": 8808,
"milliseconds": 200,
"minutes": 0,
"months": 0,
"seconds": 0,
"years": 0,
}
`;

exports[`intervalToRestrictiveDuration target 为 millisecond 时表现正常 1`] = `
Object {
"days": 0,
"hours": 0,
"milliseconds": 31708800200,
"minutes": 0,
"months": 0,
"seconds": 0,
"years": 0,
}
`;

exports[`intervalToRestrictiveDuration target 为 minute 时表现正常 1`] = `
Object {
"days": 0,
"hours": 0,
"milliseconds": 200,
"minutes": 528480,
"months": 0,
"seconds": 0,
"years": 0,
}
`;

exports[`intervalToRestrictiveDuration target 为 month 时表现正常 1`] = `
Object {
"days": 2,
"hours": 0,
"milliseconds": 200,
"minutes": 0,
"months": 12,
"seconds": 0,
"years": 0,
}
`;

exports[`intervalToRestrictiveDuration target 为 second 时表现正常 1`] = `
Object {
"days": 0,
"hours": 0,
"milliseconds": 200,
"minutes": 0,
"months": 0,
"seconds": 31708800,
"years": 0,
}
`;

exports[`intervalToRestrictiveDuration target 为 year 时表现正常 1`] = `
Object {
"days": 2,
"hours": 0,
"milliseconds": 200,
"minutes": 0,
"months": 0,
"seconds": 0,
"years": 1,
}
`;

exports[`intervalToRestrictiveDuration 未设置 target 时表现正常 1`] = `
Object {
"days": 2,
"hours": 0,
"milliseconds": 200,
"minutes": 0,
"months": 0,
"seconds": 0,
"years": 1,
}
`;
1 change: 1 addition & 0 deletions src/date/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -290,5 +290,6 @@ export {
// @index(['./**/*.ts', '!./**/*.test.*'], f => `export * from '${f.path}'`)
export * from './anyToDate'
export * from './formatDate'
export * from './intervalToRestrictiveDuration'
export * from './numeralDayToChineseDay'
// @endindex
45 changes: 45 additions & 0 deletions src/date/intervalToRestrictiveDuration.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { addDays, addMilliseconds, addYears } from 'date-fns/esm'
import { intervalToRestrictiveDuration } from './intervalToRestrictiveDuration'

describe('intervalToRestrictiveDuration', () => {
const start = new Date(2020, 5 - 1, 21, 0, 0, 0, 0)
const end = addYears(addMilliseconds(addDays(start, 2), 200), 1)

test('未设置 target 时表现正常', () => {
expect(intervalToRestrictiveDuration(start, end)).toMatchSnapshot()
})

test('target 为 year 时表现正常', () => {
expect(intervalToRestrictiveDuration(start, end, 'year')).toMatchSnapshot()
})

test('target 为 month 时表现正常', () => {
expect(intervalToRestrictiveDuration(start, end, 'month')).toMatchSnapshot()
})

test('target 为 day 时表现正常', () => {
expect(intervalToRestrictiveDuration(start, end, 'day')).toMatchSnapshot()
})

test('target 为 hour 时表现正常', () => {
expect(intervalToRestrictiveDuration(start, end, 'hour')).toMatchSnapshot()
})

test('target 为 minute 时表现正常', () => {
expect(
intervalToRestrictiveDuration(start, end, 'minute'),
).toMatchSnapshot()
})

test('target 为 second 时表现正常', () => {
expect(
intervalToRestrictiveDuration(start, end, 'second'),
).toMatchSnapshot()
})

test('target 为 millisecond 时表现正常', () => {
expect(
intervalToRestrictiveDuration(start, end, 'millisecond'),
).toMatchSnapshot()
})
})
127 changes: 127 additions & 0 deletions src/date/intervalToRestrictiveDuration.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
import { anyToDate } from './anyToDate'
import {
compareAsc,
differenceInDays,
differenceInHours,
differenceInMilliseconds,
differenceInMinutes,
differenceInMonths,
differenceInSeconds,
differenceInYears,
isValid,
sub,
} from 'date-fns/esm'

export type IntervalToRestrictiveDurationTarget =
| 'year'
| 'month'
| 'day'
| 'hour'
| 'minute'
| 'second'
| 'millisecond'

export interface IntervalToRestrictiveDurationResult {
years: number
months: number
days: number
hours: number
minutes: number
seconds: number
milliseconds: number
}

// ref: https://github.com/date-fns/date-fns/blob/master/src/intervalToDuration/index.js
export function intervalToRestrictiveDuration(
start: string | number | Date,
end: string | number | Date,
target: IntervalToRestrictiveDurationTarget = 'year',
): IntervalToRestrictiveDurationResult {
const dateLeft = anyToDate(start)
const dateRight = anyToDate(end)

if (!isValid(dateLeft)) {
throw new RangeError('Start Date is invalid')
}
if (!isValid(dateRight)) {
throw new RangeError('End Date is invalid')
}

const duration: IntervalToRestrictiveDurationResult = {
years: 0,
months: 0,
days: 0,
hours: 0,
minutes: 0,
seconds: 0,
milliseconds: 0,
}

let remaining: Date = dateLeft

const sign = compareAsc(dateLeft, dateRight)

if (target === 'year') {
duration.years = Math.abs(differenceInYears(remaining, dateRight))
}

if (target === 'year' || target === 'month') {
remaining = sub(remaining, { years: sign * duration.years })
duration.months = Math.abs(differenceInMonths(remaining, dateRight))
}

if (target === 'year' || target === 'month' || target === 'day') {
remaining = sub(remaining, { months: sign * duration.months })
duration.days = Math.abs(differenceInDays(remaining, dateRight))
}

if (
target === 'year' ||
target === 'month' ||
target === 'day' ||
target === 'hour'
) {
remaining = sub(remaining, { days: sign * duration.days })
duration.hours = Math.abs(differenceInHours(remaining, dateRight))
}

if (
target === 'year' ||
target === 'month' ||
target === 'day' ||
target === 'hour' ||
target === 'minute'
) {
remaining = sub(remaining, { hours: sign * duration.hours })
duration.minutes = Math.abs(differenceInMinutes(remaining, dateRight))
}

if (
target === 'year' ||
target === 'month' ||
target === 'day' ||
target === 'hour' ||
target === 'minute' ||
target === 'second'
) {
remaining = sub(remaining, { minutes: sign * duration.minutes })
duration.seconds = Math.abs(differenceInSeconds(remaining, dateRight))
}

if (
target === 'year' ||
target === 'month' ||
target === 'day' ||
target === 'hour' ||
target === 'minute' ||
target === 'second' ||
target === 'millisecond'
) {
remaining = sub(remaining, { seconds: sign * duration.seconds })
duration.milliseconds = Math.abs(
differenceInMilliseconds(remaining, dateRight),
)
}

return duration
}

0 comments on commit cfdcc45

Please sign in to comment.