-
-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add new function roundToNearestHours
- Loading branch information
1 parent
b8b7e52
commit da83376
Showing
2 changed files
with
124 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
import constructFrom from '../constructFrom/index' | ||
import toDate from '../toDate/index' | ||
import type { RoundingOptions } from '../types' | ||
import { getRoundingMethod } from '../_lib/roundingMethods/index' | ||
|
||
/** | ||
* The {@link roundToNearestHours} function options. | ||
*/ | ||
export interface RoundToNearestHoursOptions extends RoundingOptions { | ||
nearestTo?: number | ||
} | ||
|
||
/** | ||
* @name roundToNearestHours | ||
* @category Hour Helpers | ||
* @summary Rounds the given date to the nearest hour | ||
* | ||
* @description | ||
* Rounds the given date to the nearest hour (or number of hours). | ||
* Rounds up when the given date is exactly between the nearest rounded hour. | ||
* | ||
* @param date - the date to round | ||
* @param options - an object with options. | ||
* @returns {Date} the new date rounded to the closest hour | ||
* @throws {RangeError} `options.nearestTo` must be between 1 and 12 | ||
* | ||
* @example | ||
* // Round 10 July 2014 12:12:34 to nearest hour: | ||
* var result = roundToNearestHours(new Date(2014, 6, 10, 12, 12, 34)) | ||
* //=> Thu Jul 10 2014 12:00:00 | ||
* | ||
* @example | ||
* // Round 10 July 2014 13:12:34 to nearest quarter of day: | ||
* var result = roundToNearestHours(new Date(2014, 6, 10, 13, 12, 34), { nearestTo: 6 }) | ||
* // rounds up because given date is exactly between 12:00:00 and 18:00:00 | ||
* //=> Thu Jul 9 2014 12:00:00 | ||
*/ | ||
export default function roundToNearestHours( | ||
dirtyDate: Date | number, | ||
options?: RoundToNearestHoursOptions | ||
): Date { | ||
const nearestTo = options?.nearestTo ?? 1 | ||
|
||
if (nearestTo < 1 || nearestTo > 12) { | ||
throw new RangeError('`options.nearestTo` must be between 1 and 12') | ||
} | ||
|
||
const date = toDate(dirtyDate) | ||
const minutes = date.getMinutes() // relevant if nearestTo is 1, which is the default case | ||
const hours = date.getHours() + minutes / 60 | ||
const roundingMethod = getRoundingMethod(options?.roundingMethod) | ||
const roundedHour = roundingMethod(hours / nearestTo) * nearestTo | ||
const remainderHour = hours % nearestTo | ||
const addedHour = Math.round(remainderHour / nearestTo) * nearestTo | ||
|
||
const result = constructFrom(date, date) | ||
result.setHours(roundedHour + addedHour, 0, 0, 0) | ||
return result | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
/* eslint-env mocha */ | ||
|
||
import assert from 'assert' | ||
import roundToNearestHours from './index' | ||
|
||
describe('roundToNearestHours', function () { | ||
it('rounds given date to the nearest hour by default', function () { | ||
const result = roundToNearestHours( | ||
new Date(2014, 6 /* Jul */, 10, 12, 16, 16) | ||
) | ||
assert.deepStrictEqual(result, new Date(2014, 6 /* Jul */, 10, 12, 0, 0)) | ||
}) | ||
|
||
it('accepts a timestamp', function () { | ||
const result = roundToNearestHours( | ||
new Date(2014, 6 /* Jul */, 10, 12, 13, 16).getTime() | ||
) | ||
assert.deepStrictEqual(result, new Date(2014, 6 /* Jul */, 10, 12, 0, 0)) | ||
}) | ||
|
||
it('rounds to the closest x hours if nearestTo is provided', function () { | ||
const result = roundToNearestHours( | ||
new Date(2014, 6 /* Jul */, 10, 10, 10, 30), | ||
{ nearestTo: 4 } | ||
) | ||
assert.deepStrictEqual(result, new Date(2014, 6 /* Jul */, 10, 12, 0, 0)) | ||
}) | ||
|
||
it('rounds up >=30 minutes for nearestTo=1', function () { | ||
const result = roundToNearestHours( | ||
new Date(2014, 6 /* Jul */, 10, 12, 30, 0) | ||
) | ||
assert.deepStrictEqual(result, new Date(2014, 6 /* Jul */, 10, 13, 0, 0)) | ||
}) | ||
|
||
it('rounds down <30 minutes for nearestTo=1', function () { | ||
const result = roundToNearestHours( | ||
new Date(2014, 6 /* Jul */, 10, 12, 13, 29, 999) | ||
) | ||
assert.deepStrictEqual(result, new Date(2014, 6 /* Jul */, 10, 12, 0, 0)) | ||
}) | ||
|
||
it('does not mutate the original date', function () { | ||
const date = new Date(2014, 6 /* Jul */, 10, 12, 10, 10, 99) | ||
roundToNearestHours(date) | ||
assert.deepStrictEqual(date, new Date(2014, 6 /* Jul */, 10, 12, 10, 10, 99)) | ||
}) | ||
|
||
it('returns `Invalid Date` if the given date is invalid', function () { | ||
const result = roundToNearestHours(new Date(NaN)) | ||
assert(result instanceof Date && isNaN(result.getTime())) | ||
}) | ||
|
||
it('throws `RangeError` if nearestTo is not between 1 and 12', function () { | ||
const date = new Date(2014, 6 /* Jul */, 10, 12, 10, 30) | ||
assert.throws( | ||
roundToNearestHours.bind(null, date, { nearestTo: 13 }), | ||
RangeError | ||
) | ||
assert.throws( | ||
roundToNearestHours.bind(null, date, { nearestTo: 0 }), | ||
RangeError | ||
) | ||
}) | ||
}) |