fix(weather): fix openmeteo forecast stuck in the past (#4064)

The URL was built once at startup with a hardcoded start_date. Since
HTTPFetcher reuses the same URL, the forecast never advanced past day
one.

Use forecast_days instead — Open-Meteo resolves it relative to today on
every request. Other providers are not affected as they don't use dates
in their URLs.

Fixes #4063
This commit is contained in:
Kristjan ESPERANTO
2026-03-23 09:07:39 +01:00
committed by GitHub
parent ee261939bd
commit de78190ed7
2 changed files with 32 additions and 33 deletions
+2 -10
View File
@@ -1,5 +1,4 @@
const Log = require("logger");
const { getDateString } = require("../provider-utils");
const HTTPFetcher = require("#http_fetcher");
// https://www.bigdatacloud.com/docs/api/free-reverse-geocode-to-city-api
@@ -262,22 +261,15 @@ class OpenMeteoProvider {
precipitation_unit: "mm"
};
const now = new Date();
const startDate = new Date(now.getFullYear(), now.getMonth(), now.getDate());
const endDate = new Date(startDate);
endDate.setDate(endDate.getDate() + Math.max(0, Math.min(7, maxNumberOfDays)));
params.start_date = getDateString(startDate);
switch (this.config.type) {
case "hourly":
case "daily":
case "forecast":
params.end_date = getDateString(endDate);
params.forecast_days = maxNumberOfDays + 1; // Open-Meteo counts today as day 1, so maxNumberOfDays=5 needs forecast_days=6
break;
case "current":
params.current_weather = true;
params.end_date = params.start_date;
params.forecast_days = 1;
break;
default:
return "";
@@ -80,32 +80,39 @@ describe("OpenMeteoProvider", () => {
expect(provider.locationName).toBe("Munich, BY");
});
it("should build query dates from local date, not ISO UTC conversion", async () => {
const toISOStringSpy = vi.spyOn(Date.prototype, "toISOString").mockReturnValue("2000-01-01T00:00:00.000Z");
try {
const provider = new OpenMeteoProvider({
lat: 48.14,
lon: 11.58,
type: "current"
});
it("should use forecast_days instead of static start_date/end_date", async () => {
const provider = new OpenMeteoProvider({
lat: 48.14,
lon: 11.58,
type: "current"
});
await provider.initialize();
await provider.initialize();
const url = new URL(provider.fetcher.url);
const params = url.searchParams;
const now = new Date();
const expectedToday = [
now.getFullYear(),
String(now.getMonth() + 1).padStart(2, "0"),
String(now.getDate()).padStart(2, "0")
].join("-");
const url = new URL(provider.fetcher.url);
const params = url.searchParams;
expect(params.get("start_date")).toBe(expectedToday);
expect(params.get("end_date")).toBe(expectedToday);
expect(params.get("start_date")).not.toBe("2000-01-01");
} finally {
toISOStringSpy.mockRestore();
}
expect(params.get("forecast_days")).toBe("1");
expect(params.has("start_date")).toBe(false);
expect(params.has("end_date")).toBe(false);
});
it("should set forecast_days based on maxNumberOfDays for forecast type", async () => {
const provider = new OpenMeteoProvider({
lat: 48.14,
lon: 11.58,
type: "forecast",
maxNumberOfDays: 5
});
await provider.initialize();
const url = new URL(provider.fetcher.url);
const params = url.searchParams;
expect(params.get("forecast_days")).toBe("6"); // 5 days + 1
expect(params.has("start_date")).toBe(false);
expect(params.has("end_date")).toBe(false);
});
});