From 52ccbb1a82fe0e559d7a47b2b95d1befc1d2eda1 Mon Sep 17 00:00:00 2001 From: Jonathan Mannancheril Date: Sat, 31 Aug 2019 13:18:07 -0500 Subject: [PATCH] Add new set function --- src/fp/set/index.d.ts | 4 ++ src/fp/set/index.js | 8 +++ src/fp/set/index.js.flow | 44 ++++++++++++ src/set/benchmark.js | 25 +++++++ src/set/index.d.ts | 4 ++ src/set/index.js | 91 +++++++++++++++++++++++++ src/set/index.js.flow | 49 ++++++++++++++ src/set/test.js | 143 +++++++++++++++++++++++++++++++++++++++ 8 files changed, 368 insertions(+) create mode 100644 src/fp/set/index.d.ts create mode 100644 src/fp/set/index.js create mode 100644 src/fp/set/index.js.flow create mode 100644 src/set/benchmark.js create mode 100644 src/set/index.d.ts create mode 100644 src/set/index.js create mode 100644 src/set/index.js.flow create mode 100644 src/set/test.js diff --git a/src/fp/set/index.d.ts b/src/fp/set/index.d.ts new file mode 100644 index 0000000000..601f00b8d0 --- /dev/null +++ b/src/fp/set/index.d.ts @@ -0,0 +1,4 @@ +// This file is generated automatically by `scripts/build/typings.js`. Please, don't change it. + +import { set } from 'date-fns/fp' +export default set diff --git a/src/fp/set/index.js b/src/fp/set/index.js new file mode 100644 index 0000000000..07edbec11f --- /dev/null +++ b/src/fp/set/index.js @@ -0,0 +1,8 @@ +// This file is generated automatically by `scripts/build/fp.js`. Please, don't change it. + +import fn from '../../set/index.js' +import convertToFP from '../_lib/convertToFP/index.js' + +var set = convertToFP(fn, 2) + +export default set diff --git a/src/fp/set/index.js.flow b/src/fp/set/index.js.flow new file mode 100644 index 0000000000..a74e1a6bf3 --- /dev/null +++ b/src/fp/set/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: A) => R + +type CurriedFn2 = ( + a: A +) => CurriedFn1 | ((a: A, b: B) => R) + +declare module.exports: CurriedFn2 diff --git a/src/set/benchmark.js b/src/set/benchmark.js new file mode 100644 index 0000000000..55e2c167b8 --- /dev/null +++ b/src/set/benchmark.js @@ -0,0 +1,25 @@ +// @flow +/* eslint-env mocha */ +/* global suite, benchmark */ + +import set from '.' +import moment from 'moment' + +suite( + 'set', + function() { + benchmark('date-fns', function() { + return set(this.date, { year: 2014, month: 8 }) + }) + + benchmark('Moment.js', function() { + return this.moment.set({ year: 2014, month: 3 }) + }) + }, + { + setup: function() { + this.date = new Date(2013, 7) + this.moment = moment() + } + } +) diff --git a/src/set/index.d.ts b/src/set/index.d.ts new file mode 100644 index 0000000000..d30347b600 --- /dev/null +++ b/src/set/index.d.ts @@ -0,0 +1,4 @@ +// This file is generated automatically by `scripts/build/typings.js`. Please, don't change it. + +import { set } from 'date-fns' +export default set diff --git a/src/set/index.js b/src/set/index.js new file mode 100644 index 0000000000..c4c777e4a5 --- /dev/null +++ b/src/set/index.js @@ -0,0 +1,91 @@ +import toDate from '../toDate/index.js' +import setMonth from '../setMonth/index.js' +import toInteger from '../_lib/toInteger/index.js' + +/** + * @name set + * @category Common Helpers + * @summary Set date values to a given date. + * + * @description + * Set date values to a given date. + * + * Sets time values to date from object `values`. + * A value is not set if it is undefined or null or doesn't exist in `values`. + * + * Note about bundle size: `set` does not internally use `setX` functions from date-fns but instead opts + * to use native `Date#setX` methods. If you use this function, you may not want to include the + * other `setX` functions that date-fns provides if you are concerned about the bundle size. + * + * @param {Date|Number} date - the date to be changed + * @param {Object} values - an object with options + * @param {Number} values.year - the number of years to be set + * @param {Number} values.month - the number of months to be set + * @param {Number} values.date - the number of days to be set + * @param {Number} values.hours - the number of hours to be set + * @param {Number} values.minutes - the number of minutes to be set + * @param {Number} values.seconds - the number of seconds to be set + * @param {Number} values.milliseconds - the number of milliseconds to be set + * @returns {Date} the new date with options set + * @throws {TypeError} 2 arguments required + * @throws {RangeError} `values` must be an object + * + * @example + * // Transform 1 September 2014 into 20 October 2015 in a single line: + * var result = set(new Date(2014, 8, 20), { year: 2015, month: 9, date: 20 }) + * //=> Tue Oct 20 2015 00:00:00 + * + * @example + * // Set 12 PM to 1 September 2014 01:23:45 to 1 September 2014 12:00:00: + * var result = set(new Date(2014, 8, 1, 1, 23, 45), { hours: 12 }) + * //=> Mon Sep 01 2014 12:23:45 + */ + +export default function set(dirtyDate, values) { + if (arguments.length < 2) { + throw new TypeError( + '2 arguments required, but only ' + arguments.length + ' present' + ) + } + + if (typeof values !== 'object' || values === null) { + throw new RangeError('values parameter must be an object') + } + + var date = toDate(dirtyDate) + + // Check if date is Invalid Date because Date.prototype.setFullYear ignores the value of Invalid Date + if (isNaN(date)) { + return new Date(NaN) + } + + if (values.year != null) { + date.setFullYear(values.year) + } + + if (values.month != null) { + date = setMonth(date, values.month) + } + + if (values.date != null) { + date.setDate(toInteger(values.date)) + } + + if (values.hours != null) { + date.setHours(toInteger(values.hours)) + } + + if (values.minutes != null) { + date.setMinutes(toInteger(values.minutes)) + } + + if (values.seconds != null) { + date.setSeconds(toInteger(values.seconds)) + } + + if (values.milliseconds != null) { + date.setMilliseconds(toInteger(values.milliseconds)) + } + + return date +} diff --git a/src/set/index.js.flow b/src/set/index.js.flow new file mode 100644 index 0000000000..2d2e16f593 --- /dev/null +++ b/src/set/index.js.flow @@ -0,0 +1,49 @@ +// @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, + values: { + year?: number, + month?: number, + date?: number, + hours?: number, + minutes?: number, + seconds?: number, + milliseconds?: number + } +) => Date diff --git a/src/set/test.js b/src/set/test.js new file mode 100644 index 0000000000..c74a293f53 --- /dev/null +++ b/src/set/test.js @@ -0,0 +1,143 @@ +// @flow +/* eslint-env mocha */ + +import assert from 'power-assert' +import set from '.' + +describe('set', function() { + it('sets all values', function() { + var result = set(new Date(2013), { + year: 2014, + month: 8, // Sep + date: 20, + hours: 12, + minutes: 12, + seconds: 12, + milliseconds: 12 + }) + assert.deepEqual( + result.toString(), + new Date(2014, 8 /* Sep */, 20, 12, 12, 12, 12).toString() + ) + }) + + it('sets year', function() { + var result = set(new Date(2013, 8 /* Sep */), { year: 2014 }) + assert.deepEqual(result, new Date(2014, 8 /* Sep */)) + }) + + it('sets month', function() { + var result = set(new Date(2014, 8 /* Sep */), { month: 9 /* Oct */ }) + assert.deepEqual(result, new Date(2014, 9 /* Oct */)) + }) + + it('sets day of month', function() { + var result = set(new Date(2014, 8 /* Sep */), { date: 20 }) + assert.deepEqual(result, new Date(2014, 8 /* Sep */, 20)) + }) + + it('sets hours', function() { + var result = set(new Date(2014, 8 /* Sep */, 1), { hours: 12 }) + assert.deepEqual(result, new Date(2014, 8 /* Sep */, 1, 12)) + }) + + it('sets minutes', function() { + var result = set(new Date(2014, 8 /* Sep */, 1, 1), { minutes: 12 }) + assert.deepEqual(result, new Date(2014, 8 /* Sep */, 1, 1, 12)) + }) + + it('sets seconds', function() { + var result = set(new Date(2014, 8 /* Sep */, 1, 1, 1), { seconds: 12 }) + assert.deepEqual(result, new Date(2014, 8 /* Sep */, 1, 1, 1, 12)) + }) + + it('sets milliseconds', function() { + var result = set(new Date(2014, 8 /* Sep */, 1, 1, 1, 1), { + milliseconds: 500 + }) + assert.deepEqual(result, new Date(2014, 8 /* Sep */, 1, 1, 1, 1, 500)) + }) + + describe('value overflow', function() { + it('months overflow into years', function() { + var result = set(new Date(2014, 8 /* Sep */, 1), { + month: 12 /* 13th month */ + }) + assert.deepEqual(result, new Date(2015, 0 /* Jan */, 1)) + }) + + it('days of months overflow into months', function() { + var result = set(new Date(2014, 8 /* Sep */, 1), { date: 31 }) + assert.deepEqual(result, new Date(2014, 9 /* Oct */, 1)) + }) + + it('hours overflow into days', function() { + var result = set(new Date(2014, 8 /* Sep */, 19), { hours: 24 }) + assert.deepEqual(result, new Date(2014, 8 /* Sep */, 20)) + }) + + it('minutes overflow into hours', function() { + var result = set(new Date(2014, 8 /* Sep */, 20, 11), { minutes: 60 }) + assert.deepEqual(result, new Date(2014, 8 /* Sep */, 20, 12)) + }) + + it('seconds overflow into minutes', function() { + var result = set(new Date(2014, 8 /* Sep */, 20, 12, 58), { seconds: 60 }) + assert.deepEqual(result, new Date(2014, 8 /* Sep */, 20, 12, 59)) + }) + + it('milliseconds overflow into seconds', function() { + var result = set(new Date(2014, 8 /* Sep */, 20, 12, 58, 30), { + milliseconds: 1000 + }) + assert.deepEqual(result, new Date(2014, 8 /* Sep */, 20, 12, 58, 31)) + }) + }) + + describe('edge cases', function() { + it('sets January', function() { + var result = set(new Date(2014, 8 /* Sep */), { month: 0 /* Jan */ }) + assert.deepEqual(result, new Date(2014, 0 /* Jan */)) + }) + + it('sets the last day of new month if the initial date was the last day of a longer month', function() { + var result = set(new Date(2014, 7 /* Aug */, 31), { month: 8 /* Sep */ }) + assert.deepEqual(result, new Date(2014, 8 /* Sep */, 30)) + }) + + it('ignores undefined values', function() { + var result = set(new Date(2014, 8 /* Sep */), { year: undefined }) + assert.deepEqual(result, new Date(2014, 8 /* Sep */)) + }) + + it('ignores null values', function() { + // $ExpectedMistake + var result = set(new Date(2014, 8 /* Sep */), { year: null }) + assert.deepEqual(result, new Date(2014, 8 /* Sep */)) + }) + + it('throws TypeError exception if passed less than 2 arguments', function() { + assert.throws(set.bind(null), TypeError) + }) + + it('returns Invalid Date if any value in values is NaN', function() { + var result = set(new Date(2014, 8 /* Sep */), { year: NaN }) + assert.deepEqual(isNaN(result), isNaN(new Date(NaN))) + }) + + it('returns Invalid Date the initial date was Invalid Date as well', function() { + var result = set(new Date(NaN), { year: 2019 }) + assert.deepEqual(isNaN(result), isNaN(new Date(NaN))) + }) + + it('throws RangeError exception if `values` is not an object', function() { + // $ExpectedMistake + assert.throws(set.bind(null, new Date(), true), RangeError) + }) + + it('throws RangeError exception if `values` is null', function() { + // $ExpectedMistake + assert.throws(set.bind(null, new Date(), null), RangeError) + }) + }) +})