mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-02-17 23:44:39 -05:00
Added utility calculating date of last period start
refs https://github.com/TryGhost/Team/issues/588 - There's a need to calculate when the last period has started to be able to generate correct counting queries for the "maxPeriodical" limit - It operatest on ISO strings as an input and output in UTC timezone to take timezone calculations out of the equation - Refer to inclucded unit tests for example calculations
This commit is contained in:
parent
413549f9c0
commit
4f41c2a206
3 changed files with 102 additions and 0 deletions
|
@ -1,5 +1,30 @@
|
|||
const differenceInMonths = require('date-fns/differenceInMonths');
|
||||
const parseISO = require('date-fns/parseISO');
|
||||
const addMonths = require('date-fns/addMonths');
|
||||
|
||||
const SUPPORTED_INTERVALS = ['month'];
|
||||
/**
|
||||
* Calculates the start of the last period (billing, cycle, etc.) based on the start date
|
||||
* and the interval at which the cycle renews.
|
||||
*
|
||||
* @param {String} startDate - date in ISO 8601 format (https://en.wikipedia.org/wiki/ISO_8601)
|
||||
* @param {('month')} interval - currently only supports 'month' value, in the future might support 'year', etc.
|
||||
*
|
||||
* @returns {String} - date in ISO 8601 format (https://en.wikipedia.org/wiki/ISO_8601) of the last period start
|
||||
*/
|
||||
const lastPeriodStart = (startDate, interval) => {
|
||||
if (interval === 'month') {
|
||||
const startDateISO = parseISO(startDate);
|
||||
const fullPeriodsPast = differenceInMonths(new Date(), startDateISO);
|
||||
const lastPeriodStartDate = addMonths(startDateISO, fullPeriodsPast);
|
||||
|
||||
return lastPeriodStartDate.toISOString();
|
||||
}
|
||||
|
||||
throw new Error('Invalid interval specified. Only "month" value is accepted.');
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
lastPeriodStart,
|
||||
SUPPORTED_INTERVALS
|
||||
};
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
"access": "public"
|
||||
},
|
||||
"devDependencies": {
|
||||
"date-fns": "^2.21.2",
|
||||
"mocha": "8.3.2",
|
||||
"should": "13.2.3",
|
||||
"sinon": "10.0.0"
|
||||
|
|
76
ghost/limit-service/test/date-utils.test.js
Normal file
76
ghost/limit-service/test/date-utils.test.js
Normal file
|
@ -0,0 +1,76 @@
|
|||
// Switch these lines once there are useful utils
|
||||
// const testUtils = require('./utils');
|
||||
require('./utils');
|
||||
|
||||
const {subWeeks, subMonths} = require('date-fns');
|
||||
const sinon = require('sinon');
|
||||
const {lastPeriodStart} = require('../lib/date-utils');
|
||||
|
||||
describe('Date Utils', function () {
|
||||
describe('fn: lastPeriodStart', function () {
|
||||
let clock;
|
||||
|
||||
afterEach(function () {
|
||||
if (clock) {
|
||||
clock.restore();
|
||||
}
|
||||
});
|
||||
|
||||
it('returns same date if current date is less than a period away from current date', async function () {
|
||||
const weekAgoDate = subWeeks(new Date(), 1);
|
||||
const weekAgoISO = weekAgoDate.toISOString();
|
||||
|
||||
const lastPeriodStartDate = lastPeriodStart(weekAgoISO, 'month');
|
||||
|
||||
lastPeriodStartDate.should.equal(weekAgoISO);
|
||||
});
|
||||
|
||||
it('returns beginning of last month\'s period', async function () {
|
||||
const weekAgoDate = subWeeks(new Date(), 1);
|
||||
const weekAgoISO = weekAgoDate.toISOString();
|
||||
|
||||
const weekAndAMonthAgo = subMonths(weekAgoDate, 1);
|
||||
const weekAndAMonthAgoISO = weekAndAMonthAgo.toISOString();
|
||||
|
||||
const lastPeriodStartDate = lastPeriodStart(weekAndAMonthAgoISO, 'month');
|
||||
|
||||
lastPeriodStartDate.should.equal(weekAgoISO);
|
||||
});
|
||||
|
||||
it('returns 3rd day or current month when monthly period started on 3rd day in the past', async function () {
|
||||
// fake current clock to be past 3rd day of a month
|
||||
clock = sinon.useFakeTimers(new Date('2021-08-18T19:00:52Z').getTime());
|
||||
|
||||
const lastPeriodStartDate = lastPeriodStart('2020-03-03T23:00:01Z', 'month');
|
||||
|
||||
lastPeriodStartDate.should.equal('2021-08-03T23:00:01.000Z');
|
||||
});
|
||||
|
||||
it('returns 5rd day or last month when monthly period started on 5th day in the past and it is 3rd day of the month', async function () {
|
||||
// fake current clock to be on 3rd day of a month
|
||||
clock = sinon.useFakeTimers(new Date('2021-09-03T12:12:12Z').getTime());
|
||||
|
||||
const lastPeriodStartDate = lastPeriodStart('2020-03-05T11:11:11Z', 'month');
|
||||
|
||||
lastPeriodStartDate.should.equal('2021-08-05T11:11:11.000Z');
|
||||
});
|
||||
|
||||
it('return 29th of Feb if the subscription started on the 31st day and it is a leap year', async function () {
|
||||
// fake current clock to be march of a leap year
|
||||
clock = sinon.useFakeTimers(new Date('2020-03-05T13:15:07Z').getTime());
|
||||
|
||||
const lastPeriodStartDate = lastPeriodStart('2020-01-31T23:00:01Z', 'month');
|
||||
|
||||
lastPeriodStartDate.should.equal('2020-02-29T23:00:01.000Z');
|
||||
});
|
||||
|
||||
it('return 28th of Feb if the subscription started on the 30th day and it is **not** a leap year', async function () {
|
||||
// fake current clock to be March of non-leap year
|
||||
clock = sinon.useFakeTimers(new Date('2021-03-05T13:15:07Z').getTime());
|
||||
|
||||
const lastPeriodStartDate = lastPeriodStart('2019-04-30T01:59:42Z', 'month');
|
||||
|
||||
lastPeriodStartDate.should.equal('2021-02-28T01:59:42.000Z');
|
||||
});
|
||||
});
|
||||
});
|
Loading…
Add table
Reference in a new issue