Make exclusive end dates explicit

This commit is contained in:
Brenda Sukh
2020-11-13 15:51:25 -05:00
parent 259d848eee
commit 319b6b17de
4 changed files with 44 additions and 27 deletions
@@ -76,7 +76,7 @@ describe('getPreviousPeriodTotalCost', () => {
change: changeOf(MockAggregatedDailyCosts),
trendline: trendlineOf(MockAggregatedDailyCosts),
};
const exclusiveEndDate = '2020-10-01';
const exclusiveEndDate = '2020-09-30';
expect(
getPreviousPeriodTotalCost(
mockGroupDailyCost,
+9 -4
View File
@@ -22,6 +22,7 @@ import {
GrowthType,
MetricData,
Duration,
DEFAULT_DATE_FORMAT,
} from '../types';
import dayjs, { OpUnitType } from 'dayjs';
import duration from 'dayjs/plugin/duration';
@@ -68,13 +69,17 @@ export function getComparedChange(
export function getPreviousPeriodTotalCost(
dailyCost: Cost,
duration: Duration,
endDate: string,
inclusiveEndDate: string,
): number {
const dayjsDuration = dayjs.duration(duration);
const startDate = inclusiveStartDateOf(duration, endDate);
const startDate = inclusiveStartDateOf(
duration,
dayjs(inclusiveEndDate).add(1, 'day').format(DEFAULT_DATE_FORMAT),
);
// dayjs doesn't allow adding an ISO 8601 period to dates.
const [amount, type]: [number, OpUnitType] = dayjsDuration.days()
? [dayjsDuration.days(), 'days' as OpUnitType]
: [dayjsDuration.months(), 'months' as OpUnitType];
? [dayjsDuration.days(), 'day']
: [dayjsDuration.months(), 'month'];
const nextPeriodStart = dayjs(startDate).add(amount, type);
// Add up costs that incurred before the start of the next period.
+19 -13
View File
@@ -22,27 +22,27 @@ import { assertNever } from './assert';
* Derive the start date of a given period, assuming two repeating intervals.
*
* @param duration see comment on Duration enum
* @param endDate from CostInsightsApi.getLastCompleteBillingDate
* @param endDate from CostInsightsApi.getLastCompleteBillingDate + 1 day
*/
export function inclusiveStartDateOf(
duration: Duration,
endDate: string,
exclusiveEndDate: string,
): string {
switch (duration) {
case Duration.P30D:
case Duration.P90D:
return moment(endDate)
return moment(exclusiveEndDate)
.utc()
.subtract(moment.duration(duration).add(moment.duration(duration)))
.format(DEFAULT_DATE_FORMAT);
case Duration.P1M:
return moment(endDate)
return moment(exclusiveEndDate)
.utc()
.startOf('month')
.subtract(moment.duration(duration).add(moment.duration(duration)))
.format(DEFAULT_DATE_FORMAT);
case Duration.P3M:
return moment(endDate)
return moment(exclusiveEndDate)
.utc()
.startOf('quarter')
.subtract(moment.duration(duration).add(moment.duration(duration)))
@@ -54,16 +54,22 @@ export function inclusiveStartDateOf(
export function exclusiveEndDateOf(
duration: Duration,
endDate: string,
inclusiveEndDate: string,
): string {
switch (duration) {
case Duration.P30D:
case Duration.P90D:
return moment(endDate).utc().add(1, 'day').format(DEFAULT_DATE_FORMAT);
return moment(inclusiveEndDate)
.utc()
.add(1, 'day')
.format(DEFAULT_DATE_FORMAT);
case Duration.P1M:
return moment(endDate).utc().startOf('month').format(DEFAULT_DATE_FORMAT);
return moment(inclusiveEndDate)
.utc()
.startOf('month')
.format(DEFAULT_DATE_FORMAT);
case Duration.P3M:
return moment(endDate)
return moment(inclusiveEndDate)
.utc()
.startOf('quarter')
.format(DEFAULT_DATE_FORMAT);
@@ -74,15 +80,15 @@ export function exclusiveEndDateOf(
export function inclusiveEndDateOf(
duration: Duration,
endDate: string,
inclusiveEndDate: string,
): string {
return moment(exclusiveEndDateOf(duration, endDate))
return moment(exclusiveEndDateOf(duration, inclusiveEndDate))
.utc()
.subtract(1, 'day')
.format(DEFAULT_DATE_FORMAT);
}
// https://en.wikipedia.org/wiki/ISO_8601#Repeating_intervals
export function intervalsOf(duration: Duration, endDate: string) {
return `R2/${duration}/${exclusiveEndDateOf(duration, endDate)}`;
export function intervalsOf(duration: Duration, inclusiveEndDate: string) {
return `R2/${duration}/${exclusiveEndDateOf(duration, inclusiveEndDate)}`;
}
+15 -9
View File
@@ -15,7 +15,7 @@
*/
import moment from 'moment';
import { Duration } from '../types';
import { Duration, DEFAULT_DATE_FORMAT } from '../types';
import { inclusiveEndDateOf, inclusiveStartDateOf } from '../utils/duration';
import { pluralOf } from '../utils/grammar';
@@ -84,21 +84,27 @@ export function formatPercent(n: number): string {
return `${(n * 100).toFixed(0)}%`;
}
export function formatLastTwoLookaheadQuarters(endDate: string) {
const start = moment(inclusiveStartDateOf(Duration.P3M, endDate)).format(
'[Q]Q YYYY',
);
const end = moment(inclusiveEndDateOf(Duration.P3M, endDate)).format(
export function formatLastTwoLookaheadQuarters(inclusiveEndDate: string) {
const exclusiveEndDate = moment(inclusiveEndDate)
.add(1, 'day')
.format(DEFAULT_DATE_FORMAT);
const start = moment(
inclusiveStartDateOf(Duration.P3M, exclusiveEndDate),
).format('[Q]Q YYYY');
const end = moment(inclusiveEndDateOf(Duration.P3M, inclusiveEndDate)).format(
'[Q]Q YYYY',
);
return `${start} vs ${end}`;
}
export function formatLastTwoMonths(endDate: string) {
const start = moment(inclusiveStartDateOf(Duration.P1M, endDate))
export function formatLastTwoMonths(inclusiveEndDate: string) {
const exclusiveEndDate = moment(inclusiveEndDate)
.add(1, 'day')
.format(DEFAULT_DATE_FORMAT);
const start = moment(inclusiveStartDateOf(Duration.P1M, exclusiveEndDate))
.utc()
.format('MMMM');
const end = moment(inclusiveEndDateOf(Duration.P1M, endDate))
const end = moment(inclusiveEndDateOf(Duration.P1M, inclusiveEndDate))
.utc()
.format('MMMM');
return `${start} vs ${end}`;