Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 79 additions & 12 deletions src/modules/date/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,15 @@ import { toDate } from '../../internal/date';
import { assertLocaleData } from '../../internal/locale-proxy';
import { SimpleModuleBase } from '../../internal/module-base';

/**
* Small helper function to convert a number of years to an amount of milliseconds.
*
* @param years The number of years to convert to milliseconds.
*/
function yearsToMs(years: number): number {
return years * 365 * 24 * 3600 * 1000;
}

/**
* Module to generate dates (without methods requiring localized data).
*/
Expand Down Expand Up @@ -47,14 +56,18 @@ export class SimpleDateModule extends SimpleModuleBase {
* Generates a random date in the past.
*
* @param options The optional options object.
* @param options.years The range of years the date may be in the past. Defaults to `1`.
* @param options.years The range of years the date may be in the past. Either as a fixed amount of years or as a year range. Defaults to `1`.
Comment thread
ST-DDT marked this conversation as resolved.
* @param options.refDate The date to use as reference point for the newly generated date. Defaults to `faker.defaultRefDate()`.
*
* @throws {FakerError} If `years.max` is less than 0.
* @throws {FakerError} If `years.min` is greater or equal than `years.max`.
*
* @see faker.date.recent(): For generating dates in the recent past (days instead of years).
*
* @example
* faker.date.past() // '2021-12-03T05:40:44.408Z'
* faker.date.past({ years: 10 }) // '2017-10-25T21:34:19.488Z'
* faker.date.past({ years: { min: 4, max: 7 } }) // '2022-12-12T03:43:16.434Z'
* faker.date.past({ years: 10, refDate: '2020-01-01T00:00:00.000Z' }) // '2017-08-18T02:59:12.350Z'
*
* @since 8.0.0
Expand All @@ -66,7 +79,22 @@ export class SimpleDateModule extends SimpleModuleBase {
*
* @default 1
*/
years?: number;
years?:
| number
| {
/**
* The minimum amount of years the date should be in the past.
*
* @default 0
*/
min: number;
/**
* The maximum amount of years the date should be in the past.
*
* @default 1
*/
max: number;
};
/**
* The date to use as reference point for the newly generated date.
*
Expand All @@ -75,32 +103,46 @@ export class SimpleDateModule extends SimpleModuleBase {
refDate?: string | Date | number;
} = {}
): Date {
const { years = 1, refDate = this.faker.defaultRefDate() } = options;
const { refDate = this.faker.defaultRefDate() } = options;
let { years = 1 } = options;
if (typeof years === 'number') {
years = { min: 0, max: years };
}

if (years <= 0) {
if (years.max <= 0) {
throw new FakerError('Years must be greater than 0.');
}
Comment thread
ST-DDT marked this conversation as resolved.

if (years.min >= years.max) {
throw new FakerError(
'The maximum amount of years must be greater than the minimum amount of years.'
);
}

const time = toDate(refDate).getTime();

return this.between({
from: time - years * 365 * 24 * 3600 * 1000,
to: time - 1000,
from: time - yearsToMs(years.max),
to: time - yearsToMs(years.min) - 1000,
Comment thread
ST-DDT marked this conversation as resolved.
});
}

/**
* Generates a random date in the future.
*
* @param options The optional options object.
* @param options.years The range of years the date may be in the future. Defaults to `1`.
* @param options.years The range of years the date may be in the future. Either as a fixed amount of years or as a year range. Defaults to `1`.
* @param options.refDate The date to use as reference point for the newly generated date. Defaults to `faker.defaultRefDate()`.
*
* @throws {FakerError} If `years.max` is less than 0.
* @throws {FakerError} If `years.min` is greater or equal than `years.max`.
*
* @see faker.date.soon(): For generating dates in the near future (days instead of years).
*
* @example
* faker.date.future() // '2022-11-19T05:52:49.100Z'
* faker.date.future({ years: 10 }) // '2030-11-23T09:38:28.710Z'
* faker.date.future({ years: { min: 4, max: 7 } }) // '2031-05-21T05:49:21.116Z'
* faker.date.future({ years: 10, refDate: '2020-01-01T00:00:00.000Z' }) // '2020-12-13T22:45:10.252Z'
*
* @since 8.0.0
Expand All @@ -112,7 +154,22 @@ export class SimpleDateModule extends SimpleModuleBase {
*
* @default 1
*/
years?: number;
years?:
| number
| {
/**
* The minimum amount of years the date should be in the future.
*
* @default 0
*/
min: number;
/**
* The maximum amount of years the date should be in the future.
*
* @default 1
*/
max: number;
};
/**
* The date to use as reference point for the newly generated date.
*
Expand All @@ -121,17 +178,27 @@ export class SimpleDateModule extends SimpleModuleBase {
refDate?: string | Date | number;
} = {}
): Date {
const { years = 1, refDate = this.faker.defaultRefDate() } = options;
const { refDate = this.faker.defaultRefDate() } = options;
let { years = 1 } = options;
if (typeof years === 'number') {
years = { min: 0, max: years };
}

if (years <= 0) {
if (years.max <= 0) {
throw new FakerError('Years must be greater than 0.');
}

if (years.min >= years.max) {
throw new FakerError(
'The maximum amount of years must be greater than the minimum amount of years.'
);
}

const time = toDate(refDate).getTime();

return this.between({
from: time + 1000,
to: time + years * 365 * 24 * 3600 * 1000,
from: time + yearsToMs(years.min) + 1000,
to: time + yearsToMs(years.max),
});
}

Expand Down
24 changes: 18 additions & 6 deletions test/modules/__snapshots__/date.spec.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,9 @@ exports[`date > 42 > future > with only number refDate 1`] = `2021-07-08T10:07:3

exports[`date > 42 > future > with only string refDate 1`] = `2021-07-08T10:07:33.524Z`;

exports[`date > 42 > future > with value 1`] = `2024-11-19T18:52:08.216Z`;
exports[`date > 42 > future > with value numeric 1`] = `2024-11-19T18:52:08.216Z`;
Comment thread
ST-DDT marked this conversation as resolved.

exports[`date > 42 > future > with value range 1`] = `2027-07-06T01:53:51.028Z`;

exports[`date > 42 > month > noArgs 1`] = `"January"`;

Expand All @@ -97,7 +99,9 @@ exports[`date > 42 > past > with only number refDate 1`] = `2020-07-08T10:07:32.

exports[`date > 42 > past > with only string refDate 1`] = `2020-07-08T10:07:32.524Z`;

exports[`date > 42 > past > with value 1`] = `2014-11-22T18:52:07.216Z`;
exports[`date > 42 > past > with value numeric 1`] = `2014-11-22T18:52:07.216Z`;

exports[`date > 42 > past > with value range 1`] = `2012-07-09T01:53:50.028Z`;

exports[`date > 42 > recent > with only Date refDate 1`] = `2021-02-21T02:08:35.603Z`;

Expand Down Expand Up @@ -207,7 +211,9 @@ exports[`date > 1211 > future > with only number refDate 1`] = `2022-01-26T14:59

exports[`date > 1211 > future > with only string refDate 1`] = `2022-01-26T14:59:27.356Z`;

exports[`date > 1211 > future > with value 1`] = `2030-06-03T19:31:11.518Z`;
exports[`date > 1211 > future > with value numeric 1`] = `2030-06-03T19:31:11.518Z`;

exports[`date > 1211 > future > with value range 1`] = `2032-06-28T21:40:59.944Z`;

exports[`date > 1211 > month > noArgs 1`] = `"September"`;

Expand All @@ -223,7 +229,9 @@ exports[`date > 1211 > past > with only number refDate 1`] = `2021-01-26T14:59:2

exports[`date > 1211 > past > with only string refDate 1`] = `2021-01-26T14:59:26.356Z`;

exports[`date > 1211 > past > with value 1`] = `2020-06-05T19:31:10.518Z`;
exports[`date > 1211 > past > with value numeric 1`] = `2020-06-05T19:31:10.518Z`;

exports[`date > 1211 > past > with value range 1`] = `2017-07-02T21:40:58.944Z`;

exports[`date > 1211 > recent > with only Date refDate 1`] = `2021-02-21T15:26:18.924Z`;

Expand Down Expand Up @@ -331,7 +339,9 @@ exports[`date > 1337 > future > with only number refDate 1`] = `2021-05-28T08:29

exports[`date > 1337 > future > with only string refDate 1`] = `2021-05-28T08:29:26.600Z`;

exports[`date > 1337 > future > with value 1`] = `2023-10-06T02:30:57.962Z`;
exports[`date > 1337 > future > with value numeric 1`] = `2023-10-06T02:30:57.962Z`;

exports[`date > 1337 > future > with value range 1`] = `2026-07-01T11:10:47.810Z`;

exports[`date > 1337 > month > noArgs 1`] = `"February"`;

Expand All @@ -347,7 +357,9 @@ exports[`date > 1337 > past > with only number refDate 1`] = `2020-05-28T08:29:2

exports[`date > 1337 > past > with only string refDate 1`] = `2020-05-28T08:29:25.600Z`;

exports[`date > 1337 > past > with value 1`] = `2013-10-08T02:30:56.962Z`;
exports[`date > 1337 > past > with value numeric 1`] = `2013-10-08T02:30:56.962Z`;

exports[`date > 1337 > past > with value range 1`] = `2011-07-05T11:10:46.810Z`;

exports[`date > 1337 > recent > with only Date refDate 1`] = `2021-02-20T23:26:34.381Z`;

Expand Down
107 changes: 104 additions & 3 deletions test/modules/date.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ describe('date', () => {
.it('with only number refDate', {
refDate: new Date(refDate).getTime(),
})
.it('with value', { years: 10, refDate });
.it('with value numeric', { years: 10, refDate })
.it('with value range', { years: { min: 3, max: 12 }, refDate });
});

t.describeEach(
Expand Down Expand Up @@ -190,13 +191,60 @@ describe('date', () => {
expect(date).greaterThanOrEqual(yearsAgo);
});

it('should return a date between 20 and 40 years in the past', () => {
const today = new Date();
const yearsAgoMax = 40;
const yearAgoMax = new Date(today);
yearAgoMax.setFullYear(yearAgoMax.getFullYear() - yearsAgoMax);

const yearsAgoMin = 20;
const yearAgoMin = new Date(today);
yearAgoMin.setFullYear(yearAgoMin.getFullYear() - yearsAgoMin);

const date = faker.date.past({
years: { min: yearsAgoMin, max: yearsAgoMax },
});

expect(date).lessThan(today);
expect(date).lessThan(yearAgoMin);
expect(date).greaterThanOrEqual(yearAgoMax);
});

it('should throw an error when years = 0', () => {
const refDate = new Date();
expect(() =>
faker.date.past({ years: 0, refDate: refDate.toISOString() })
).toThrow(new FakerError('Years must be greater than 0.'));
});

it('should throw an error when years.min > years.max', () => {
const refDate = new Date();
expect(() =>
faker.date.past({
years: { min: 3, max: 2 },
refDate: refDate.toISOString(),
})
).toThrow(
new FakerError(
'The maximum amount of years must be greater than the minimum amount of years.'
)
);
});

it('should throw an error when years.min = years.max', () => {
const refDate = new Date();
expect(() =>
faker.date.past({
years: { min: 6, max: 6 },
refDate: refDate.toISOString(),
})
).toThrow(
new FakerError(
'The maximum amount of years must be greater than the minimum amount of years.'
)
);
});

it.each(converterMap)(
'should return a past date relative to given refDate',
(converter) => {
Expand All @@ -216,9 +264,34 @@ describe('date', () => {

describe('future()', () => {
it('should return a date 75 years into the future', () => {
const date = faker.date.future({ years: 75 });
const today = new Date();
const yearsUntilMax = 75;
const yearUntilMax = new Date(today);
yearUntilMax.setFullYear(yearUntilMax.getFullYear() + yearsUntilMax);

expect(date).greaterThan(new Date());
const date = faker.date.future({ years: yearsUntilMax });

expect(date).greaterThan(today);
expect(date).lessThanOrEqual(yearUntilMax);
});

it('should return a date between 20 and 40 years in the future', () => {
const today = new Date();
const yearsUntilMin = 20;
const yearUntilMin = new Date(today);
yearUntilMin.setFullYear(yearUntilMin.getFullYear() + yearsUntilMin);

const yearsUntilMax = 40;
const yearUntilMax = new Date(today);
yearUntilMax.setFullYear(yearUntilMax.getFullYear() + yearsUntilMax);

const date = faker.date.future({
years: { min: yearsUntilMin, max: yearsUntilMax },
});

expect(date).greaterThan(today);
expect(date).greaterThan(yearUntilMin);
expect(date).lessThanOrEqual(yearUntilMax);
});

it('should throw an error when years = 0', () => {
Expand All @@ -228,6 +301,34 @@ describe('date', () => {
).toThrow(new FakerError('Years must be greater than 0.'));
});

it('should throw an error when years.min > years.max', () => {
const refDate = new Date();
expect(() =>
faker.date.future({
years: { min: 3, max: 2 },
refDate: refDate.toISOString(),
})
).toThrow(
new FakerError(
'The maximum amount of years must be greater than the minimum amount of years.'
)
);
});

it('should throw an error when years.min = years.max', () => {
const refDate = new Date();
expect(() =>
faker.date.future({
years: { min: 6, max: 6 },
refDate: refDate.toISOString(),
})
).toThrow(
new FakerError(
'The maximum amount of years must be greater than the minimum amount of years.'
)
);
});

it.each(converterMap)(
'should return a date 75 years after the date given',
(converter) => {
Expand Down
Loading