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

Fix corner cases #460

Merged
merged 30 commits into from Apr 6, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
4a86f69
Invalid Date tests for `addX`, `setX` and `subX`
leshakoss Mar 10, 2017
c2ad9aa
Invalid Date tests for `getX`
leshakoss Mar 10, 2017
7198e72
Invalid Date tests for `startOfX`, `endOfX` and `lastDayOfX`
leshakoss Mar 10, 2017
bdf0fe6
Invalid Date tests for `isSameX`
leshakoss Mar 10, 2017
23bf5cc
Invalid Date tests for `differenceInX`
leshakoss Mar 10, 2017
a221f1d
`isX(new Date(NaN))` tests
leshakoss Mar 10, 2017
a29d4c1
`isAfter`, `isBefore` and `isEqual` Invalid Date tests
leshakoss Mar 10, 2017
76a7ee9
Interval functions Invalid Date tests
leshakoss Mar 10, 2017
f95be8d
`compareAsc` and `compareDesc` Invalid Date tests
leshakoss Mar 10, 2017
e37f161
`closestTo`, `closestIndexTo`, `max` and `min` Invalid Date tests
leshakoss Mar 10, 2017
6f1ad3c
Test `toDate` if `options.additionalDigits` is not 0, 1, 2 or undefined
leshakoss Mar 10, 2017
55d8f13
Test `parse` if baseDate is `Invalid Date`
leshakoss Mar 10, 2017
f5d8974
`distanceInWords` and `distanceInWordsStrict` invalid values tests
leshakoss Mar 10, 2017
638588c
Invalid `options.weekStartsOn` tests
leshakoss Mar 10, 2017
0a4ae92
Invalid value implementation fixes
leshakoss Mar 10, 2017
f16abd9
`parse` implementation fix
leshakoss Apr 4, 2017
2dfc42b
`weekStartsOn` implementation fix
leshakoss Apr 4, 2017
32e6716
Rename `partialMethod` to `roundingMethod`
leshakoss Mar 9, 2017
94aa54c
`distanceInWordsStrict` implementation fix
leshakoss Apr 4, 2017
57c0bfb
Rebuild typings
leshakoss Apr 4, 2017
fefcf91
`toDate` implementation fix
leshakoss Apr 4, 2017
c56f2a4
Add CHANGELOG.md entry
leshakoss Apr 4, 2017
d6dbf1e
Add missing tests
leshakoss Apr 5, 2017
5bdbb46
Make interval functions throw RangeError
leshakoss Apr 5, 2017
e077e09
Fix @throws docs messages
leshakoss Apr 5, 2017
9c6c6f7
Add `@throws {RangeError}` to all functions docs
leshakoss Apr 5, 2017
e5df225
Add `@param [options.additionalDigits]` to all functions docs
leshakoss Apr 5, 2017
edaf164
Add `options.additionalDigits` tests to all functions
leshakoss Apr 5, 2017
202ba04
Complete corner cases changelog entry
leshakoss Apr 5, 2017
4318f37
Add missing `$ExpectedMistake`
leshakoss Apr 5, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
43 changes: 40 additions & 3 deletions CHANGELOG.md
Expand Up @@ -187,8 +187,9 @@ This change log follows the format documented in [Keep a CHANGELOG].
```

Also these functions now accept an object with `start` and `end` properties
instead of two arguments as an interval. All these functions, as before,
throw an exception if the start of the interval is after its end.
instead of two arguments as an interval. All these functions
throw `RangeError` if the start of the interval is after its end
or if any date in interval is `Invalid Date`.

```javascript
// Before v2.0.0
Expand Down Expand Up @@ -311,7 +312,43 @@ This change log follows the format documented in [Keep a CHANGELOG].

We introduce this change to make *date-fns* consistent with ECMAScript behavior
that try to coerce arguments to the expected type
(which is also the case with other *date-fns* functions).
(which is also the case with other *date-fns* functions).

- **BREAKING**: `partialMethod` option in `distanceInWordsStrict` is renamed to `roundingMethod`.

```javascript
// Before v2.0.0
var options = {partialMethod: 'ceil'}
// v2.0.0 onward
var options = {roundingMethod: 'ceil'}

var result = distanceInWordsStrict(
new Date(1986, 3, 4, 10, 32, 0),
new Date(1986, 3, 4, 10, 33, 1),
options
)
```

- **BREAKING**: functions now throw `RangeError` if optional values passed to `options`
are not `undefined` or have expected values.
This change is introduced for consistency with ECMAScript standard library which does the same.
See [docs/Options.js](https://github.com/date-fns/date-fns/blob/master/docs/Options.js)

- **BREAKING**: all functions now handle arguments by following rules:

- as before, arguments expected to be `Date` are converted to `Date` using *date-fns'* `toDate` function;
- arguments expected to be numbers are converted to numbers using JavaScript's `Number` function;
- arguments expected to be strings arguments are converted to strings using JavaScript's `String` function.

If any of resulting arguments is invalid (i.e. `NaN` for numbers and `Invalid Date` for dates),
an invalid value will be returned:

- `false` for functions that return booleans (expect `isValid`);
- `Invalid Date` for functions that return dates;
- `NaN` for functions that return numbers;
- and `String('Invalid Date')` for functions that return strings.

See tests and PR [#460](https://github.com/date-fns/date-fns/pull/460) for exact behavior.

- Every function now has `options` as the last argument which is passed to all its dependencies
for consistency and future features.
Expand Down
16 changes: 13 additions & 3 deletions docs/Options.js
Expand Up @@ -6,9 +6,9 @@
* An object passed as the last optional argument to all functions.
*
* @typedef {Object} Options
* @property {Number} [weekStartsOn=0] - the index of the first day of the week (0 - Sunday).
* @property {0|1|2|3|4|5|6} [weekStartsOn=0] - the index of the first day of the week (0 - Sunday).
* Used by `differenceInCalendarWeeks`, `endOfWeek`, `isSameWeek`,
* `isThisWeek`, `lastDayOfWeek`, `setDay`, and `startOfWeek`
* `lastDayOfWeek`, `parse`, `setDay`, and `startOfWeek`
* @property {0|1|2} [additionalDigits=2] - the additional number of digits in the extended year format.
* Used by all functions that take String as Date-like argument.
* Internally, passed to `toDate` to specify which way to convert extended year formatted String to Date.
Expand All @@ -22,9 +22,19 @@
* If true, the result will indicate if the second date is earlier or later than the first
* @property {'s'|'m'|'h'|'d'|'M'|'Y'} [unit] - used by `distanceInWordsStrict`.
* If specified, will force a unit
* @property {'floor'|'ceil'|'round'} [partialMethod='floor'] - used by `distanceInWordsStrict`.
* @property {'floor'|'ceil'|'round'} [roundingMethod='floor'] - used by `distanceInWordsStrict`.
* Specifies, which way to round partial units
*
* @throws {RangeError} `options.additionalDigits` must be 0, 1 or 2.
* Thrown by **all** functions
* @throws {RangeError} `options.weekStartsOn` must be between 0 and 6.
* Thrown by `differenceInCalendarWeeks`, `endOfWeek`, `isSameWeek`,
* `lastDayOfWeek`, `parse`, `setDay`, and `startOfWeek`.
* @throws {RangeError} `options.roundingMethod` must be 'floor', 'ceil' or 'round'.
* Thrown by `distanceInWordsStrict`
* @throws {RangeError} `options.unit` must be 's', 'm', 'h', 'd', 'M' or 'Y'.
* Thrown by `distanceInWordsStrict`
*
* @example
* // For 15 December 12345 AD, represent the start of the week in Esperanto,
* // if the first day of the week is Monday:
Expand Down
2 changes: 2 additions & 0 deletions src/addDays/index.js
Expand Up @@ -11,7 +11,9 @@ import toDate from '../toDate/index.js'
* @param {Date|String|Number} date - the date to be changed
* @param {Number} amount - the amount of days to be added
* @param {Options} [options] - the object with options. See [Options]{@link docs/Options}
* @param {0|1|2} [options.additionalDigits=2] - passed to `toDate`. See [toDate]{@link docs/toDate}
* @returns {Date} the new date with the days added
* @throws {RangeError} `options.additionalDigits` must be 0, 1 or 2
*
* @example
* // Add 10 days to 1 September 2014:
Expand Down
4 changes: 2 additions & 2 deletions src/addDays/index.js.flow
Expand Up @@ -7,13 +7,13 @@ type Interval = {
}

type Options = {
weekStartsOn?: number,
weekStartsOn?: 0 | 1 | 2 | 3 | 4 | 5 | 6,
additionalDigits?: 0 | 1 | 2,
locale?: Locale,
includeSeconds?: boolean,
addSuffix?: boolean,
unit?: 's' | 'm' | 'h' | 'd' | 'M' | 'Y',
partialMethod?: 'floor' | 'ceil' | 'round'
roundingMethod?: 'floor' | 'ceil' | 'round'
}

type Locale = {
Expand Down
16 changes: 16 additions & 0 deletions src/addDays/test.js
Expand Up @@ -31,4 +31,20 @@ describe('addDays', function () {
addDays(date, 11)
assert.deepEqual(date, new Date(2014, 8 /* Sep */, 1))
})

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

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

it('throws `RangeError` if `options.additionalDigits` is not convertable to 0, 1, 2 or undefined', function () {
// $ExpectedMistake
var block = addDays.bind(null, new Date(2014, 8 /* Sep */, 1), 10, {additionalDigits: NaN})
assert.throws(block, RangeError)
})
})
2 changes: 2 additions & 0 deletions src/addHours/index.js
Expand Up @@ -13,7 +13,9 @@ var MILLISECONDS_IN_HOUR = 3600000
* @param {Date|String|Number} date - the date to be changed
* @param {Number} amount - the amount of hours to be added
* @param {Options} [options] - the object with options. See [Options]{@link docs/Options}
* @param {0|1|2} [options.additionalDigits=2] - passed to `toDate`. See [toDate]{@link docs/toDate}
* @returns {Date} the new date with the hours added
* @throws {RangeError} `options.additionalDigits` must be 0, 1 or 2
*
* @example
* // Add 2 hours to 10 July 2014 23:00:00:
Expand Down
4 changes: 2 additions & 2 deletions src/addHours/index.js.flow
Expand Up @@ -7,13 +7,13 @@ type Interval = {
}

type Options = {
weekStartsOn?: number,
weekStartsOn?: 0 | 1 | 2 | 3 | 4 | 5 | 6,
additionalDigits?: 0 | 1 | 2,
locale?: Locale,
includeSeconds?: boolean,
addSuffix?: boolean,
unit?: 's' | 'm' | 'h' | 'd' | 'M' | 'Y',
partialMethod?: 'floor' | 'ceil' | 'round'
roundingMethod?: 'floor' | 'ceil' | 'round'
}

type Locale = {
Expand Down
16 changes: 16 additions & 0 deletions src/addHours/test.js
Expand Up @@ -35,4 +35,20 @@ describe('addHours', function () {
addHours(date, 10)
assert.deepEqual(date, new Date(2014, 6 /* Jul */, 10, 23, 0))
})

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

it('returns `Invalid Date` if the given amount is NaN', function () {
var result = addHours(new Date(2014, 6 /* Jul */, 10, 23, 0), NaN)
assert(result instanceof Date && isNaN(result))
})

it('throws `RangeError` if `options.additionalDigits` is not convertable to 0, 1, 2 or undefined', function () {
// $ExpectedMistake
var block = addHours.bind(null, new Date(2014, 6 /* Jul */, 10, 23, 0), 2, {additionalDigits: NaN})
assert.throws(block, RangeError)
})
})
2 changes: 2 additions & 0 deletions src/addISOYears/index.js
Expand Up @@ -14,7 +14,9 @@ import setISOYear from '../setISOYear/index.js'
* @param {Date|String|Number} date - the date to be changed
* @param {Number} amount - the amount of ISO week-numbering years to be added
* @param {Options} [options] - the object with options. See [Options]{@link docs/Options}
* @param {0|1|2} [options.additionalDigits=2] - passed to `toDate`. See [toDate]{@link docs/toDate}
* @returns {Date} the new date with the ISO week-numbering years added
* @throws {RangeError} `options.additionalDigits` must be 0, 1 or 2
*
* @example
* // Add 5 ISO week-numbering years to 2 July 2010:
Expand Down
4 changes: 2 additions & 2 deletions src/addISOYears/index.js.flow
Expand Up @@ -7,13 +7,13 @@ type Interval = {
}

type Options = {
weekStartsOn?: number,
weekStartsOn?: 0 | 1 | 2 | 3 | 4 | 5 | 6,
additionalDigits?: 0 | 1 | 2,
locale?: Locale,
includeSeconds?: boolean,
addSuffix?: boolean,
unit?: 's' | 'm' | 'h' | 'd' | 'M' | 'Y',
partialMethod?: 'floor' | 'ceil' | 'round'
roundingMethod?: 'floor' | 'ceil' | 'round'
}

type Locale = {
Expand Down
16 changes: 16 additions & 0 deletions src/addISOYears/test.js
Expand Up @@ -42,4 +42,20 @@ describe('addISOYears', function () {
var result = addISOYears(initialDate, 5)
assert.deepEqual(result, expectedResult)
})

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

it('returns `Invalid Date` if the given amount is NaN', function () {
var result = addISOYears(new Date(2010, 6 /* Jul */, 2), NaN)
assert(result instanceof Date && isNaN(result))
})

it('throws `RangeError` if `options.additionalDigits` is not convertable to 0, 1, 2 or undefined', function () {
// $ExpectedMistake
var block = addISOYears.bind(null, new Date(2010, 6 /* Jul */, 2), 5, {additionalDigits: NaN})
assert.throws(block, RangeError)
})
})
2 changes: 2 additions & 0 deletions src/addMilliseconds/index.js
Expand Up @@ -11,7 +11,9 @@ import toDate from '../toDate/index.js'
* @param {Date|String|Number} date - the date to be changed
* @param {Number} amount - the amount of milliseconds to be added
* @param {Options} [options] - the object with options. See [Options]{@link docs/Options}
* @param {0|1|2} [options.additionalDigits=2] - passed to `toDate`. See [toDate]{@link docs/toDate}
* @returns {Date} the new date with the milliseconds added
* @throws {RangeError} `options.additionalDigits` must be 0, 1 or 2
*
* @example
* // Add 750 milliseconds to 10 July 2014 12:45:30.000:
Expand Down
4 changes: 2 additions & 2 deletions src/addMilliseconds/index.js.flow
Expand Up @@ -7,13 +7,13 @@ type Interval = {
}

type Options = {
weekStartsOn?: number,
weekStartsOn?: 0 | 1 | 2 | 3 | 4 | 5 | 6,
additionalDigits?: 0 | 1 | 2,
locale?: Locale,
includeSeconds?: boolean,
addSuffix?: boolean,
unit?: 's' | 'm' | 'h' | 'd' | 'M' | 'Y',
partialMethod?: 'floor' | 'ceil' | 'round'
roundingMethod?: 'floor' | 'ceil' | 'round'
}

type Locale = {
Expand Down
16 changes: 16 additions & 0 deletions src/addMilliseconds/test.js
Expand Up @@ -35,4 +35,20 @@ describe('addMilliseconds', function () {
addMilliseconds(date, 250)
assert.deepEqual(date, new Date(2014, 6 /* Jul */, 10, 12, 45, 30, 0))
})

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

it('returns `Invalid Date` if the given amount is NaN', function () {
var result = addMilliseconds(new Date(2014, 6 /* Jul */, 10, 12, 45, 30, 0), NaN)
assert(result instanceof Date && isNaN(result))
})

it('throws `RangeError` if `options.additionalDigits` is not convertable to 0, 1, 2 or undefined', function () {
// $ExpectedMistake
var block = addMilliseconds.bind(null, new Date(2014, 6 /* Jul */, 10, 12, 45, 30, 0), 750, {additionalDigits: NaN})
assert.throws(block, RangeError)
})
})
2 changes: 2 additions & 0 deletions src/addMinutes/index.js
Expand Up @@ -13,7 +13,9 @@ var MILLISECONDS_IN_MINUTE = 60000
* @param {Date|String|Number} date - the date to be changed
* @param {Number} amount - the amount of minutes to be added
* @param {Options} [options] - the object with options. See [Options]{@link docs/Options}
* @param {0|1|2} [options.additionalDigits=2] - passed to `toDate`. See [toDate]{@link docs/toDate}
* @returns {Date} the new date with the minutes added
* @throws {RangeError} `options.additionalDigits` must be 0, 1 or 2
*
* @example
* // Add 30 minutes to 10 July 2014 12:00:00:
Expand Down
4 changes: 2 additions & 2 deletions src/addMinutes/index.js.flow
Expand Up @@ -7,13 +7,13 @@ type Interval = {
}

type Options = {
weekStartsOn?: number,
weekStartsOn?: 0 | 1 | 2 | 3 | 4 | 5 | 6,
additionalDigits?: 0 | 1 | 2,
locale?: Locale,
includeSeconds?: boolean,
addSuffix?: boolean,
unit?: 's' | 'm' | 'h' | 'd' | 'M' | 'Y',
partialMethod?: 'floor' | 'ceil' | 'round'
roundingMethod?: 'floor' | 'ceil' | 'round'
}

type Locale = {
Expand Down
16 changes: 16 additions & 0 deletions src/addMinutes/test.js
Expand Up @@ -35,4 +35,20 @@ describe('addMinutes', function () {
addMinutes(date, 25)
assert.deepEqual(date, new Date(2014, 6 /* Jul */, 10, 12, 0))
})

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

it('returns `Invalid Date` if the given amount is NaN', function () {
var result = addMinutes(new Date(2014, 6 /* Jul */, 10, 12, 0), NaN)
assert(result instanceof Date && isNaN(result))
})

it('throws `RangeError` if `options.additionalDigits` is not convertable to 0, 1, 2 or undefined', function () {
// $ExpectedMistake
var block = addMinutes.bind(null, new Date(2014, 6 /* Jul */, 10, 12, 0), 30, {additionalDigits: NaN})
assert.throws(block, RangeError)
})
})
2 changes: 2 additions & 0 deletions src/addMonths/index.js
Expand Up @@ -12,7 +12,9 @@ import getDaysInMonth from '../getDaysInMonth/index.js'
* @param {Date|String|Number} date - the date to be changed
* @param {Number} amount - the amount of months to be added
* @param {Options} [options] - the object with options. See [Options]{@link docs/Options}
* @param {0|1|2} [options.additionalDigits=2] - passed to `toDate`. See [toDate]{@link docs/toDate}
* @returns {Date} the new date with the months added
* @throws {RangeError} `options.additionalDigits` must be 0, 1 or 2
*
* @example
* // Add 5 months to 1 September 2014:
Expand Down
4 changes: 2 additions & 2 deletions src/addMonths/index.js.flow
Expand Up @@ -7,13 +7,13 @@ type Interval = {
}

type Options = {
weekStartsOn?: number,
weekStartsOn?: 0 | 1 | 2 | 3 | 4 | 5 | 6,
additionalDigits?: 0 | 1 | 2,
locale?: Locale,
includeSeconds?: boolean,
addSuffix?: boolean,
unit?: 's' | 'm' | 'h' | 'd' | 'M' | 'Y',
partialMethod?: 'floor' | 'ceil' | 'round'
roundingMethod?: 'floor' | 'ceil' | 'round'
}

type Locale = {
Expand Down
16 changes: 16 additions & 0 deletions src/addMonths/test.js
Expand Up @@ -48,4 +48,20 @@ describe('addMonths', function () {
var result = addMonths(initialDate, 1)
assert.deepEqual(result, expectedResult)
})

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

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

it('throws `RangeError` if `options.additionalDigits` is not convertable to 0, 1, 2 or undefined', function () {
// $ExpectedMistake
var block = addMonths.bind(null, new Date(2014, 8 /* Sep */, 1), 5, {additionalDigits: NaN})
assert.throws(block, RangeError)
})
})
2 changes: 2 additions & 0 deletions src/addQuarters/index.js
Expand Up @@ -11,7 +11,9 @@ import addMonths from '../addMonths/index.js'
* @param {Date|String|Number} date - the date to be changed
* @param {Number} amount - the amount of quarters to be added
* @param {Options} [options] - the object with options. See [Options]{@link docs/Options}
* @param {0|1|2} [options.additionalDigits=2] - passed to `toDate`. See [toDate]{@link docs/toDate}
* @returns {Date} the new date with the quarters added
* @throws {RangeError} `options.additionalDigits` must be 0, 1 or 2
*
* @example
* // Add 1 quarter to 1 September 2014:
Expand Down
4 changes: 2 additions & 2 deletions src/addQuarters/index.js.flow
Expand Up @@ -7,13 +7,13 @@ type Interval = {
}

type Options = {
weekStartsOn?: number,
weekStartsOn?: 0 | 1 | 2 | 3 | 4 | 5 | 6,
additionalDigits?: 0 | 1 | 2,
locale?: Locale,
includeSeconds?: boolean,
addSuffix?: boolean,
unit?: 's' | 'm' | 'h' | 'd' | 'M' | 'Y',
partialMethod?: 'floor' | 'ceil' | 'round'
roundingMethod?: 'floor' | 'ceil' | 'round'
}

type Locale = {
Expand Down