Skip to content

Commit

Permalink
New eachMinuteOfInterval function (#2382)
Browse files Browse the repository at this point in the history
Added new `eachMinuteOfInterval` function.

Co-authored-by: Vitor Ferreira <vitorfrs98@gmail.com>
  • Loading branch information
tan75 and vitorfrs-dev committed Apr 8, 2021
1 parent 988b6ef commit 76945e0
Show file tree
Hide file tree
Showing 3 changed files with 189 additions and 0 deletions.
20 changes: 20 additions & 0 deletions src/eachMinuteOfInterval/benchmark.js
@@ -0,0 +1,20 @@
// @flow
/* eslint-env mocha */
/* global suite, benchmark */

import eachMinuteOfInterval from '.'

suite(
'eachMinuteOfInterval',
function() {
benchmark('date-fns', function() {
return eachMinuteOfInterval({ start: this.dateA, end: this.dateB })
})
},
{
setup: function() {
this.dateA = new Date()
this.dateB = new Date(this.dateA.getTime() + 300000)
}
}
)
70 changes: 70 additions & 0 deletions src/eachMinuteOfInterval/index.ts
@@ -0,0 +1,70 @@
import addMinutes from '../addMinutes/index'
import toDate from '../toDate/index'
import startOfMinute from '../startOfMinute/index'
import requiredArgs from '../_lib/requiredArgs/index'

import { Interval, StepOptions } from '../types'

/**
* @name eachMinuteOfInterval
* @category Interval Helpers
* @summary Return the array of minutes within the specified time interval.
*
* @description
* Returns the array of minutes within the specified time interval.
*
* @param {Interval} interval - the interval. See [Interval]{@link https://date-fns.org/docs/Interval}
* @param {Object} [options] - an object with options.
* @param {Number} [options.step=1] - the step to increment by. The starts of minutes from the hour of the interval start to the hour of the interval end
* @throws {TypeError} 1 argument requie value should be more than 1.
* @returns {Date[]} the array withred
* @throws {RangeError} `options.step` must be a number equal or greater than 1
* @throws {RangeError} The start of an interval cannot be after its end
* @throws {RangeError} Date in interval cannot be `Invalid Date`
*
* @example
* // Each minute between 14 October 2020, 13:00 and 14 October 2020, 13:03
* const result = eachMinuteOfInterval({
* start: new Date(2014, 9, 14, 13),
* end: new Date(2014, 9, 14, 13, 3)
* })
* //=> [
* // Wed Oct 14 2014 13:00:00,
* // Wed Oct 14 2014 13:01:00,
* // Wed Oct 14 2014 13:02:00,
* // Wed Oct 14 2014 13:03:00
* // ]
*/
export default function eachMinuteOfInterval(
interval: Interval,
options?: StepOptions
): Date[] {
requiredArgs(1, arguments)

const startDate = startOfMinute(toDate(interval.start))
const endDate = startOfMinute(toDate(interval.end))

const startTime = startDate.getTime()
const endTime = endDate.getTime()

if (startTime >= endTime) {
throw new RangeError('Invalid interval')
}

const dates = []

let currentDate = startDate

const step = options && 'step' in options ? Number(options.step) : 1
if (step < 1 || isNaN(step))
throw new RangeError(
'`options.step` must be a number equal or greater than 1'
)

while (currentDate.getTime() <= endTime) {
dates.push(toDate(currentDate))
currentDate = addMinutes(currentDate, step)
}

return dates
}
99 changes: 99 additions & 0 deletions src/eachMinuteOfInterval/test.ts
@@ -0,0 +1,99 @@
// @flow
/* eslint-env mocha */

import assert from 'power-assert'

import eachMinuteOfInterval from '.'

describe('eachMinuteOfInterval', () => {
it('should return an array of Date objects containing a Date for each minute between the interval', () => {
const result = eachMinuteOfInterval({
start: new Date(2020, 10, 14, 13, 0),
end: new Date(2020, 10, 14, 13, 5)
})

assert.deepEqual(result, [
new Date(2020, 10, 14, 13, 0),
new Date(2020, 10, 14, 13, 1),
new Date(2020, 10, 14, 13, 2),
new Date(2020, 10, 14, 13, 3),
new Date(2020, 10, 14, 13, 4),
new Date(2020, 10, 14, 13, 5)
])
})

it('should handle all the minutes that are not in the begining', () => {
const result = eachMinuteOfInterval({
start: new Date(2020, 10, 14, 13, 0, 33),
end: new Date(2020, 10, 14, 13, 2)
})

assert.deepEqual(result[0], new Date(2020, 10, 14, 13))
assert.deepEqual(result[2], new Date(2020, 10, 14, 13, 2))
})

it('should accept timestamps', () => {
const start = new Date(2020, 10, 14, 13, 0).getTime()
const end = new Date(2020, 10, 14, 13, 2).getTime()

const result = eachMinuteOfInterval({
start,
end
})

assert.deepEqual(result, [
new Date(2020, 10, 14, 13, 0),
new Date(2020, 10, 14, 13, 1),
new Date(2020, 10, 14, 13, 2)
])
})

it('throws an exception if the start date is after the end date', () => {
const block = eachMinuteOfInterval.bind(null, {
start: new Date(2014, 10, 14, 10),
end: new Date(2014, 10, 14, 5)
})
assert.throws(block, RangeError)
})

describe('options.step', () => {
const interval = {
start: new Date(2020, 9, 14, 13, 1),
end: new Date(2020, 9, 14, 13, 7)
}

const stepError = /^RangeError: `options.step` must be a number equal or greater than 1$/

it('returns an array with starts of hours from the hour of the start date to the hour of the end date with the given step', () => {
const result = eachMinuteOfInterval(interval, { step: 3 })
assert.deepEqual(result, [
new Date(2020, 9, 14, 13, 1),
new Date(2020, 9, 14, 13, 4),
new Date(2020, 9, 14, 13, 7)
])
})

it('throws TypeError error if `options.step` is less than 1', () => {
assert.throws(
() => eachMinuteOfInterval(interval, { step: 0 }),
stepError
)
assert.throws(
() => eachMinuteOfInterval(interval, { step: -3 }),
stepError
)
})

it('throws TypeError error if `options.step` is NaN', () => {
// $ExpectedMistake
assert.throws(
() => eachMinuteOfInterval(interval, { step: 'w' }),
stepError
)
assert.throws(
() => eachMinuteOfInterval(interval, { step: NaN }),
stepError
)
})
})
})

0 comments on commit 76945e0

Please sign in to comment.