Skip to content

Commit

Permalink
Add addBusinessDays function (date-fns#1154)
Browse files Browse the repository at this point in the history
  • Loading branch information
codinsonn authored and elmomalmo committed Jul 12, 2019
1 parent f429b90 commit 8609cad
Show file tree
Hide file tree
Showing 17 changed files with 294 additions and 0 deletions.
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)'
)

0 comments on commit 8609cad

Please sign in to comment.