0
Fork 0
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:
Naz 2021-05-06 15:19:36 +04:00
parent 413549f9c0
commit 4f41c2a206
3 changed files with 102 additions and 0 deletions

View file

@ -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
};

View file

@ -20,6 +20,7 @@
"access": "public"
},
"devDependencies": {
"date-fns": "^2.21.2",
"mocha": "8.3.2",
"should": "13.2.3",
"sinon": "10.0.0"

View 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');
});
});
});