Skip to content

Commit

Permalink
Make format functions throw RangeError (closes #987) (#1032)
Browse files Browse the repository at this point in the history
See JavaScript's `toISOString` and Intl API for the reasoning:

```js
const date = new Date()

date.setHours('nope')
//=> NaN

date.getYear()
//=> NaN

date.toString()
//=> Invalid date

date.toISOString()
//=> RangeError: Invalid time value

new Intl.DateTimeFormat('en-US').format(date)
//=> RangeError: Invalid time value
```
  • Loading branch information
kossnocorp committed Jan 10, 2019
1 parent f6920b8 commit a239752
Show file tree
Hide file tree
Showing 11 changed files with 75 additions and 41 deletions.
8 changes: 6 additions & 2 deletions CHANGELOG.md
Expand Up @@ -683,6 +683,11 @@ for the list of changes made since `v2.0.0-alpha.1`.
are not `undefined` or have expected values.
This change is introduced for consistency with ECMAScript standard library which does the same.

- **BREAKING**: `format`, `formatDistance` (previously `distanceInWords`) and
`formatDistanceStrict` (previously `distanceInWordsStrict`) now throw
`RangeError` if one the passed arguments is invalid. It reflects behavior of
`toISOString` and Intl API. See [#1032](https://github.com/date-fns/date-fns/pull/1032).

- **BREAKING**: all functions now implicitly convert arguments by following rules:

| | date | number | string | boolean |
Expand Down Expand Up @@ -712,8 +717,7 @@ for the list of changes made since `v2.0.0-alpha.1`.

- `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.
- and `NaN` for functions that return numbers.

See tests and PRs [#460](https://github.com/date-fns/date-fns/pull/460) and
[#765](https://github.com/date-fns/date-fns/pull/765) for exact behavior.
Expand Down
2 changes: 1 addition & 1 deletion src/format/index.js
Expand Up @@ -385,7 +385,7 @@ export default function format(dirtyDate, dirtyFormatStr, dirtyOptions) {
var originalDate = toDate(dirtyDate)

if (!isValid(originalDate)) {
return 'Invalid Date'
throw new RangeError('Invalid time value')
}

// Convert the date in system timezone to the same date in UTC+00:00 timezone.
Expand Down
7 changes: 5 additions & 2 deletions src/format/test.js
Expand Up @@ -641,8 +641,11 @@ describe('format', function() {
})

describe('edge cases', function() {
it("returns String('Invalid Date') if the date isn't valid", function() {
assert(format(new Date(NaN), 'MMMM d, yyyy') === 'Invalid Date')
it('throws RangeError if the time value is invalid', () => {
assert.throws(
format.bind(null, new Date(NaN), 'MMMM d, yyyy'),
RangeError
)
})

it('handles dates before 100 AD', function() {
Expand Down
2 changes: 1 addition & 1 deletion src/formatDistance/index.js
Expand Up @@ -134,7 +134,7 @@ export default function formatDistance(dirtyDate, dirtyBaseDate, dirtyOptions) {
var comparison = compareAsc(dirtyDate, dirtyBaseDate)

if (isNaN(comparison)) {
return 'Invalid Date'
throw new RangeError('Invalid time value')
}

var localizeOptions = cloneObject(options)
Expand Down
24 changes: 15 additions & 9 deletions src/formatDistance/test.js
Expand Up @@ -274,19 +274,25 @@ describe('formatDistance', function() {
})
})

it("returns String('Invalid Date') if the first date is `Invalid Date`", function() {
var result = formatDistance(new Date(NaN), new Date(1986, 3, 7, 10, 32, 0))
assert(result === 'Invalid Date')
it('throws RangeError if the first date is `Invalid Date`', function() {
assert.throws(
formatDistance.bind(null, new Date(NaN), new Date(1986, 3, 7, 10, 32, 0)),
RangeError
)
})

it("returns String('Invalid Date') if the second date is `Invalid Date`", function() {
var result = formatDistance(new Date(1986, 3, 4, 10, 32, 0), new Date(NaN))
assert(result === 'Invalid Date')
it('throws RangeError if the second date is `Invalid Date`', function() {
assert.throws(
formatDistance.bind(null, new Date(1986, 3, 4, 10, 32, 0), new Date(NaN)),
RangeError
)
})

it("returns String('Invalid Date') if the both dates are `Invalid Date`", function() {
var result = formatDistance(new Date(NaN), new Date(NaN))
assert(result === 'Invalid Date')
it('throws RangeError if the both dates are `Invalid Date`', function() {
assert.throws(
formatDistance.bind(null, new Date(NaN), new Date(NaN)),
RangeError
)
})

it('throws TypeError exception if passed less than 2 arguments', function() {
Expand Down
2 changes: 1 addition & 1 deletion src/formatDistanceStrict/index.js
Expand Up @@ -178,7 +178,7 @@ export default function formatDistanceStrict(
var comparison = compareAsc(dirtyDate, dirtyBaseDate)

if (isNaN(comparison)) {
return 'Invalid Date'
throw new RangeError('Invalid time value')
}

var localizeOptions = cloneObject(options)
Expand Down
34 changes: 21 additions & 13 deletions src/formatDistanceStrict/test.js
Expand Up @@ -442,25 +442,33 @@ describe('formatDistanceStrict', function() {
})
})

it("returns String('Invalid Date') if the first date is `Invalid Date`", function() {
var result = formatDistanceStrict(
new Date(NaN),
new Date(1986, 3, 7, 10, 32, 0)
it('throws `RangeError` if the first date is `Invalid Date`', function() {
assert.throws(
formatDistanceStrict.bind(
null,
new Date(NaN),
new Date(1986, 3, 7, 10, 32, 0)
),
RangeError
)
assert(result === 'Invalid Date')
})

it("returns String('Invalid Date') if the second date is `Invalid Date`", function() {
var result = formatDistanceStrict(
new Date(1986, 3, 4, 10, 32, 0),
new Date(NaN)
it('throws `RangeError` if the second date is `Invalid Date`', function() {
assert.throws(
formatDistanceStrict.bind(
null,
new Date(1986, 3, 4, 10, 32, 0),
new Date(NaN)
),
RangeError
)
assert(result === 'Invalid Date')
})

it("returns String('Invalid Date') if the both dates are `Invalid Date`", function() {
var result = formatDistanceStrict(new Date(NaN), new Date(NaN))
assert(result === 'Invalid Date')
it('throws `RangeError` if the both dates are `Invalid Date`', function() {
assert.throws(
formatDistanceStrict.bind(null, new Date(NaN), new Date(NaN)),
RangeError
)
})

it("throws `RangeError` if `options.roundingMethod` is not 'floor', 'ceil', 'round' or undefined", function() {
Expand Down
2 changes: 1 addition & 1 deletion src/formatRelative/index.js
Expand Up @@ -66,7 +66,7 @@ export default function formatRelative(dirtyDate, dirtyBaseDate, dirtyOptions) {
var diff = differenceInCalendarDays(date, baseDate)

if (isNaN(diff)) {
return 'Invalid Date'
throw new RangeError('Invalid time value')
}

var token
Expand Down
26 changes: 18 additions & 8 deletions src/formatRelative/test.js
Expand Up @@ -60,19 +60,29 @@ describe('formatRelative', function() {
})

describe('edge cases', function() {
it("returns String('Invalid Date') if the date isn't valid", function() {
assert(formatRelative(new Date(NaN), baseDate) === 'Invalid Date')
it("throws RangeError if the date isn't valid", function() {
assert.throws(
formatRelative.bind(null, new Date(NaN), baseDate),
RangeError
)
})

it("returns String('Invalid Date') if the base date isn't valid", function() {
assert(
formatRelative(new Date(2017, 0 /* Jan */, 1), new Date(NaN)) ===
'Invalid Date'
it("throws RangeError if the base date isn't valid", function() {
assert.throws(
formatRelative.bind(
null,
new Date(2017, 0 /* Jan */, 1),
new Date(NaN)
),
RangeError
)
})

it("returns String('Invalid Date') if both dates aren't valid", function() {
assert(formatRelative(new Date(NaN), new Date(NaN)) === 'Invalid Date')
it("throws RangeError if both dates aren't valid", function() {
assert.throws(
formatRelative.bind(null, new Date(NaN), new Date(NaN)),
RangeError
)
})

it('handles dates before 100 AD', function() {
Expand Down
2 changes: 1 addition & 1 deletion src/lightFormat/index.js
Expand Up @@ -92,7 +92,7 @@ export default function lightFormat(dirtyDate, dirtyFormatStr) {
var originalDate = toDate(dirtyDate)

if (!isValid(originalDate)) {
return 'Invalid Date'
throw new RangeError('Invalid time value')
}

// Convert the date in system timezone to the same date in UTC+00:00 timezone.
Expand Down
7 changes: 5 additions & 2 deletions src/lightFormat/test.js
Expand Up @@ -109,8 +109,11 @@ describe('lightFormat', () => {
})
})

it("returns String('Invalid Date') if the date isn't valid", () => {
assert(lightFormat(new Date(NaN), 'MMMM d, yyyy') === 'Invalid Date')
it("throws RangeError if the date isn't valid", () => {
assert.throws(
lightFormat.bind(null, new Date(NaN), 'MMMM d, yyyy'),
RangeError
)
})

it('implicitly converts `formatString`', () => {
Expand Down

0 comments on commit a239752

Please sign in to comment.