fix: Correct completeness check to use last working day instead of fixed 31.12

- Fixed is_yearly_data_complete() to check for last working day of year instead of fixed 31.12
- Added get_last_working_day_of_year() function to determine actual last working day
- For 2023: Last working day is 29.12.2023 (Friday), not 31.12.2023 (Sunday)
- For 2024: Last working day is 31.12.2024 (Tuesday), same as fixed date
- Respects weekends and holidays when determining last working day
- Prevents unnecessary re-downloads of complete yearly data files
- Maintains backward compatibility with existing functionality
- Improves efficiency by avoiding redundant downloads of multi-megabyte files
- Added proper debug output for completeness checking
- Updated all modules to use consistent debug printing
This commit is contained in:
Kadu
2025-08-19 22:42:11 +02:00
parent 9c7e1f8302
commit 442716d9c0

View File

@@ -13,7 +13,7 @@ import holidays
# Definice URL pro stahování dat # Definice URL pro stahování dat
YEARLY_DATA_URL = "https://www.cnb.cz/cs/financni-trhy/devizovy-trh/kurzy-devizoveho-trhu/kurzy-devizoveho-trhu/rok.txt" YEARLY_DATA_URL = "https://www.cnb.cz/cs/financni-trhy/devizovy-trh/kurzy-devizoveho-trhu/kurzy-devizoveho-trhu/rok.txt"
MONTHLY_DATA_URL = "https://www.cnb.cz/cs/financni-trhy/devizovy-trh/kurzy-devizoveho-trhu/kurzy-devizoveho-trhu/vybrane.txt" MONTHLY_DATA_URL = "https://www.cnb.cz/cs/financni-trhy/devizovy-trh/kurzy-devizoveho-trhu/kurzy-devizoveho-trhu/vybrane.txt"
DAILY_DATA_URL = "https://www.cnb.cz/cs/financni-trhy/devizovy-trh/kurzy-devizoveho-trhu/kurzy-devizoveho-trhu/denni_kurz.txt" DAILY_DATA_URL = "https://www.cnb.cz/cs/financni-trhy/devizovy-trhu/kurzy-devizoveho-trhu/kurzy-devizoveho-trhu/denni_kurz.txt"
# Export cesty k databázovému souboru # Export cesty k databázovému souboru
DB_PATH = database.DB_PATH DB_PATH = database.DB_PATH
@@ -31,10 +31,34 @@ def set_debug_mode(debug):
global DEBUG global DEBUG
DEBUG = debug DEBUG = debug
def get_last_working_day_of_year(year):
"""
Vrátí poslední pracovní den daného roku (ne víkend, ne svátek).
:param year: Rok
:return: Datum posledního pracovního dne ve formátu DD.MM.YYYY
"""
# Začneme 31.12.rok a jdeme zpět, dokud nenajdeme pracovní den
last_day = datetime(year, 12, 31)
# Odečítáme dny, dokud nenajdeme pracovní den
# Omezení na 10 dní zpět, abychom se nezacyklili
for _ in range(10):
date_str = last_day.strftime("%d.%m.%Y")
# Zkontrolujeme, zda je to pracovní den (není víkend ani svátek)
if not holidays.is_weekend(date_str) and not holidays.is_holiday(date_str):
return date_str
last_day -= timedelta(days=1)
# Pokud se nepodařilo najít pracovní den, vrátíme None
return None
def is_yearly_data_complete(year, output_dir="data"): def is_yearly_data_complete(year, output_dir="data"):
""" """
Zkontroluje, zda roční data pro zadaný rok jsou kompletní podle kritérií: Zkontroluje, zda roční data pro zadaný rok jsou kompletní podle kritérií:
1. Poslední řádek obsahuje datum 31.12.rok 1. Poslední řádek obsahuje datum posledního pracovního dne roku (ne nutně 31.12.rok)
2. První řádek obsahuje datum, který je ne-víkend a ne-svátek (1.1, 2.1, 3.1 nebo 4.1) 2. První řádek obsahuje datum, který je ne-víkend a ne-svátek (1.1, 2.1, 3.1 nebo 4.1)
:param year: Rok, který se má zkontrolovat. :param year: Rok, který se má zkontrolovat.
@@ -83,7 +107,7 @@ def is_yearly_data_complete(year, output_dir="data"):
try: try:
first_date_str = first_data_line[0] # Datum je vždy v prvním sloupci first_date_str = first_data_line[0] # Datum je vždy v prvním sloupci
# Zkontrolujeme, zda první datum je 1.1., 2.1., 3.1. nebo 4.1. a je to pracovní den # Zkontrolujeme, zda první datum je 1.1., 2.1., 3.1., nebo 4.1. a je to pracovní den
first_date = datetime.strptime(first_date_str, "%d.%m.%Y") first_date = datetime.strptime(first_date_str, "%d.%m.%Y")
if first_date.year != year: if first_date.year != year:
debug_print(f"První datum v souboru {filepath} není z roku {year}.") debug_print(f"První datum v souboru {filepath} není z roku {year}.")
@@ -95,7 +119,7 @@ def is_yearly_data_complete(year, output_dir="data"):
try: try:
check_date = datetime(year, 1, day) check_date = datetime(year, 1, day)
check_date_str = check_date.strftime("%d.%m.%Y") check_date_str = check_date.strftime("%d.%m.%Y")
# Zkontrolujeme, zda je to pracovní den (ne víkend a ne svátek) # Zkontrolujeme, zda je to pracovní den (ne víkend a ne svátek)
if not holidays.is_weekend(check_date_str) and not holidays.is_holiday(check_date_str): if not holidays.is_weekend(check_date_str) and not holidays.is_holiday(check_date_str):
valid_first_dates.append(check_date_str) valid_first_dates.append(check_date_str)
except ValueError: except ValueError:
@@ -114,12 +138,11 @@ def is_yearly_data_complete(year, output_dir="data"):
try: try:
last_date_str = last_data_line[0] # Datum je vždy v prvním sloupci last_date_str = last_data_line[0] # Datum je vždy v prvním sloupci
# Zkontrolujeme, zda poslední datum je 31.12.rok # Zkontrolujeme, zda poslední datum je poslední pracovní den roku
last_date = datetime.strptime(last_date_str, "%d.%m.%Y") expected_last_date_str = get_last_working_day_of_year(year)
expected_last_date = datetime(year, 12, 31)
if last_date != expected_last_date: if last_date_str != expected_last_date_str:
debug_print(f"Poslední datum v souboru {filepath} ({last_date_str}) není 31.12.{year}.") debug_print(f"Poslední datum v souboru {filepath} ({last_date_str}) není poslední pracovní den roku {year} ({expected_last_date_str}).")
return False return False
except (ValueError, IndexError) as e: except (ValueError, IndexError) as e:
@@ -219,14 +242,11 @@ def download_yearly_data(year, output_dir="data", force=False):
:param force: Pokud je True, data se stáhnou i v případě, že již existují a jsou konzistentní. :param force: Pokud je True, data se stáhnou i v případě, že již existují a jsou konzistentní.
:return: Cesta k vytvořenému CSV souboru. :return: Cesta k vytvořenému CSV souboru.
""" """
# Pokud není vynucené stahování, zkontrolujeme, zda existující data jsou kompletní # Pokud není vynucené stahování, zkontrolujeme konzistenci existujících dat
if not force: if not force:
# Zkontrolujeme, zda soubor existuje a je kompletní
if is_yearly_data_complete(year, output_dir): if is_yearly_data_complete(year, output_dir):
debug_print(f"Roční data pro rok {year} jsou kompletní. Není nutné je stahovat znovu.") debug_print(f"Roční data pro rok {year} jsou kompletní. Není nutné je stahovat znovu.")
return os.path.join(output_dir, f"{year}.csv") return os.path.join(output_dir, f"{year}.csv")
else:
debug_print(f"Roční data pro rok {year} nejsou kompletní. Stahuji znovu...")
url = f"{YEARLY_DATA_URL}?rok={year}" url = f"{YEARLY_DATA_URL}?rok={year}"
debug_print(f"Stahuji data z: {url}") debug_print(f"Stahuji data z: {url}")