Fix incorrect dates from UTC abuse
This commit is contained in:
@@ -76,13 +76,13 @@ describe('getPreviousPeriodTotalCost', () => {
|
||||
change: changeOf(MockAggregatedDailyCosts),
|
||||
trendline: trendlineOf(MockAggregatedDailyCosts),
|
||||
};
|
||||
const exclusiveEndDate = '2020-09-30';
|
||||
const inclusiveEndDate = '2020-09-30';
|
||||
expect(
|
||||
getPreviousPeriodTotalCost(
|
||||
mockGroupDailyCost.aggregation,
|
||||
Duration.P30D,
|
||||
exclusiveEndDate,
|
||||
inclusiveEndDate,
|
||||
),
|
||||
).toEqual(100_000);
|
||||
).toEqual(96_600);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -22,7 +22,6 @@ import {
|
||||
GrowthType,
|
||||
MetricData,
|
||||
Duration,
|
||||
DEFAULT_DATE_FORMAT,
|
||||
DateAggregation,
|
||||
} from '../types';
|
||||
import dayjs, { OpUnitType } from 'dayjs';
|
||||
@@ -73,10 +72,7 @@ export function getPreviousPeriodTotalCost(
|
||||
inclusiveEndDate: string,
|
||||
): number {
|
||||
const dayjsDuration = dayjs.duration(duration);
|
||||
const startDate = inclusiveStartDateOf(
|
||||
duration,
|
||||
dayjs(inclusiveEndDate).add(1, 'day').format(DEFAULT_DATE_FORMAT),
|
||||
);
|
||||
const startDate = inclusiveStartDateOf(duration, inclusiveEndDate);
|
||||
// dayjs doesn't allow adding an ISO 8601 period to dates.
|
||||
const [amount, type]: [number, OpUnitType] = dayjsDuration.days()
|
||||
? [dayjsDuration.days(), 'day']
|
||||
|
||||
@@ -24,23 +24,21 @@ export const DEFAULT_DURATION = Duration.P30D;
|
||||
* Derive the start date of a given period, assuming two repeating intervals.
|
||||
*
|
||||
* @param duration see comment on Duration enum
|
||||
* @param exclusiveEndDate from CostInsightsApi.getLastCompleteBillingDate + 1 day
|
||||
* @param inclusiveEndDate from CostInsightsApi.getLastCompleteBillingDate
|
||||
*/
|
||||
export function inclusiveStartDateOf(
|
||||
duration: Duration,
|
||||
exclusiveEndDate: string,
|
||||
inclusiveEndDate: string,
|
||||
): string {
|
||||
switch (duration) {
|
||||
case Duration.P7D:
|
||||
case Duration.P30D:
|
||||
case Duration.P90D:
|
||||
return moment(exclusiveEndDate)
|
||||
.utc()
|
||||
return moment(inclusiveEndDate)
|
||||
.subtract(moment.duration(duration).add(moment.duration(duration)))
|
||||
.format(DEFAULT_DATE_FORMAT);
|
||||
case Duration.P3M:
|
||||
return moment(exclusiveEndDate)
|
||||
.utc()
|
||||
return moment(inclusiveEndDate)
|
||||
.startOf('quarter')
|
||||
.subtract(moment.duration(duration).add(moment.duration(duration)))
|
||||
.format(DEFAULT_DATE_FORMAT);
|
||||
@@ -57,13 +55,9 @@ export function exclusiveEndDateOf(
|
||||
case Duration.P7D:
|
||||
case Duration.P30D:
|
||||
case Duration.P90D:
|
||||
return moment(inclusiveEndDate)
|
||||
.utc()
|
||||
.add(1, 'day')
|
||||
.format(DEFAULT_DATE_FORMAT);
|
||||
return moment(inclusiveEndDate).add(1, 'day').format(DEFAULT_DATE_FORMAT);
|
||||
case Duration.P3M:
|
||||
return moment(quarterEndDate(inclusiveEndDate))
|
||||
.utc()
|
||||
.add(1, 'day')
|
||||
.format(DEFAULT_DATE_FORMAT);
|
||||
default:
|
||||
@@ -76,7 +70,6 @@ export function inclusiveEndDateOf(
|
||||
inclusiveEndDate: string,
|
||||
): string {
|
||||
return moment(exclusiveEndDateOf(duration, inclusiveEndDate))
|
||||
.utc()
|
||||
.subtract(1, 'day')
|
||||
.format(DEFAULT_DATE_FORMAT);
|
||||
}
|
||||
@@ -94,7 +87,7 @@ export function intervalsOf(
|
||||
}
|
||||
|
||||
export function quarterEndDate(inclusiveEndDate: string): string {
|
||||
const endDate = moment(inclusiveEndDate).utc();
|
||||
const endDate = moment(inclusiveEndDate);
|
||||
const endOfQuarter = endDate.endOf('quarter').format(DEFAULT_DATE_FORMAT);
|
||||
if (endOfQuarter === inclusiveEndDate) {
|
||||
return endDate.format(DEFAULT_DATE_FORMAT);
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
import moment from 'moment';
|
||||
import pluralize from 'pluralize';
|
||||
import { Duration, DEFAULT_DATE_FORMAT } from '../types';
|
||||
import { Duration } from '../types';
|
||||
import { inclusiveEndDateOf, inclusiveStartDateOf } from '../utils/duration';
|
||||
|
||||
export type Period = {
|
||||
@@ -92,11 +92,8 @@ export function formatPercent(n: number): string {
|
||||
}
|
||||
|
||||
export function formatLastTwoLookaheadQuarters(inclusiveEndDate: string) {
|
||||
const exclusiveEndDate = moment(inclusiveEndDate)
|
||||
.add(1, 'day')
|
||||
.format(DEFAULT_DATE_FORMAT);
|
||||
const start = moment(
|
||||
inclusiveStartDateOf(Duration.P3M, exclusiveEndDate),
|
||||
inclusiveStartDateOf(Duration.P3M, inclusiveEndDate),
|
||||
).format('[Q]Q YYYY');
|
||||
const end = moment(inclusiveEndDateOf(Duration.P3M, inclusiveEndDate)).format(
|
||||
'[Q]Q YYYY',
|
||||
|
||||
@@ -36,7 +36,7 @@ import {
|
||||
getDefaultState as getDefaultLoadingState,
|
||||
} from '../utils/loading';
|
||||
import { findAlways } from '../utils/assert';
|
||||
import { inclusiveStartDateOf } from './duration';
|
||||
import { inclusiveEndDateOf, inclusiveStartDateOf } from './duration';
|
||||
|
||||
type mockAlertRenderer<T> = (alert: T) => T;
|
||||
type mockEntityRenderer<T> = (entity: T) => T;
|
||||
@@ -228,8 +228,9 @@ export function aggregationFor(
|
||||
baseline: number,
|
||||
): DateAggregation[] {
|
||||
const { duration, endDate } = parseIntervals(intervals);
|
||||
const inclusiveEndDate = inclusiveEndDateOf(duration, endDate);
|
||||
const days = dayjs(endDate).diff(
|
||||
inclusiveStartDateOf(duration, endDate),
|
||||
inclusiveStartDateOf(duration, inclusiveEndDate),
|
||||
'day',
|
||||
);
|
||||
|
||||
@@ -244,7 +245,7 @@ export function aggregationFor(
|
||||
return [...Array(days).keys()].reduce(
|
||||
(values: DateAggregation[], i: number): DateAggregation[] => {
|
||||
const last = values.length ? values[values.length - 1].amount : baseline;
|
||||
const date = dayjs(inclusiveStartDateOf(duration, endDate))
|
||||
const date = dayjs(inclusiveStartDateOf(duration, inclusiveEndDate))
|
||||
.add(i, 'day')
|
||||
.format(DEFAULT_DATE_FORMAT);
|
||||
const amount = Math.max(0, last + nextDelta());
|
||||
|
||||
Reference in New Issue
Block a user