Commit 772ee696 authored by Nathan Friend's avatar Nathan Friend Committed by Jose Ivan Vargas

Add UTC support to date add/subtract utilities

This commit update all date addition/subtraction utilities to optionally
support perfoming the calculation with UTC dates, which ignores
Daylight Saving Time.
parent b1a936ba
......@@ -676,69 +676,127 @@ export const secondsToHours = (offset) => {
};
/**
* Returns the date n days after the date provided
* Returns the date `n` days after the date provided
*
* @param {Date} date the initial date
* @param {Number} numberOfDays number of days after
* @return {Date} the date following the date provided
* @param {Object} [options={}] Additional options for this calculation
* @param {boolean} [options.utc=false] Perform the calculation using UTC dates.
* This will cause Daylight Saving Time to be ignored. Defaults to `false`
* if not provided, which causes the calculation to be performed in the
* user's timezone.
*
* @return {Date} A `Date` object `n` days after the provided `Date`
*/
export const nDaysAfter = (date, numberOfDays) =>
new Date(newDate(date)).setDate(date.getDate() + numberOfDays);
export const nDaysAfter = (date, numberOfDays, { utc = false } = {}) => {
const clone = newDate(date);
const cloneValue = utc
? clone.setUTCDate(date.getUTCDate() + numberOfDays)
: clone.setDate(date.getDate() + numberOfDays);
return new Date(cloneValue);
};
/**
* Returns the date n days before the date provided
* Returns the date `n` days before the date provided
*
* @param {Date} date the initial date
* @param {Number} numberOfDays number of days before
* @return {Date} the date preceding the date provided
* @param {Object} [options={}] Additional options for this calculation
* @param {boolean} [options.utc=false] Perform the calculation using UTC dates.
* This will cause Daylight Saving Time to be ignored. Defaults to `false`
* if not provided, which causes the calculation to be performed in the
* user's timezone.
* @return {Date} A `Date` object `n` days before the provided `Date`
*/
export const nDaysBefore = (date, numberOfDays) => nDaysAfter(date, -numberOfDays);
export const nDaysBefore = (date, numberOfDays, options) =>
nDaysAfter(date, -numberOfDays, options);
/**
* Returns the date n weeks after the date provided
* Returns the date `n` weeks after the date provided
*
* @param {Date} date the initial date
* @param {Number} numberOfWeeks number of weeks after
* @return {Date} the date following the date provided
* @param {Object} [options={}] Additional options for this calculation
* @param {boolean} [options.utc=false] Perform the calculation using UTC dates.
* This will cause Daylight Saving Time to be ignored. Defaults to `false`
* if not provided, which causes the calculation to be performed in the
* user's timezone.
*
* @return {Date} A `Date` object `n` weeks after the provided `Date`
*/
export const nWeeksAfter = (date, numberOfWeeks) =>
new Date(newDate(date)).setDate(date.getDate() + DAYS_IN_WEEK * numberOfWeeks);
export const nWeeksAfter = (date, numberOfWeeks, options) =>
nDaysAfter(date, DAYS_IN_WEEK * numberOfWeeks, options);
/**
* Returns the date n weeks before the date provided
* Returns the date `n` weeks before the date provided
*
* @param {Date} date the initial date
* @param {Number} numberOfWeeks number of weeks before
* @return {Date} the date following the date provided
* @param {Object} [options={}] Additional options for this calculation
* @param {boolean} [options.utc=false] Perform the calculation using UTC dates.
* This will cause Daylight Saving Time to be ignored. Defaults to `false`
* if not provided, which causes the calculation to be performed in the
* user's timezone.
*
* @return {Date} A `Date` object `n` weeks before the provided `Date`
*/
export const nWeeksBefore = (date, numberOfWeeks) => nWeeksAfter(date, -numberOfWeeks);
export const nWeeksBefore = (date, numberOfWeeks, options) =>
nWeeksAfter(date, -numberOfWeeks, options);
/**
* Returns the date n months after the date provided
* Returns the date `n` months after the date provided
*
* @param {Date} date the initial date
* @param {Number} numberOfMonths number of months after
* @return {Date} the date following the date provided
* @param {Object} [options={}] Additional options for this calculation
* @param {boolean} [options.utc=false] Perform the calculation using UTC dates.
* This will cause Daylight Saving Time to be ignored. Defaults to `false`
* if not provided, which causes the calculation to be performed in the
* user's timezone.
*
* @return {Date} A `Date` object `n` months after the provided `Date`
*/
export const nMonthsAfter = (date, numberOfMonths) =>
new Date(newDate(date)).setMonth(date.getMonth() + numberOfMonths);
export const nMonthsAfter = (date, numberOfMonths, { utc = false } = {}) => {
const clone = newDate(date);
const cloneValue = utc
? clone.setUTCMonth(date.getUTCMonth() + numberOfMonths)
: clone.setMonth(date.getMonth() + numberOfMonths);
return new Date(cloneValue);
};
/**
* Returns the date n months before the date provided
* Returns the date `n` months before the date provided
*
* @param {Date} date the initial date
* @param {Number} numberOfMonths number of months before
* @return {Date} the date preceding the date provided
* @param {Object} [options={}] Additional options for this calculation
* @param {boolean} [options.utc=false] Perform the calculation using UTC dates.
* This will cause Daylight Saving Time to be ignored. Defaults to `false`
* if not provided, which causes the calculation to be performed in the
* user's timezone.
*
* @return {Date} A `Date` object `n` months before the provided `Date`
*/
export const nMonthsBefore = (date, numberOfMonths) => nMonthsAfter(date, -numberOfMonths);
export const nMonthsBefore = (date, numberOfMonths, options) =>
nMonthsAfter(date, -numberOfMonths, options);
/**
* Returns the date after the date provided
*
* @param {Date} date the initial date
* @param {Object} [options={}] Additional options for this calculation
* @param {boolean} [options.utc=false] Perform the calculation using UTC dates.
* This will cause Daylight Saving Time to be ignored. Defaults to `false`
* if not provided, which causes the calculation to be performed in the
* user's timezone.
*
* @return {Date} the date following the date provided
*/
export const dayAfter = (date) => new Date(newDate(date).setDate(date.getDate() + 1));
export const dayAfter = (date, options) => nDaysAfter(date, 1, options);
/**
* Mimics the behaviour of the rails distance_of_time_in_words function
......@@ -933,3 +991,22 @@ export const isToday = (date) => {
date.getFullYear() === today.getFullYear()
);
};
/**
* Returns the start of the provided day
*
* @param {Object} [options={}] Additional options for this calculation
* @param {boolean} [options.utc=false] Perform the calculation using UTC time.
* If `true`, the time returned will be midnight UTC. If `false` (the default)
* the time returned will be midnight in the user's local time.
*
* @returns {Date} A new `Date` object that represents the start of the day
* of the provided date
*/
export const getStartOfDay = (date, { utc = false } = {}) => {
const clone = newDate(date);
const cloneValue = utc ? clone.setUTCHours(0, 0, 0, 0) : clone.setHours(0, 0, 0, 0);
return new Date(cloneValue);
};
......@@ -76,7 +76,7 @@ export default {
query: getShiftsForRotations,
variables() {
const startsAt = this.timeframeStartDate;
const endsAt = new Date(nWeeksAfter(startsAt, 2));
const endsAt = nWeeksAfter(startsAt, 2);
return {
projectPath: this.projectPath,
......@@ -116,7 +116,7 @@ export default {
case PRESET_TYPES.WEEKS: {
const firstDayOfTheLastWeek = this.timeframe[this.timeframe.length - 1];
const firstDayOfTheNextTimeframe = nWeeksAfter(firstDayOfTheLastWeek, 1);
const lastDayOfTimeframe = nDaysBefore(new Date(firstDayOfTheNextTimeframe), 1);
const lastDayOfTimeframe = nDaysBefore(firstDayOfTheNextTimeframe, 1);
return `${formatDate(this.timeframe[0], 'mmmm d')} - ${formatDate(
lastDayOfTimeframe,
......@@ -142,10 +142,10 @@ export default {
updateToViewPreviousTimeframe() {
switch (this.presetType) {
case PRESET_TYPES.DAYS:
this.timeframeStartDate = new Date(nDaysBefore(this.timeframeStartDate, 1));
this.timeframeStartDate = nDaysBefore(this.timeframeStartDate, 1);
break;
case PRESET_TYPES.WEEKS:
this.timeframeStartDate = new Date(nWeeksBefore(this.timeframeStartDate, 2));
this.timeframeStartDate = nWeeksBefore(this.timeframeStartDate, 2);
break;
default:
break;
......@@ -154,10 +154,10 @@ export default {
updateToViewNextTimeframe() {
switch (this.presetType) {
case PRESET_TYPES.DAYS:
this.timeframeStartDate = new Date(nDaysAfter(this.timeframeStartDate, 1));
this.timeframeStartDate = nDaysAfter(this.timeframeStartDate, 1);
break;
case PRESET_TYPES.WEEKS:
this.timeframeStartDate = new Date(nWeeksAfter(this.timeframeStartDate, 2));
this.timeframeStartDate = nWeeksAfter(this.timeframeStartDate, 2);
break;
default:
break;
......
......@@ -35,7 +35,7 @@ export default {
},
computed: {
currentTimeframeEndsAt() {
return new Date(nDaysAfter(this.timeframeItem, 1));
return nDaysAfter(this.timeframeItem, 1);
},
hoursUntilEndOfTimeFrame() {
return HOURS_IN_DAY - new Date(this.shiftRangeOverlap.overlapStartDate).getHours();
......
......@@ -35,7 +35,7 @@ export default {
},
computed: {
currentTimeframeEndsAt() {
return new Date(nDaysAfter(this.timeframeItem, DAYS_IN_DATE_WEEK));
return nDaysAfter(this.timeframeItem, DAYS_IN_DATE_WEEK);
},
daysUntilEndOfTimeFrame() {
return (
......
......@@ -6,9 +6,9 @@ import { LAST_WEEK, LAST_MONTH, LAST_90_DAYS } from './constants';
// Compute all relative dates based on the _beginning_ of today
const startOfToday = new Date(new Date().setHours(0, 0, 0, 0));
const lastWeek = new Date(nDaysBefore(startOfToday, 7));
const lastMonth = new Date(nMonthsBefore(startOfToday, 1));
const last90Days = new Date(nDaysBefore(startOfToday, 90));
const lastWeek = nDaysBefore(startOfToday, 7);
const lastMonth = nMonthsBefore(startOfToday, 1);
const last90Days = nDaysBefore(startOfToday, 90);
const apiDateFormatString = 'isoDateTime';
const titleDateFormatString = 'mmm d';
const sharedRequestParams = {
......
......@@ -584,22 +584,6 @@ describe('secondsToMilliseconds', () => {
});
});
describe('dayAfter', () => {
const date = new Date('2019-07-16T00:00:00.000Z');
it('returns the following date', () => {
const nextDay = datetimeUtility.dayAfter(date);
const expectedNextDate = new Date('2019-07-17T00:00:00.000Z');
expect(nextDay).toStrictEqual(expectedNextDate);
});
it('does not modifiy the original date', () => {
datetimeUtility.dayAfter(date);
expect(date).toStrictEqual(new Date('2019-07-16T00:00:00.000Z'));
});
});
describe('secondsToDays', () => {
it('converts seconds to days correctly', () => {
expect(datetimeUtility.secondsToDays(0)).toBe(0);
......@@ -608,132 +592,214 @@ describe('secondsToDays', () => {
});
});
describe('nDaysAfter', () => {
const date = new Date('2019-07-16T00:00:00.000Z');
describe('date addition/subtraction methods', () => {
beforeEach(() => {
timezoneMock.register('US/Eastern');
});
afterEach(() => {
timezoneMock.unregister();
});
describe('dayAfter', () => {
const input = '2019-03-10T00:00:00.000Z';
const expectedLocalResult = '2019-03-10T23:00:00.000Z';
const expectedUTCResult = '2019-03-11T00:00:00.000Z';
it.each`
numberOfDays | expectedResult
${1} | ${new Date('2019-07-17T00:00:00.000Z').valueOf()}
${90} | ${new Date('2019-10-14T00:00:00.000Z').valueOf()}
${-1} | ${new Date('2019-07-15T00:00:00.000Z').valueOf()}
${0} | ${date.valueOf()}
${0.9} | ${date.valueOf()}
inputAsString | options | expectedAsString
${input} | ${undefined} | ${expectedLocalResult}
${input} | ${{}} | ${expectedLocalResult}
${input} | ${{ utc: false }} | ${expectedLocalResult}
${input} | ${{ utc: true }} | ${expectedUTCResult}
`(
'returns the date $numberOfDays day(s) after the provided date',
({ numberOfDays, expectedResult }) => {
expect(datetimeUtility.nDaysAfter(date, numberOfDays)).toBe(expectedResult);
'when the provided date is $inputAsString and the options parameter is $options, returns $expectedAsString',
({ inputAsString, options, expectedAsString }) => {
const inputDate = new Date(inputAsString);
const actual = datetimeUtility.dayAfter(inputDate, options);
expect(actual.toISOString()).toBe(expectedAsString);
},
);
});
describe('nDaysBefore', () => {
const date = new Date('2019-07-16T00:00:00.000Z');
it('does not modifiy the original date', () => {
const inputDate = new Date(input);
datetimeUtility.dayAfter(inputDate);
expect(inputDate.toISOString()).toBe(input);
});
});
describe('nDaysAfter', () => {
const input = '2019-07-16T00:00:00.000Z';
it.each`
numberOfDays | expectedResult
${1} | ${new Date('2019-07-15T00:00:00.000Z').valueOf()}
${90} | ${new Date('2019-04-17T00:00:00.000Z').valueOf()}
${-1} | ${new Date('2019-07-17T00:00:00.000Z').valueOf()}
${0} | ${date.valueOf()}
${0.9} | ${new Date('2019-07-15T00:00:00.000Z').valueOf()}
inputAsString | numberOfDays | options | expectedAsString
${input} | ${1} | ${undefined} | ${'2019-07-17T00:00:00.000Z'}
${input} | ${-1} | ${undefined} | ${'2019-07-15T00:00:00.000Z'}
${input} | ${0} | ${undefined} | ${'2019-07-16T00:00:00.000Z'}
${input} | ${0.9} | ${undefined} | ${'2019-07-16T00:00:00.000Z'}
${input} | ${120} | ${undefined} | ${'2019-11-13T01:00:00.000Z'}
${input} | ${120} | ${{}} | ${'2019-11-13T01:00:00.000Z'}
${input} | ${120} | ${{ utc: false }} | ${'2019-11-13T01:00:00.000Z'}
${input} | ${120} | ${{ utc: true }} | ${'2019-11-13T00:00:00.000Z'}
`(
'returns the date $numberOfDays day(s) before the provided date',
({ numberOfDays, expectedResult }) => {
expect(datetimeUtility.nDaysBefore(date, numberOfDays)).toBe(expectedResult);
'when the provided date is $inputAsString, numberOfDays is $numberOfDays, and the options parameter is $options, returns $expectedAsString',
({ inputAsString, numberOfDays, options, expectedAsString }) => {
const inputDate = new Date(inputAsString);
const actual = datetimeUtility.nDaysAfter(inputDate, numberOfDays, options);
expect(actual.toISOString()).toBe(expectedAsString);
},
);
});
});
describe('nWeeksAfter', () => {
const date = new Date('2021-07-16T00:00:00.000Z');
describe('nDaysBefore', () => {
const input = '2019-07-16T00:00:00.000Z';
it.each`
numberOfWeeks | expectedResult
${1} | ${new Date('2021-07-23T00:00:00.000Z').valueOf()}
${3} | ${new Date('2021-08-06T00:00:00.000Z').valueOf()}
${-1} | ${new Date('2021-07-09T00:00:00.000Z').valueOf()}
${0} | ${date.valueOf()}
${0.6} | ${new Date('2021-07-20T00:00:00.000Z').valueOf()}
inputAsString | numberOfDays | options | expectedAsString
${input} | ${1} | ${undefined} | ${'2019-07-15T00:00:00.000Z'}
${input} | ${-1} | ${undefined} | ${'2019-07-17T00:00:00.000Z'}
${input} | ${0} | ${undefined} | ${'2019-07-16T00:00:00.000Z'}
${input} | ${0.9} | ${undefined} | ${'2019-07-15T00:00:00.000Z'}
${input} | ${180} | ${undefined} | ${'2019-01-17T01:00:00.000Z'}
${input} | ${180} | ${{}} | ${'2019-01-17T01:00:00.000Z'}
${input} | ${180} | ${{ utc: false }} | ${'2019-01-17T01:00:00.000Z'}
${input} | ${180} | ${{ utc: true }} | ${'2019-01-17T00:00:00.000Z'}
`(
'returns the date $numberOfWeeks week(s) after the provided date',
({ numberOfWeeks, expectedResult }) => {
expect(datetimeUtility.nWeeksAfter(date, numberOfWeeks)).toBe(expectedResult);
'when the provided date is $inputAsString, numberOfDays is $numberOfDays, and the options parameter is $options, returns $expectedAsString',
({ inputAsString, numberOfDays, options, expectedAsString }) => {
const inputDate = new Date(inputAsString);
const actual = datetimeUtility.nDaysBefore(inputDate, numberOfDays, options);
expect(actual.toISOString()).toBe(expectedAsString);
},
);
});
});
describe('nWeeksBefore', () => {
const date = new Date('2021-07-16T00:00:00.000Z');
describe('nWeeksAfter', () => {
const input = '2021-07-16T00:00:00.000Z';
it.each`
numberOfWeeks | expectedResult
${1} | ${new Date('2021-07-09T00:00:00.000Z').valueOf()}
${3} | ${new Date('2021-06-25T00:00:00.000Z').valueOf()}
${-1} | ${new Date('2021-07-23T00:00:00.000Z').valueOf()}
${0} | ${date.valueOf()}
${0.6} | ${new Date('2021-07-11T00:00:00.000Z').valueOf()}
inputAsString | numberOfWeeks | options | expectedAsString
${input} | ${1} | ${undefined} | ${'2021-07-23T00:00:00.000Z'}
${input} | ${3} | ${undefined} | ${'2021-08-06T00:00:00.000Z'}
${input} | ${-1} | ${undefined} | ${'2021-07-09T00:00:00.000Z'}
${input} | ${0} | ${undefined} | ${'2021-07-16T00:00:00.000Z'}
${input} | ${0.6} | ${undefined} | ${'2021-07-20T00:00:00.000Z'}
${input} | ${18} | ${undefined} | ${'2021-11-19T01:00:00.000Z'}
${input} | ${18} | ${{}} | ${'2021-11-19T01:00:00.000Z'}
${input} | ${18} | ${{ utc: false }} | ${'2021-11-19T01:00:00.000Z'}
${input} | ${18} | ${{ utc: true }} | ${'2021-11-19T00:00:00.000Z'}
`(
'returns the date $numberOfWeeks week(s) before the provided date',
({ numberOfWeeks, expectedResult }) => {
expect(datetimeUtility.nWeeksBefore(date, numberOfWeeks)).toBe(expectedResult);
'when the provided date is $inputAsString, numberOfWeeks is $numberOfWeeks, and the options parameter is $options, returns $expectedAsString',
({ inputAsString, numberOfWeeks, options, expectedAsString }) => {
const inputDate = new Date(inputAsString);
const actual = datetimeUtility.nWeeksAfter(inputDate, numberOfWeeks, options);
expect(actual.toISOString()).toBe(expectedAsString);
},
);
});
});
describe('nWeeksBefore', () => {
const input = '2021-07-16T00:00:00.000Z';
describe('nMonthsAfter', () => {
it.each`
inputAsString | numberOfWeeks | options | expectedAsString
${input} | ${1} | ${undefined} | ${'2021-07-09T00:00:00.000Z'}
${input} | ${3} | ${undefined} | ${'2021-06-25T00:00:00.000Z'}
${input} | ${-1} | ${undefined} | ${'2021-07-23T00:00:00.000Z'}
${input} | ${0} | ${undefined} | ${'2021-07-16T00:00:00.000Z'}
${input} | ${0.6} | ${undefined} | ${'2021-07-11T00:00:00.000Z'}
${input} | ${20} | ${undefined} | ${'2021-02-26T01:00:00.000Z'}
${input} | ${20} | ${{}} | ${'2021-02-26T01:00:00.000Z'}
${input} | ${20} | ${{ utc: false }} | ${'2021-02-26T01:00:00.000Z'}
${input} | ${20} | ${{ utc: true }} | ${'2021-02-26T00:00:00.000Z'}
`(
'when the provided date is $inputAsString, numberOfWeeks is $numberOfWeeks, and the options parameter is $options, returns $expectedAsString',
({ inputAsString, numberOfWeeks, options, expectedAsString }) => {
const inputDate = new Date(inputAsString);
const actual = datetimeUtility.nWeeksBefore(inputDate, numberOfWeeks, options);
expect(actual.toISOString()).toBe(expectedAsString);
},
);
});
describe('nMonthsAfter', () => {
// February has 28 days
const feb2019 = new Date('2019-02-15T00:00:00.000Z');
const feb2019 = '2019-02-15T00:00:00.000Z';
// Except in 2020, it had 29 days
const feb2020 = new Date('2020-02-15T00:00:00.000Z');
const feb2020 = '2020-02-15T00:00:00.000Z';
// April has 30 days
const apr2020 = new Date('2020-04-15T00:00:00.000Z');
const apr2020 = '2020-04-15T00:00:00.000Z';
// May has 31 days
const may2020 = new Date('2020-05-15T00:00:00.000Z');
const may2020 = '2020-05-15T00:00:00.000Z';
// November 1, 2020 was the day Daylight Saving Time ended in 2020 (in the US)
const oct2020 = '2020-10-15T00:00:00.000Z';
it.each`
date | numberOfMonths | expectedResult
${feb2019} | ${1} | ${new Date('2019-03-15T00:00:00.000Z').valueOf()}
${feb2020} | ${1} | ${new Date('2020-03-15T00:00:00.000Z').valueOf()}
${apr2020} | ${1} | ${new Date('2020-05-15T00:00:00.000Z').valueOf()}
${may2020} | ${1} | ${new Date('2020-06-15T00:00:00.000Z').valueOf()}
${may2020} | ${12} | ${new Date('2021-05-15T00:00:00.000Z').valueOf()}
${may2020} | ${-1} | ${new Date('2020-04-15T00:00:00.000Z').valueOf()}
${may2020} | ${0} | ${may2020.valueOf()}
${may2020} | ${0.9} | ${may2020.valueOf()}
inputAsString | numberOfMonths | options | expectedAsString
${feb2019} | ${1} | ${undefined} | ${'2019-03-14T23:00:00.000Z'}
${feb2020} | ${1} | ${undefined} | ${'2020-03-14T23:00:00.000Z'}
${apr2020} | ${1} | ${undefined} | ${'2020-05-15T00:00:00.000Z'}
${may2020} | ${1} | ${undefined} | ${'2020-06-15T00:00:00.000Z'}
${may2020} | ${12} | ${undefined} | ${'2021-05-15T00:00:00.000Z'}
${may2020} | ${-1} | ${undefined} | ${'2020-04-15T00:00:00.000Z'}
${may2020} | ${0} | ${undefined} | ${may2020}
${may2020} | ${0.9} | ${undefined} | ${may2020}
${oct2020} | ${1} | ${undefined} | ${'2020-11-15T01:00:00.000Z'}
${oct2020} | ${1} | ${{}} | ${'2020-11-15T01:00:00.000Z'}
${oct2020} | ${1} | ${{ utc: false }} | ${'2020-11-15T01:00:00.000Z'}
${oct2020} | ${1} | ${{ utc: true }} | ${'2020-11-15T00:00:00.000Z'}
`(
'returns the date $numberOfMonths month(s) after the provided date',
({ date, numberOfMonths, expectedResult }) => {
expect(datetimeUtility.nMonthsAfter(date, numberOfMonths)).toBe(expectedResult);
'when the provided date is $inputAsString, numberOfMonths is $numberOfMonths, and the options parameter is $options, returns $expectedAsString',
({ inputAsString, numberOfMonths, options, expectedAsString }) => {
const inputDate = new Date(inputAsString);
const actual = datetimeUtility.nMonthsAfter(inputDate, numberOfMonths, options);
expect(actual.toISOString()).toBe(expectedAsString);
},
);
});
});
describe('nMonthsBefore', () => {
describe('nMonthsBefore', () => {
// The previous month (February) has 28 days
const march2019 = new Date('2019-03-15T00:00:00.000Z');
const march2019 = '2019-03-15T00:00:00.000Z';
// Except in 2020, it had 29 days
const march2020 = new Date('2020-03-15T00:00:00.000Z');
const march2020 = '2020-03-15T00:00:00.000Z';
// The previous month (April) has 30 days
const may2020 = new Date('2020-05-15T00:00:00.000Z');
const may2020 = '2020-05-15T00:00:00.000Z';
// The previous month (May) has 31 days
const june2020 = new Date('2020-06-15T00:00:00.000Z');
const june2020 = '2020-06-15T00:00:00.000Z';
// November 1, 2020 was the day Daylight Saving Time ended in 2020 (in the US)
const nov2020 = '2020-11-15T00:00:00.000Z';
it.each`
date | numberOfMonths | expectedResult
${march2019} | ${1} | ${new Date('2019-02-15T00:00:00.000Z').valueOf()}
${march2020} | ${1} | ${new Date('2020-02-15T00:00:00.000Z').valueOf()}
${may2020} | ${1} | ${new Date('2020-04-15T00:00:00.000Z').valueOf()}
${june2020} | ${1} | ${new Date('2020-05-15T00:00:00.000Z').valueOf()}
${june2020} | ${12} | ${new Date('2019-06-15T00:00:00.000Z').valueOf()}
${june2020} | ${-1} | ${new Date('2020-07-15T00:00:00.000Z').valueOf()}
${june2020} | ${0} | ${june2020.valueOf()}
${june2020} | ${0.9} | ${new Date('2020-05-15T00:00:00.000Z').valueOf()}
inputAsString | numberOfMonths | options | expectedAsString
${march2019} | ${1} | ${undefined} | ${'2019-02-15T01:00:00.000Z'}
${march2020} | ${1} | ${undefined} | ${'2020-02-15T01:00:00.000Z'}
${may2020} | ${1} | ${undefined} | ${'2020-04-15T00:00:00.000Z'}
${june2020} | ${1} | ${undefined} | ${'2020-05-15T00:00:00.000Z'}
${june2020} | ${12} | ${undefined} | ${'2019-06-15T00:00:00.000Z'}
${june2020} | ${-1} | ${undefined} | ${'2020-07-15T00:00:00.000Z'}
${june2020} | ${0} | ${undefined} | ${june2020}
${june2020} | ${0.9} | ${undefined} | ${'2020-05-15T00:00:00.000Z'}
${nov2020} | ${1} | ${undefined} | ${'2020-10-14T23:00:00.000Z'}
${nov2020} | ${1} | ${{}} | ${'2020-10-14T23:00:00.000Z'}
${nov2020} | ${1} | ${{ utc: false }} | ${'2020-10-14T23:00:00.000Z'}
${nov2020} | ${1} | ${{ utc: true }} | ${'2020-10-15T00:00:00.000Z'}
`(
'returns the date $numberOfMonths month(s) before the provided date',
({ date, numberOfMonths, expectedResult }) => {
expect(datetimeUtility.nMonthsBefore(date, numberOfMonths)).toBe(expectedResult);
'when the provided date is $inputAsString, numberOfMonths is $numberOfMonths, and the options parameter is $options, returns $expectedAsString',
({ inputAsString, numberOfMonths, options, expectedAsString }) => {
const inputDate = new Date(inputAsString);
const actual = datetimeUtility.nMonthsBefore(inputDate, numberOfMonths, options);
expect(actual.toISOString()).toBe(expectedAsString);
},
);
});
});
describe('approximateDuration', () => {
......@@ -951,3 +1017,32 @@ describe('isToday', () => {
expect(datetimeUtility.isToday(date)).toBe(expected);
});
});
describe('getStartOfDay', () => {
beforeEach(() => {
timezoneMock.register('US/Eastern');
});
afterEach(() => {
timezoneMock.unregister();
});
it.each`
inputAsString | options | expectedAsString
${'2021-01-29T18:08:23.014Z'} | ${undefined} | ${'2021-01-29T05:00:00.000Z'}
${'2021-01-29T13:08:23.014-05:00'} | ${undefined} | ${'2021-01-29T05:00:00.000Z'}
${'2021-01-30T03:08:23.014+09:00'} | ${undefined} | ${'2021-01-29T05:00:00.000Z'}
${'2021-01-28T18:08:23.014-10:00'} | ${undefined} | ${'2021-01-28T05:00:00.000Z'}
${'2021-01-28T18:08:23.014-10:00'} | ${{}} | ${'2021-01-28T05:00:00.000Z'}
${'2021-01-28T18:08:23.014-10:00'} | ${{ utc: false }} | ${'2021-01-28T05:00:00.000Z'}
${'2021-01-28T18:08:23.014-10:00'} | ${{ utc: true }} | ${'2021-01-29T00:00:00.000Z'}
`(
'when the provided date is $inputAsString and the options parameter is $options, returns $expectedAsString',
({ inputAsString, options, expectedAsString }) => {
const inputDate = new Date(inputAsString);
const actual = datetimeUtility.getStartOfDay(inputDate, options);
expect(actual.toISOString()).toEqual(expectedAsString);
},
);
});
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment