Skip to content

Commit

Permalink
refactor(date)!: stricter error handling of between (#2719)
Browse files Browse the repository at this point in the history
  • Loading branch information
matthewmayer committed Mar 28, 2024
1 parent 47f008a commit da35c51
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 3 deletions.
3 changes: 3 additions & 0 deletions docs/guide/upgrading_v9/2711.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
### Require `from` and `to` in `faker.date.between()` and `betweens()`

Previously, in `faker.date.between()` and `faker.date.betweens()` if the `from` or `to` parameter was omitted (in Javascript) or an invalid date (in Javascript or Typescript), they would default to the current date or reference date. Now, both boundaries must now be given explictly. If you still need the old behavior, you can pass `Date.now()` or the reference date for `from` or `to`.
34 changes: 31 additions & 3 deletions src/modules/date/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,10 +155,13 @@ export class SimpleDateModule extends SimpleModuleBase {
/**
* Generates a random date between the given boundaries.
*
* @param options The optional options object.
* @param options The options object.
* @param options.from The early date boundary.
* @param options.to The late date boundary.
*
* @throws If `from` or `to` are not provided.
* @throws If `from` is after `to`.
*
* @example
* faker.date.between({ from: '2020-01-01T00:00:00.000Z', to: '2030-01-01T00:00:00.000Z' }) // '2026-05-16T02:22:53.002Z'
*
Expand All @@ -174,22 +177,35 @@ export class SimpleDateModule extends SimpleModuleBase {
*/
to: string | Date | number;
}): Date {
// TODO @matthewmayer 2023-03-27: Consider removing in v10 as this check is only needed in JS
if (options == null || options.from == null || options.to == null) {
throw new FakerError(
'Must pass an options object with `from` and `to` values.'
);
}

const { from, to } = options;

const fromMs = toDate(from, 'from').getTime();
const toMs = toDate(to, 'to').getTime();
if (fromMs > toMs) {
throw new FakerError('`from` date must be before `to` date.');
}

return new Date(this.faker.number.int({ min: fromMs, max: toMs }));
}

/**
* Generates random dates between the given boundaries. The dates will be returned in an array sorted in chronological order.
*
* @param options The optional options object.
* @param options The options object.
* @param options.from The early date boundary.
* @param options.to The late date boundary.
* @param options.count The number of dates to generate. Defaults to `3`.
*
* @throws If `from` or `to` are not provided.
* @throws If `from` is after `to`.
*
* @example
* faker.date.betweens({ from: '2020-01-01T00:00:00.000Z', to: '2030-01-01T00:00:00.000Z' })
* // [
Expand Down Expand Up @@ -235,8 +251,14 @@ export class SimpleDateModule extends SimpleModuleBase {
max: number;
};
}): Date[] {
const { from, to, count = 3 } = options;
// TODO @matthewmayer 2023-03-27: Consider removing in v10 as this check is only needed in JS
if (options == null || options.from == null || options.to == null) {
throw new FakerError(
'Must pass an options object with `from` and `to` values.'
);
}

const { from, to, count = 3 } = options;
return this.faker.helpers
.multiple(() => this.between({ from, to }), { count })
.sort((a, b) => a.getTime() - b.getTime());
Expand Down Expand Up @@ -433,6 +455,12 @@ export class SimpleDateModule extends SimpleModuleBase {
*
* For more control, any of these methods can be customized with further options, or use [`between()`](https://fakerjs.dev/api/date.html#between) to generate a single date between two dates, or [`betweens()`](https://fakerjs.dev/api/date.html#betweens) for multiple dates.
*
* Dates can be specified as Javascript Date objects, strings or UNIX timestamps.
* For example to generate a date between 1st January 2000 and now, use:
* ```ts
* faker.date.between({ from: '2000-01-01', to: Date.now() });
* ```
*
* You can generate random localized month and weekday names using [`month()`](https://fakerjs.dev/api/date.html#month) and [`weekday()`](https://fakerjs.dev/api/date.html#weekday).
*
* These methods have additional concerns about reproducibility, see [Reproducible Results](https://fakerjs.dev/guide/usage.html#reproducible-results).
Expand Down
46 changes: 46 additions & 0 deletions test/modules/date.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,32 @@ describe('date', () => {
expect(date).lessThan(to);
}
);

it('should throw an error when from is after to', () => {
expect(() =>
faker.date.between({
from: '2000-01-01',
to: '1990-01-01',
})
).toThrow(new FakerError('`from` date must be before `to` date.'));
});

it('should allow date 0 (start of UNIX epoch)', () => {
const date = faker.date.between({
from: 0,
to: '1970-12-31',
});
expect(date).greaterThan(new Date(0));
});

it('should throw an error if to is invalid', () => {
expect(() =>
faker.date.between({
from: '1990-01-01',
to: 'not-a-date',
})
).toThrow(new FakerError('Invalid to date: not-a-date'));
});
});

describe('betweens()', () => {
Expand Down Expand Up @@ -325,6 +351,26 @@ describe('date', () => {
expect(dates.at(-1)).lessThan(to);
}
);

it('should throw an error when from is after to', () => {
expect(() =>
faker.date.betweens({
from: '2000-01-01',
to: '1990-01-01',
count: 3,
})
).toThrow(new FakerError('`from` date must be before `to` date.'));
});

it('should throw an error if to is invalid', () => {
expect(() =>
faker.date.betweens({
from: '1990-01-01',
to: 'not-a-date',
count: 3,
})
).toThrow(new FakerError('Invalid to date: not-a-date'));
});
});

describe('recent()', () => {
Expand Down

0 comments on commit da35c51

Please sign in to comment.