Skip to content

Commit de5d46b

Browse files
committed
fix month & year management
1 parent 0531527 commit de5d46b

2 files changed

Lines changed: 101 additions & 7 deletions

File tree

app/utils/download-anomalies.ts

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,14 +49,18 @@ function isDateAffected(
4949
return startWeek < anomaly.end.date && endWeek > anomaly.start.date
5050
}
5151
case 'monthly': {
52-
const startMonth = anomaly.start.date.slice(0, 7) + '-01'
53-
const endMonth = anomaly.end.date.slice(0, 7) + '-01'
54-
return date >= startMonth && date <= endMonth
52+
const monthStart = date
53+
const monthStartDate = new Date(`${date}T00:00:00Z`)
54+
const monthEndDate = new Date(monthStartDate)
55+
monthEndDate.setUTCMonth(monthEndDate.getUTCMonth() + 1)
56+
monthEndDate.setUTCDate(monthEndDate.getUTCDate() - 1)
57+
const monthEnd = monthEndDate.toISOString().slice(0, 10)
58+
return monthStart < anomaly.end.date && monthEnd > anomaly.start.date
5559
}
5660
case 'yearly': {
57-
const startYear = anomaly.start.date.slice(0, 4) + '-01-01'
58-
const endYear = anomaly.end.date.slice(0, 4) + '-01-01'
59-
return date >= startYear && date <= endYear
61+
const yearStart = date
62+
const yearEnd = `${date.slice(0, 4)}-12-31`
63+
return yearStart < anomaly.end.date && yearEnd > anomaly.start.date
6064
}
6165
}
6266
}

test/unit/app/utils/download-anomalies.spec.ts

Lines changed: 91 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
import { describe, expect, it } from 'vitest'
22
import { applyBlocklistCorrection } from '../../../../app/utils/download-anomalies'
3-
import type { WeeklyDataPoint } from '../../../../app/types/chart'
3+
import type {
4+
MonthlyDataPoint,
5+
WeeklyDataPoint,
6+
YearlyDataPoint,
7+
} from '../../../../app/types/chart'
48

59
/** Helper to build a WeeklyDataPoint from a start date and value. */
610
function week(weekStart: string, value: number): WeeklyDataPoint {
@@ -18,6 +22,22 @@ function week(weekStart: string, value: number): WeeklyDataPoint {
1822
}
1923
}
2024

25+
function month(monthStr: string, value: number): MonthlyDataPoint {
26+
return {
27+
value,
28+
month: monthStr,
29+
timestamp: new Date(`${monthStr}-01T00:00:00Z`).getTime(),
30+
}
31+
}
32+
33+
function year(yearStr: string, value: number): YearlyDataPoint {
34+
return {
35+
value,
36+
year: yearStr,
37+
timestamp: new Date(`${yearStr}-01-01T00:00:00Z`).getTime(),
38+
}
39+
}
40+
2141
describe('applyBlocklistCorrection', () => {
2242
// Anomaly Nov 2022: start=2022-11-15, end=2022-11-30
2343
it('corrects weeks overlapping the anomaly', () => {
@@ -90,4 +110,74 @@ describe('applyBlocklistCorrection', () => {
90110
expect(result[1]!.hasAnomaly).toBe(true)
91111
expect(result[1]!.value).toBeLessThan(1_000_000)
92112
})
113+
114+
// Vite anomaly: start=2025-08-04, end=2025-09-08 (spans Aug-Sep)
115+
it('does not over-correct a month that only touches the anomaly end boundary', () => {
116+
const data = [
117+
month('2025-07', 30_000_000),
118+
month('2025-08', 100_000_000), // contains spike
119+
month('2025-09', 100_000_000), // contains spike (Sep 1-7)
120+
month('2025-10', 30_000_000), // after anomaly end — normal!
121+
]
122+
123+
const result = applyBlocklistCorrection({
124+
data,
125+
packageName: 'vite',
126+
granularity: 'monthly',
127+
}) as MonthlyDataPoint[]
128+
129+
expect(result[1]!.hasAnomaly).toBe(true)
130+
expect(result[2]!.hasAnomaly).toBe(true)
131+
132+
// October must NOT be modified
133+
expect(result[3]!.value).toBe(30_000_000)
134+
expect(result[3]!.hasAnomaly).toBeUndefined()
135+
})
136+
137+
it('does not over-correct a month that only touches the anomaly start boundary', () => {
138+
const data = [
139+
month('2025-07', 30_000_000), // before anomaly start — normal!
140+
month('2025-08', 100_000_000), // contains spike
141+
month('2025-09', 100_000_000), // contains spike
142+
month('2025-10', 30_000_000),
143+
]
144+
145+
const result = applyBlocklistCorrection({
146+
data,
147+
packageName: 'vite',
148+
granularity: 'monthly',
149+
}) as MonthlyDataPoint[]
150+
151+
// July must NOT be modified
152+
expect(result[0]!.value).toBe(30_000_000)
153+
expect(result[0]!.hasAnomaly).toBeUndefined()
154+
155+
expect(result[1]!.hasAnomaly).toBe(true)
156+
expect(result[2]!.hasAnomaly).toBe(true)
157+
})
158+
159+
it('does not over-correct a year that only touches the anomaly boundary', () => {
160+
const data = [
161+
year('2024', 500_000_000),
162+
year('2025', 2_000_000_000), // contains spike
163+
year('2026', 500_000_000),
164+
]
165+
166+
const result = applyBlocklistCorrection({
167+
data,
168+
packageName: 'vite',
169+
granularity: 'yearly',
170+
}) as YearlyDataPoint[]
171+
172+
// 2024 must NOT be modified
173+
expect(result[0]!.value).toBe(500_000_000)
174+
expect(result[0]!.hasAnomaly).toBeUndefined()
175+
176+
// 2025 must be corrected
177+
expect(result[1]!.hasAnomaly).toBe(true)
178+
179+
// 2026 must NOT be modified
180+
expect(result[2]!.value).toBe(500_000_000)
181+
expect(result[2]!.hasAnomaly).toBeUndefined()
182+
})
93183
})

0 commit comments

Comments
 (0)