diff --git a/backend/src/alphapulse/calendar/europe.py b/backend/src/alphapulse/calendar/europe.py
index f389547..8658710 100644
--- a/backend/src/alphapulse/calendar/europe.py
+++ b/backend/src/alphapulse/calendar/europe.py
@@ -307,7 +307,7 @@ def parse_announcement(family: str, body: str) -> Announcement:
if p is None:
raise ValueError("Eurostat GDP 公告缺少季度")
period = period_of(p[1], quarter=True)
- table = next((t for t in s.css("table") if "Growth rates of GDP in volume" in compact(t.xpath("string(.)").get())), None)
+ table = next((t for t in s.css("table") if "growth rates of gdp in volume" in compact(t.xpath("string(.)").get()).lower()), None)
if table is None:
raise ValueError("Eurostat 缺少实际 GDP 增长表,不能使用就业增长表")
row = eurostat_row(table, "Euro area")
@@ -316,7 +316,7 @@ def parse_announcement(family: str, body: str) -> Announcement:
raise ValueError("Eurostat GDP 表格列口径改变")
values = {"gdp_qoq": value(row[count], row[count - 1]), "gdp_yoy": value(row[-1], row[-2])}
else:
- p = re.search(r"In ([A-Z][a-z]+ 20\d\d), the euro area seasonally adjusted unemployment rate was\s*(" + N + r")%", text)
+ p = re.search(r"In ([A-Z][a-z]+ 20\d\d), the euro area seasonally[- ]adjusted unemployment rate was\s*(" + N + r")%", text)
if p is None:
raise ValueError("Eurostat 公告未识别到欧元区季调失业率")
period = period_of(p[1])
diff --git a/backend/tests/fixtures/europe/ea_gdp_2025_01.html b/backend/tests/fixtures/europe/ea_gdp_2025_01.html
new file mode 100644
index 0000000..d3d6e30
--- /dev/null
+++ b/backend/tests/fixtures/europe/ea_gdp_2025_01.html
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+
+In the fourth quarter of 2024, seasonally adjusted GDP remained stable in the euro area and increased by 0.1% in the EU, compared with the previous quarter, according to a preliminary flash estimate published by Eurostat, the statistical office of the European Union. In the third quarter of 2024, GDP had grown by 0.4% in both areas.
+
+
+
+ Published growth rates of GDP in volume up to 2024Q4 (based on seasonally adjusted* data) |
+
+
+ |
+ Percentage change compared with the previous quarter |
+ Percentage change compared with the same quarter of the previous year |
+
+
+ |
+ 2024Q1 |
+ 2024Q2 |
+ 2024Q3 |
+ 2024Q4 |
+ 2024Q1 |
+ 2024Q2 |
+ 2024Q3 |
+ 2024Q4 |
+
+
+ Euro area |
+ 0.3 |
+ 0.2 |
+ 0.4 |
+ 0.0 |
+ 0.4 |
+ 0.5 |
+ 0.9 |
+ 0.9 |
+
+
+
+
diff --git a/backend/tests/fixtures/europe/ea_jobs_2025_01.html b/backend/tests/fixtures/europe/ea_jobs_2025_01.html
new file mode 100644
index 0000000..42d6a19
--- /dev/null
+++ b/backend/tests/fixtures/europe/ea_jobs_2025_01.html
@@ -0,0 +1,142 @@
+
+
+
+
+
+
+
+In November 2024, the euro area seasonally-adjusted unemployment rate was 6.3%, stable compared with October 2024 and down from 6.5% in November 2023. The EU unemployment rate was 5.9% in November 2024, also stable compared with October 2024 and down from 6.1% in November 2023. These figures are published by Eurostat, the statistical office of the European Union.
+
+
+
+ Seasonally adjusted unemployment, totals |
+
+
+ |
+ Rates (%) |
+ Number of persons (in thousands) |
+
+
+ 2023 |
+ 2024 |
+ 2023 |
+ 2024 |
+
+
+ Nov |
+ Aug |
+ Sep |
+ Oct |
+ Nov |
+ Nov |
+ Aug |
+ Sep |
+ Oct |
+ Nov |
+
+
+
+ 6.5 |
+ 6.3 |
+ 6.3 |
+ 6.3 |
+ 6.3 |
+ 11 152 |
+ 10 850 |
+ 10 862 |
+ 10 858 |
+ 10 819 |
+
+
+
+
+
+
+ Seasonally adjusted youth (under 25s) unemployment |
+
+
+ |
+ Rates (%) |
+ Number of persons (in thousands) |
+
+
+ 2023 |
+ 2024 |
+ 2023 |
+ 2024 |
+
+
+ Nov |
+ Aug |
+ Sep |
+ Oct |
+ Nov |
+ Nov |
+ Aug |
+ Sep |
+ Oct |
+ Nov |
+
+
+
+ 14.6 |
+ 14.9 |
+ 14.9 |
+ 15.0 |
+ 15.0 |
+ 2 322 |
+ 2 384 |
+ 2 390 |
+ 2 421 |
+ 2 423 |
+
+
+
+
+
+
+ Seasonally adjusted unemployment rates (%), by sex |
+
+
+ |
+ Males |
+ Females |
+
+
+ 2023 |
+ 2024 |
+ 2023 |
+ 2024 |
+
+
+ Nov |
+ Aug |
+ Sep |
+ Oct |
+ Nov |
+ Nov |
+ Aug |
+ Sep |
+ Oct |
+ Nov |
+
+
+
+ 6.2 |
+ 6.2 |
+ 6.2 |
+ 6.1 |
+ 6.1 |
+ 6.8 |
+ 6.5 |
+ 6.5 |
+ 6.5 |
+ 6.5 |
+
+
+
+
diff --git a/backend/tests/test_europe.py b/backend/tests/test_europe.py
index 4d7ccef..5c1019d 100644
--- a/backend/tests/test_europe.py
+++ b/backend/tests/test_europe.py
@@ -25,7 +25,9 @@ def fixture(name):
("ea_hicp", "ea_cpi", "2026-09", "final", {"hicp_yoy": "3.8", "hicp_mom": "0.6", "core_hicp_yoy": "2.5"}),
("ea_hicp", "ea_flash", "2026-09", "flash", {"hicp_yoy": "3.8", "hicp_mom": "0.6", "core_hicp_yoy": "2.5"}),
("ea_jobs", "ea_jobs", "2026-08", None, {"ilo_unemployment": "6.4"}),
+ ("ea_jobs", "ea_jobs_2025_01", "2024-11", None, {"ilo_unemployment": "6.3"}),
("ea_gdp", "ea_gdp", "2026-Q2", "preliminary", {"gdp_qoq": "0.4", "gdp_yoy": "1"}),
+ ("ea_gdp", "ea_gdp_2025_01", "2024-Q4", "preliminary", {"gdp_qoq": "0", "gdp_yoy": "0.9"}),
("ea_gdp", "ea_gdp_flash", "2026-Q2", "flash", {"gdp_qoq": "0.4", "gdp_yoy": "1"}),
("ea_gdp", "ea_gdp_final", "2026-Q2", "final", {"gdp_qoq": "0.6", "gdp_yoy": "1.2"}),
("de_cpi", "de_cpi", "2026-09", "final", {"eu_cpi_yoy": "3.3", "eu_cpi_mom": "0.6", "hicp_yoy": "3.3", "hicp_mom": "0.6"}),
@@ -61,6 +63,22 @@ def test_monthly_previous_is_previous_month_not_same_month_last_year():
assert result.values["eu_core_cpi_yoy"]["previous"] == "2.6"
+def test_historical_eurostat_results_preserve_previous_values_and_real_publication_dates():
+ gdp = parse_announcement("ea_gdp", fixture("ea_gdp_2025_01.html"))
+ assert gdp.at == datetime(2025, 1, 30, 10, tzinfo=UTC)
+ assert gdp.values["gdp_qoq"]["previous"] == "0.4"
+ assert gdp.values["gdp_yoy"]["previous"] == "0.9"
+ jobs = parse_announcement("ea_jobs", fixture("ea_jobs_2025_01.html"))
+ assert jobs.at == datetime(2025, 1, 7, 10, tzinfo=UTC)
+ assert jobs.values["ilo_unemployment"]["previous"] == "6.3"
+
+
+def test_eurostat_gdp_does_not_take_an_employment_table_when_the_gdp_table_is_missing():
+ body = fixture("ea_gdp_2025_01.html").replace("growth rates of GDP in volume", "growth rates of employment")
+ with pytest.raises(ValueError, match="GDP 增长表"):
+ parse_announcement("ea_gdp", body)
+
+
@pytest.mark.parametrize("period,expected", [("December 2024 to February 2025", "2025-02"),
("December 2025 to February 2026", "2026-02"),
("June to August 2026", "2026-08")])