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

Add new feature addBusinessDays #1154

Merged
merged 9 commits into from Jun 10, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Expand Up @@ -761,6 +761,9 @@ for the list of changes made since `v2.0.0-alpha.1`.
- [Add new function `differenceInBusinessDays`](https://github.com/date-fns/date-fns/pull/1194)
which calculates the difference in business days. Kudos to [@ThorrStevens](https://github.com/ThorrStevens)!

- [Add new function `addBusinessDays`](https://github.com/date-fns/date-fns/pull/1154),
similar to `addDays` but ignoring weekends. Thanks to [@ThorrStevens](https://github.com/ThorrStevens)!

## [1.30.1] - 2018-12-10

### Fixed
Expand Down
1 change: 1 addition & 0 deletions scripts/test/dst.sh
Expand Up @@ -11,3 +11,4 @@ export PATH="$(yarn bin):$PATH"
env TZ=America/Sao_Paulo babel-node ./test/dst/parseISO/basic.js
env TZ=Pacific/Apia babel-node ./test/dst/parseISO/samoa.js
env TZ=Asia/Damascus babel-node ./test/dst/eachDayOfInterval/basic.js
env TZ=America/Santiago babel-node ./test/dst/addBusinessDays/basic.js
4 changes: 4 additions & 0 deletions src/addBusinessDays/index.d.ts
@@ -0,0 +1,4 @@
// This file is generated automatically by `scripts/build/typings.js`. Please, don't change it.

import { addBusinessDays } from 'date-fns'
export default addBusinessDays
44 changes: 44 additions & 0 deletions src/addBusinessDays/index.js
@@ -0,0 +1,44 @@
import isWeekend from '../isWeekend/index.js'
import toDate from '../toDate/index.js'
import toInteger from '../_lib/toInteger/index.js'

/**
* @name addBusinessDays
* @category Day Helpers
* @summary Add the specified number of business days (mon - fri) to the given date.
*
* @description
* Add the specified number of business days (mon - fri) to the given date, ignoring weekends.
*
* @param {Date|Number} date - the date to be changed
* @param {Number} amount - the amount of business days to be added
* @returns {Date} the new date with the business days added
* @throws {TypeError} 2 arguments required
*
* @example
* // Add 10 business days to 1 September 2014:
* var result = addBusinessDays(new Date(2014, 8, 1), 10)
* //=> Mon Sep 15 2014 00:00:00 (skipped weekend days)
*/
export default function addBusinessDays(dirtyDate, dirtyAmount) {
if (arguments.length < 2) {
throw new TypeError(
'2 arguments required, but only ' + arguments.length + ' present'
)
}

var date = toDate(dirtyDate)
var amount = toInteger(dirtyAmount)

if (isNaN(amount)) return new Date(NaN)

var hours = date.getHours()
var numWeekDays = 0
while (numWeekDays < amount) {
date.setDate(date.getDate() + 1)
date.setHours(hours)
if (!isWeekend(date)) numWeekDays++
}

return date
}
38 changes: 38 additions & 0 deletions src/addBusinessDays/index.js.flow
@@ -0,0 +1,38 @@
// @flow
// This file is generated automatically by `scripts/build/typings.js`. Please, don't change it.

type Interval = {
start: Date | number,
end: Date | number
}

type Locale = {
formatDistance: Function,
formatRelative: Function,
localize: {
ordinalNumber: Function,
era: Function,
quarter: Function,
month: Function,
day: Function,
dayPeriod: Function
},
formatLong: Object,
date: Function,
time: Function,
dateTime: Function,
match: {
ordinalNumber: Function,
era: Function,
quarter: Function,
month: Function,
day: Function,
dayPeriod: Function
},
options?: {
weekStartsOn?: 0 | 1 | 2 | 3 | 4 | 5 | 6,
firstWeekContainsDate?: 1 | 2 | 3 | 4 | 5 | 6 | 7
}
}

declare module.exports: (date: Date | number, amount: number) => Date
49 changes: 49 additions & 0 deletions src/addBusinessDays/test.js
@@ -0,0 +1,49 @@
// @flow
/* eslint-env mocha */

import assert from 'power-assert'
import addBusinessDays from '.'

describe('addBusinessDays', function() {
it('adds the given number of business days', function() {
var result = addBusinessDays(new Date(2014, 8 /* Sep */, 1), 10)
assert.deepEqual(result, new Date(2014, 8 /* Sep */, 15))
})

it('accepts a timestamp', function() {
var result = addBusinessDays(new Date(2014, 8 /* Sep */, 1).getTime(), 10)
assert.deepEqual(result, new Date(2014, 8 /* Sep */, 15))
})

it('converts a fractional number to an integer', function() {
var result = addBusinessDays(new Date(2014, 8 /* Sep */, 1), 10.5)
assert.deepEqual(result, new Date(2014, 8 /* Sep */, 15))
})

it('implicitly converts number arguments', function() {
// $ExpectedMistake
var result = addBusinessDays(new Date(2014, 8 /* Sep */, 1), '10')
assert.deepEqual(result, new Date(2014, 8 /* Sep */, 15))
})

it('does not mutate the original date', function() {
var date = new Date(2014, 8 /* Sep */, 1)
addBusinessDays(date, 11)
assert.deepEqual(date, new Date(2014, 8 /* Sep */, 1))
})

it('returns `Invalid Date` if the given date is invalid', function() {
var result = addBusinessDays(new Date(NaN), 10)
assert(result instanceof Date && isNaN(result))
})

it('returns `Invalid Date` if the given amount is NaN', function() {
var result = addBusinessDays(new Date(2014, 8 /* Sep */, 1), NaN)
assert(result instanceof Date && isNaN(result))
})

it('throws TypeError exception if passed less than 2 arguments', function() {
assert.throws(addBusinessDays.bind(null), TypeError)
assert.throws(addBusinessDays.bind(null, 1), TypeError)
})
})
1 change: 1 addition & 0 deletions src/esm/fp/index.js
@@ -1,5 +1,6 @@
// This file is generated automatically by `scripts/build/indices.js`. Please, don't change it.

export { default as addBusinessDays } from './addBusinessDays/index.js'
export { default as addDays } from './addDays/index.js'
export { default as addHours } from './addHours/index.js'
export { default as addISOWeekYears } from './addISOWeekYears/index.js'
Expand Down
1 change: 1 addition & 0 deletions src/esm/index.js
@@ -1,5 +1,6 @@
// This file is generated automatically by `scripts/build/indices.js`. Please, don't change it.

export { default as addBusinessDays } from './addBusinessDays/index.js'
export { default as addDays } from './addDays/index.js'
export { default as addHours } from './addHours/index.js'
export { default as addISOWeekYears } from './addISOWeekYears/index.js'
Expand Down
4 changes: 4 additions & 0 deletions src/fp/addBusinessDays/index.d.ts
@@ -0,0 +1,4 @@
// This file is generated automatically by `scripts/build/typings.js`. Please, don't change it.

import { addBusinessDays } from 'date-fns/fp'
export default addBusinessDays
8 changes: 8 additions & 0 deletions src/fp/addBusinessDays/index.js
@@ -0,0 +1,8 @@
// This file is generated automatically by `scripts/build/fp.js`. Please, don't change it.

import fn from '../../addBusinessDays/index.js'
import convertToFP from '../_lib/convertToFP/index.js'

var addBusinessDays = convertToFP(fn, 2)

export default addBusinessDays
44 changes: 44 additions & 0 deletions src/fp/addBusinessDays/index.js.flow
@@ -0,0 +1,44 @@
// @flow
// This file is generated automatically by `scripts/build/typings.js`. Please, don't change it.

type Interval = {
start: Date | number,
end: Date | number
}

type Locale = {
formatDistance: Function,
formatRelative: Function,
localize: {
ordinalNumber: Function,
era: Function,
quarter: Function,
month: Function,
day: Function,
dayPeriod: Function
},
formatLong: Object,
date: Function,
time: Function,
dateTime: Function,
match: {
ordinalNumber: Function,
era: Function,
quarter: Function,
month: Function,
day: Function,
dayPeriod: Function
},
options?: {
weekStartsOn?: 0 | 1 | 2 | 3 | 4 | 5 | 6,
firstWeekContainsDate?: 1 | 2 | 3 | 4 | 5 | 6 | 7
}
}

type CurriedFn1<A, R> = <A>(a: A) => R

type CurriedFn2<A, B, R> = <A>(
a: A
) => CurriedFn1<B, R> | (<A, B>(a: A, b: B) => R)

declare module.exports: CurriedFn2<number, Date | number, Date>
1 change: 1 addition & 0 deletions src/fp/index.js
Expand Up @@ -3,6 +3,7 @@
var constants = require('../constants/index.js')

module.exports = {
addBusinessDays: require('./addBusinessDays/index.js'),
addDays: require('./addDays/index.js'),
addHours: require('./addHours/index.js'),
addISOWeekYears: require('./addISOWeekYears/index.js'),
Expand Down
1 change: 1 addition & 0 deletions src/fp/index.js.flow
Expand Up @@ -66,6 +66,7 @@ type CurriedFn4<A, B, C, D, R> = <A>(
) => CurriedFn1<D, R> | (<A, B, C, D>(a: A, b: B, c: C, d: D) => R)))

declare module.exports: {
addBusinessDays: CurriedFn2<number, Date | number, Date>,
addDays: CurriedFn2<number, Date | number, Date>,
addHours: CurriedFn2<number, Date | number, Date>,
addISOWeekYears: CurriedFn2<number, Date | number, Date>,
Expand Down
1 change: 1 addition & 0 deletions src/index.js
Expand Up @@ -3,6 +3,7 @@
var constants = require('./constants/index.js')

module.exports = {
addBusinessDays: require('./addBusinessDays/index.js'),
addDays: require('./addDays/index.js'),
addHours: require('./addHours/index.js'),
addISOWeekYears: require('./addISOWeekYears/index.js'),
Expand Down
2 changes: 2 additions & 0 deletions src/index.js.flow
Expand Up @@ -36,6 +36,8 @@ type Locale = {
}

declare module.exports: {
addBusinessDays: (date: Date | number, amount: number) => Date,

addDays: (date: Date | number, amount: number) => Date,

addHours: (date: Date | number, amount: number) => Date,
Expand Down
18 changes: 18 additions & 0 deletions test/dst/addBusinessDays/basic.js
@@ -0,0 +1,18 @@
// This is basic DST test for addBusinessDays

import assert from 'assert'
import addBusinessDays from '../../../src/addBusinessDays'

if (process.env.TZ !== 'America/Santiago')
throw new Error('The test must be run with TZ=America/Santiago')

if (parseInt(process.version.match(/^v(\d+)\./)[1]) < 10)
throw new Error('The test must be run on Node.js version >= 10')

console.log(addBusinessDays(new Date(2014, 8 /* Sep */, 1), 10).toString())

assert.deepEqual(
// new Date(2014, 8, 7) is the DST day
addBusinessDays(new Date(2014, 8 /* Sep */, 1), 10).toString(),
'Mon Sep 15 2014 00:00:00 GMT-0300 (Chile Summer Time)'
)