Skip to content

Commit

Permalink
weeks, change days in months, adapt function, init
Browse files Browse the repository at this point in the history
  • Loading branch information
KronosDev-Pro committed Aug 7, 2023
1 parent 9019ba7 commit 3a59d9a
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 77 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"scripts": {
"test": "TZ=Pacific/Auckland npm run test-tz && TZ=Europe/London npm run test-tz && TZ=America/Whitehorse npm run test-tz && npm run test-tz && jest",
"test-tz": "date && jest test/timezone.test --coverage=false",
"lint": "./node_modules/.bin/eslint src/* test/* build/*",
"lint": "eslint src/* test/* build/*",
"prettier": "prettier --write \"docs/**/*.md\"",
"babel": "cross-env BABEL_ENV=build babel src --out-dir esm --copy-files && node build/esm",
"build": "cross-env BABEL_ENV=build node build && npm run size",
Expand Down
144 changes: 75 additions & 69 deletions src/plugin/duration/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,20 @@ import {
REGEX_FORMAT
} from '../../constant'

const MILLISECONDS_A_YEAR = MILLISECONDS_A_DAY * 365
const MILLISECONDS_A_MONTH = MILLISECONDS_A_DAY * 30
const MILLISECONDS_A_MONTH = MILLISECONDS_A_WEEK * 4
const MILLISECONDS_A_YEAR = MILLISECONDS_A_MONTH * 12

const durationRegex = /^(-|\+)?P(?:([-+]?[0-9,.]*)Y)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)W)?(?:([-+]?[0-9,.]*)D)?(?:T(?:([-+]?[0-9,.]*)H)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)S)?)?$/

const unitToMS = {
years: MILLISECONDS_A_YEAR,
months: MILLISECONDS_A_MONTH,
weeks: MILLISECONDS_A_WEEK,
days: MILLISECONDS_A_DAY,
hours: MILLISECONDS_A_HOUR,
minutes: MILLISECONDS_A_MINUTE,
seconds: MILLISECONDS_A_SECOND,
milliseconds: 1,
weeks: MILLISECONDS_A_WEEK
milliseconds: 1
}

const isDuration = d => d instanceof Duration // eslint-disable-line no-use-before-define
Expand All @@ -34,7 +34,7 @@ const wrapper = (input, instance, unit) =>
const prettyUnit = unit => `${$u.p(unit)}s`
const isNegative = number => number < 0
const roundNumber = number =>
(isNegative(number) ? Math.ceil(number) : Math.floor(number))
isNegative(number) ? Math.ceil(number) : Math.floor(number)
const absolute = number => Math.abs(number)
const getNumberUnitFormat = (number, unit) => {
if (!number) {
Expand All @@ -61,6 +61,7 @@ class Duration {
constructor(input, unit, locale) {
this.$d = {}
this.$l = locale

if (input === undefined) {
this.$ms = 0
this.parseFromMilliseconds()
Expand All @@ -71,40 +72,51 @@ class Duration {
if (typeof input === 'number') {
this.$ms = input
this.parseFromMilliseconds()
return this
}
if (typeof input === 'object') {
Object.keys(input).forEach((k) => {
this.$d[prettyUnit(k)] = input[k]
const obj = {
years: 0,
months: 0,
weeks: 0,
days: 0,
hours: 0,
minutes: 0,
seconds: 0,
milliseconds: 0
}
Object.keys(input).forEach(k => {
obj[prettyUnit(k)] = input[k] || 0
})
this.calMilliseconds()
return this
this.calMilliseconds(obj)
}
if (typeof input === 'string') {
const d = input.match(durationRegex)
if (d) {
const properties = d.slice(2)
const numberD = properties.map(value => (value != null ? Number(value) : 0));
[
this.$d.years,
this.$d.months,
this.$d.weeks,
this.$d.days,
this.$d.hours,
this.$d.minutes,
this.$d.seconds
] = numberD
this.calMilliseconds()
return this
const numberD = properties.map(value =>
value != null ? Number(value) : 0
)
this.calMilliseconds({
years: numberD[0],
months: numberD[1],
weeks: numberD[2],
days: numberD[3],
hours: numberD[4],
minutes: numberD[5],
seconds: numberD[6]
})
}
}
return this
}

calMilliseconds() {
this.$ms = Object.keys(this.$d).reduce((total, unit) => (
total + ((this.$d[unit] || 0) * (unitToMS[unit]))
), 0)
calMilliseconds(obj) {
this.$ms = Object.keys(obj).reduce(
(total, unit) => total + ((obj[unit] || 0) * unitToMS[unit]),
0
)

this.parseFromMilliseconds()
}

parseFromMilliseconds() {
Expand All @@ -113,6 +125,8 @@ class Duration {
$ms %= MILLISECONDS_A_YEAR
this.$d.months = roundNumber($ms / MILLISECONDS_A_MONTH)
$ms %= MILLISECONDS_A_MONTH
this.$d.weeks = roundNumber($ms / MILLISECONDS_A_WEEK)
$ms %= MILLISECONDS_A_WEEK
this.$d.days = roundNumber($ms / MILLISECONDS_A_DAY)
$ms %= MILLISECONDS_A_DAY
this.$d.hours = roundNumber($ms / MILLISECONDS_A_HOUR)
Expand All @@ -122,15 +136,18 @@ class Duration {
this.$d.seconds = roundNumber($ms / MILLISECONDS_A_SECOND)
$ms %= MILLISECONDS_A_SECOND
this.$d.milliseconds = $ms

return this
}

toISOString() {
const Y = getNumberUnitFormat(this.$d.years, 'Y')
const M = getNumberUnitFormat(this.$d.months, 'M')
const M = getNumberUnitFormat(+this.$d.months || 0, 'M')

let days = +this.$d.days || 0
if (this.$d.weeks) {
days += this.$d.weeks * 7
const weeks = +this.$d.weeks || 0
if (weeks) {
days += weeks * 7
}

const D = getNumberUnitFormat(days, 'D')
Expand All @@ -156,56 +173,45 @@ class Duration {
const P = negativeMode ? '-' : ''

const result = `${P}P${Y.format}${M.format}${D.format}${T}${H.format}${m.format}${S.format}`

return result === 'P' || result === '-P' ? 'P0D' : result
}

toJSON() {
return this.toISOString()
}
toJSON() { return this.toISOString() }

format(formatStr) {
const str = formatStr || 'YYYY-MM-DDTHH:mm:ss'
const matches = {
Y: this.$d.years,
YY: $u.s(this.$d.years, 2, '0'),
YYYY: $u.s(this.$d.years, 4, '0'),
M: this.$d.months,
MM: $u.s(this.$d.months, 2, '0'),
D: this.$d.days,
DD: $u.s(this.$d.days, 2, '0'),
H: this.$d.hours,
HH: $u.s(this.$d.hours, 2, '0'),
m: this.$d.minutes,
mm: $u.s(this.$d.minutes, 2, '0'),
s: this.$d.seconds,
ss: $u.s(this.$d.seconds, 2, '0'),
SSS: $u.s(this.$d.milliseconds, 3, '0')

let days = +this.$d.days || 0
const weeks = +this.$d.weeks || 0
if (weeks) {
days += weeks * 7
}
return str.replace(REGEX_FORMAT, (match, $1) => $1 || String(matches[match]))
}

as(unit) {
return this.$ms / (unitToMS[prettyUnit(unit)])
return str.replace(
REGEX_FORMAT,
(match, $1) => $1 || String({
Y: this.$d.years,
YY: $u.s(this.$d.years, 2, '0'),
YYYY: $u.s(this.$d.years, 4, '0'),
M: this.$d.months,
MM: $u.s(this.$d.months, 2, '0'),
D: days,
DD: $u.s(days, 2, '0'),
H: this.$d.hours,
HH: $u.s(this.$d.hours, 2, '0'),
m: this.$d.minutes,
mm: $u.s(this.$d.minutes, 2, '0'),
s: this.$d.seconds,
ss: $u.s(this.$d.seconds, 2, '0'),
SSS: $u.s(this.$d.milliseconds, 3, '0')
}[match])
)
}

get(unit) {
const pUnit = prettyUnit(unit)
let base = roundNumber(this.$ms / unitToMS[pUnit])

if (pUnit === 'milliseconds') {
base %= 1000
} else if (pUnit === 'seconds' || pUnit === 'minutes') {
base %= 60
} else if (pUnit === 'hours') {
base %= 24
} else if (pUnit === 'days') {
base %= 7
} else if (pUnit === 'months') {
base %= 12
}
as(unit) { return (this.$ms / unitToMS[prettyUnit(unit)]) || 0 }

return base === 0 ? 0 : base // a === 0 will be true on both 0 and -0
}
get(unit) { return this.$d[prettyUnit(unit)] || 0 }

add(input, unit, isSubtract) {
let another
Expand All @@ -217,7 +223,7 @@ class Duration {
another = wrapper(input, this).$ms
}

return wrapper(this.$ms + (another * (isSubtract ? -1 : 1)), this)
return wrapper(this.$ms + another * (isSubtract ? -1 : 1), this)
}

subtract(input, unit) {
Expand Down
15 changes: 8 additions & 7 deletions test/plugin/duration.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ describe('Creating', () => {
weeks: 5,
months: 6,
years: 7
}).toISOString()).toBe('P7Y6M39DT3H2M1.1S')
}).toISOString()).toBe('P7Y7M11DT3H2M1.1S') // P7Y7M11DT3H2M1.1S
})
it('object with millisecond', () => {
expect(dayjs.duration({
Expand All @@ -77,16 +77,16 @@ describe('Parse ISO string', () => {
expect(dayjs.duration('P7Y6M4DT3H2M1S').toISOString()).toBe('P7Y6M4DT3H2M1S')
})
it('Part ISO string', () => {
expect(dayjs.duration('PT2777H46M40S').toISOString()).toBe('PT2777H46M40S')
expect(dayjs.duration('PT2777H46M40S').toISOString()).toBe('P4M3DT17H46M40S')
})
it('Formatting missing components', () => {
expect(dayjs.duration('PT1H').format('YYYY-MM-DDTHH:mm:ss')).toBe('0000-00-00T01:00:00')
})
it('ISO string with week', () => {
const d = dayjs.duration('P2M3W4D')
expect(d.toISOString()).toBe('P2M25D')
expect(d.asDays()).toBe(85) // moment 85, count 2M as 61 days
expect(d.asWeeks()).toBe(12.142857142857142) // moment 12.285714285714286
expect(d.asDays()).toBe(81) // moment 85, count 2M as 56 days
expect(d.asWeeks()).toBe(11.571428571428571) // moment 12.285714285714286
})
it('Invalid ISO string', () => {
expect(dayjs.duration('Invalid').toISOString()).toBe('P0D')
Expand Down Expand Up @@ -340,13 +340,14 @@ describe('Weeks', () => {
})

describe('Month', () => {
expect(dayjs.duration(10000000000).months()).toBe(3)
expect(dayjs.duration(10000000000).months()).toBe(4)
expect(dayjs.duration(7257600000).asMonths()).toBe(3)
expect(dayjs.duration({ months: 3 }).asMonths()).toBe(3)
})

describe('Years', () => {
expect(dayjs.duration(100000000000).years()).toBe(3)
expect(dayjs.duration(100000000000).asYears().toFixed(2)).toBe('3.17')
expect(dayjs.duration(100000000000).asYears().toFixed(2)).toBe('3.44')
})

describe('Add', () => {
Expand Down Expand Up @@ -383,7 +384,7 @@ describe('prettyUnit', () => {
expect(dayjs.duration({
M: 12,
m: 12
}).toISOString()).toBe('P12MT12M')
}).toISOString()).toBe('P1YT12M')
})

describe('Format', () => {
Expand Down

0 comments on commit 3a59d9a

Please sign in to comment.