fix: _parse_date валидирует формат даты через regex вместо возврата мусора
This commit is contained in:
parent
e957446063
commit
b22b02d65e
@ -48,9 +48,10 @@ class TestParseDate:
|
|||||||
[
|
[
|
||||||
("Mon, 28 May 2026 10:00:00 +0000", "28.05.2026"),
|
("Mon, 28 May 2026 10:00:00 +0000", "28.05.2026"),
|
||||||
("Mon, 28 May 2026 10:00:00 GMT", "28.05.2026"),
|
("Mon, 28 May 2026 10:00:00 GMT", "28.05.2026"),
|
||||||
("2026-05-28T10:00:00Z", "2026.05.28"),
|
("2026-05-28T10:00:00Z", "28.05.2026"),
|
||||||
("2026-12-31T23:59:59Z", "2026.12.31"),
|
("2026-12-31T23:59:59Z", "31.12.2026"),
|
||||||
("2026-01-01T00:00:00Z", "2026.01.01"),
|
("2026-01-01T00:00:00Z", "01.01.2026"),
|
||||||
|
("2026-05-28", "28.05.2026"),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_parse_date_known(self, pub_date, expected) -> None:
|
def test_parse_date_known(self, pub_date, expected) -> None:
|
||||||
@ -69,11 +70,9 @@ class TestParseDate:
|
|||||||
assert _parse_date(pub_date) == expected
|
assert _parse_date(pub_date) == expected
|
||||||
|
|
||||||
def test_parse_date_invalid(self) -> None:
|
def test_parse_date_invalid(self) -> None:
|
||||||
"""Невалидная дата должна вернуть первые 10 символов."""
|
"""Невалидная дата должна вернуть пустую строку."""
|
||||||
result = _parse_date("invalid-date-string")
|
result = _parse_date("invalid-date-string")
|
||||||
assert (
|
assert result == ""
|
||||||
result == "invalid.da"
|
|
||||||
) # первые 10 символов: 'invalid-da' → 'invalid.da' (replace('-','.'))
|
|
||||||
|
|
||||||
|
|
||||||
class TestFormatArticles:
|
class TestFormatArticles:
|
||||||
@ -205,7 +204,7 @@ class TestFormatArticles:
|
|||||||
},
|
},
|
||||||
]
|
]
|
||||||
result = format_articles(articles, "Заголовок", "https://habr.com/feed")
|
result = format_articles(articles, "Заголовок", "https://habr.com/feed")
|
||||||
assert result[1] == "Статья\n2026.05.28 <https://habr.com/1>"
|
assert result[1] == "Статья\n28.05.2026 <https://habr.com/1>"
|
||||||
|
|
||||||
def test_format_articles_empty_date(self) -> None:
|
def test_format_articles_empty_date(self) -> None:
|
||||||
"""Пустая дата должна быть пустой строкой."""
|
"""Пустая дата должна быть пустой строкой."""
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
import logging
|
import logging
|
||||||
|
import re
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
@ -82,7 +83,13 @@ async def fetch_rss(url: str) -> Optional[list[dict]]:
|
|||||||
|
|
||||||
|
|
||||||
def _parse_date(pub_date: Optional[str]) -> str:
|
def _parse_date(pub_date: Optional[str]) -> str:
|
||||||
"""Парсить дату из RSS в строку 'дд.мм.гггг' или вернуть часть даты."""
|
"""Парсить дату из RSS в строку 'дд.мм.гггг'.
|
||||||
|
|
||||||
|
Поддерживает:
|
||||||
|
- RFC 822: "Mon, 01 Jan 2024 12:00:00 GMT"
|
||||||
|
- ISO 8601: "2024-01-01T12:00:00+00:00" или "2024-01-01"
|
||||||
|
Возвращает пустую строку, если формат не распознан.
|
||||||
|
"""
|
||||||
if not pub_date:
|
if not pub_date:
|
||||||
return ""
|
return ""
|
||||||
try:
|
try:
|
||||||
@ -90,7 +97,12 @@ def _parse_date(pub_date: Optional[str]) -> str:
|
|||||||
dt = datetime.strptime(d, "%a, %d %b %Y %H:%M:%S %z")
|
dt = datetime.strptime(d, "%a, %d %b %Y %H:%M:%S %z")
|
||||||
return dt.strftime("%d.%m.%Y")
|
return dt.strftime("%d.%m.%Y")
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return pub_date[:10].replace("-", ".")
|
pass
|
||||||
|
# Fallback: YYYY-MM-DD или YYYY-MM-DDT...
|
||||||
|
match = re.match(r"(\d{4})-(\d{2})-(\d{2})", pub_date)
|
||||||
|
if match:
|
||||||
|
return f"{match.group(3)}.{match.group(2)}.{match.group(1)}"
|
||||||
|
return ""
|
||||||
|
|
||||||
|
|
||||||
def truncate_title(title: str, max_len: int = 60) -> str:
|
def truncate_title(title: str, max_len: int = 60) -> str:
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user