Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added new duration plugin #567

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion src/constant.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
export const MONTHS_A_YEAR = 12
export const DAYS_A_WEEK = 7

export const SECONDS_A_MINUTE = 60
export const SECONDS_A_HOUR = SECONDS_A_MINUTE * 60
export const SECONDS_A_DAY = SECONDS_A_HOUR * 24
export const SECONDS_A_WEEK = SECONDS_A_DAY * 7
export const SECONDS_A_WEEK = SECONDS_A_DAY * DAYS_A_WEEK

export const MILLISECONDS_A_SECOND = 1e3
export const MILLISECONDS_A_MINUTE = SECONDS_A_MINUTE * MILLISECONDS_A_SECOND
Expand Down
76 changes: 76 additions & 0 deletions src/plugin/duration/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import * as C from '../../constant'

const dayStart = dt => dt.startOf(C.D)

function dayDiff(earlier, later) {
return Math.floor(dayStart(later).diff(dayStart(earlier)) / C.MILLISECONDS_A_DAY)
}

function highOrderDiffs(cursor, later, isPast) {
const differs = [
[C.Y, (a, b) => b.year() - a.year()],
[C.M, (a, b) => (b.month() - a.month()) + ((b.year() - a.year()) * C.MONTHS_A_YEAR)],
[C.D, dayDiff]
]
const results = {}
let cdelta
for (const [unit, differ] of differs) {
let delta = differ(cursor, later)
cdelta = cursor.add(delta, unit)
if (cdelta > later) {
delta -= 1
cursor = cursor.add(delta, unit)
} else {
cursor = cdelta
}
results[unit] = isPast ? -1 * delta : delta
}
return [cursor, results]
}

function lowerOrderDiffs(rms, isPast) {
const differs = [
[C.H, ms => Math.floor(ms / C.MILLISECONDS_A_HOUR),
(ms, h) => ms - (h * C.MILLISECONDS_A_HOUR)
],
[C.MIN, ms => Math.floor(ms / C.MILLISECONDS_A_MINUTE),
(ms, m) => ms - (m * C.MILLISECONDS_A_MINUTE)
],
[C.S, ms => Math.floor(ms / C.MILLISECONDS_A_SECOND),
(ms, s) => ms - (s * C.MILLISECONDS_A_SECOND)
],
[C.MS, ms => Math.floor(ms)]
]
const results = {}
let delta = 0
for (const [unit, differ, rimender] of differs) {
if (rms > 0) {
delta = differ(rms)
if (delta >= 0 && unit !== C.MS) {
rms = rimender(rms, delta)
} else {
rms = 0
}
}
results[unit] = isPast ? -1 * delta : delta
delta = 0
}
return results
}

export default (o, c, d) => {
const proto = c.prototype
proto.duration = function (input) {
const instance = d(this)
const that = d(input)
const isPast = instance > that
const earlier = isPast ? that : instance
const later = isPast ? instance : that

const [cursor, results] = highOrderDiffs(earlier, later, isPast)

const remainingMillis = later - cursor

return Object.assign(results, lowerOrderDiffs(remainingMillis, isPast))
}
}
81 changes: 81 additions & 0 deletions test/plugin/duration.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import MockDate from 'mockdate'
import dayjs from '../../src'
import duration from '../../src/plugin/duration'

dayjs.extend(duration)

beforeEach(() => {
MockDate.set(new Date())
})

afterEach(() => {
MockDate.reset()
})

it('duration between dates', () => {
const dayjsA = dayjs('2019-03-31')
const dayjsB = dayjs('2019-04-1')
const dayjsACopy = dayjs(dayjsA)
const dayjsBCopy = dayjs(dayjsB)
const result = dayjsA.duration(dayjsB)
expect(result.year).toBe(0)
expect(result.month).toBe(0)
expect(result.day).toBe(1)
expect(result.hour).toBe(0)
expect(result.minute).toBe(0)
expect(result.second).toBe(0)
expect(result.millisecond).toBe(0)
expect(+dayjsA).toEqual(+dayjsACopy, 'duration should not change moment')
expect(+dayjsB).toEqual(+dayjsBCopy, 'duration should not change moment')
})

it('duration between dates, future date', () => {
const dayjsA = dayjs(new Date(2018, 3, 3, 4, 45, 45, 400))
const dayjsB = dayjs(new Date(2019, 4, 15, 11, 20, 34, 700))
const dayjsACopy = dayjs(dayjsA)
const dayjsBCopy = dayjs(dayjsB)
const result = dayjsA.duration(dayjsB)
expect(result.year).toBe(1)
expect(result.month).toBe(1)
expect(result.day).toBe(12)
expect(result.hour).toBe(6)
expect(result.minute).toBe(34)
expect(result.second).toBe(49)
expect(result.millisecond).toBe(300)
expect(+dayjsA).toEqual(+dayjsACopy, 'duration should not change moment')
expect(+dayjsB).toEqual(+dayjsBCopy, 'duration should not change moment')
})

it('duration between dates, past date', () => {
const dayjsA = dayjs(new Date(2019, 4, 15, 11, 20, 34, 700))
const dayjsB = dayjs(new Date(2018, 3, 3, 4, 45, 45, 400))
const dayjsACopy = dayjs(dayjsA)
const dayjsBCopy = dayjs(dayjsB)
const result = dayjsA.duration(dayjsB)
expect(result.year).toBe(-1)
expect(result.month).toBe(-1)
expect(result.day).toBe(-12)
expect(result.hour).toBe(-6)
expect(result.minute).toBe(-34)
expect(result.second).toBe(-49)
expect(result.millisecond).toBe(-300)
expect(+dayjsA).toEqual(+dayjsACopy, 'duration should not change moment')
expect(+dayjsB).toEqual(+dayjsBCopy, 'duration should not change moment')
})

it('duration between same dates', () => {
const dayjsA = dayjs(new Date(2019, 2, 27, 23, 59, 59, 800))
const dayjsB = dayjs(new Date(2019, 2, 27, 23, 59, 59, 800))
const dayjsACopy = dayjs(dayjsA)
const dayjsBCopy = dayjs(dayjsB)
const result = dayjsA.duration(dayjsB)
expect(result.year).toBe(0)
expect(result.month).toBe(0)
expect(result.day).toBe(0)
expect(result.hour).toBe(0)
expect(result.minute).toBe(0)
expect(result.second).toBe(0)
expect(result.millisecond).toBe(0)
expect(+dayjsA).toEqual(+dayjsACopy, 'duration should not change moment')
expect(+dayjsB).toEqual(+dayjsBCopy, 'duration should not change moment')
})
10 changes: 10 additions & 0 deletions types/plugin/duration.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { PluginFunc } from 'dayjs'

declare const plugin: PluginFunc
export = plugin

declare module 'dayjs' {
interface Dayjs {
duration(input: ConfigType): any
}
}