From 237940861f474fcea14407603bf715c19a64c079 Mon Sep 17 00:00:00 2001 From: Dominik Roth Date: Sat, 30 Oct 2021 14:18:14 +0200 Subject: [PATCH] Included a cache --- .gitignore | 1 + meuro.py | 66 +++++++++++++++++++++++++++++++++++------------------- 2 files changed, 44 insertions(+), 23 deletions(-) diff --git a/.gitignore b/.gitignore index bee8a64..666886f 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ __pycache__ +cache.json diff --git a/meuro.py b/meuro.py index d208e5e..bf582b1 100755 --- a/meuro.py +++ b/meuro.py @@ -1,34 +1,53 @@ #!/usr/bin/python3 -import requests +import requests, json, os.path from datetime import datetime from dateutil import relativedelta from dateutil import parser as dparser from dateutil.parser._parser import ParserError as DateParserError -# Ugly code thats outside of any function -url = 'https://sdw.ecb.europa.eu/quickviewexport.do?SERIES_KEY=122.ICP.M.U2.N.000000.4.ANR&type=csv' -resp = requests.get(url) -lines = resp.text.split('\n')[6:] -years = {} # Will later contain the monthly factor of inflation (~1.0016667) for every month -for line in lines: - vals = line.split(',') - year = int(vals[0][:4]) - month = datetime.strptime(vals[0][4:],'%b').month - inflation = float(vals[1]) - if not year in years: - years[year] = {} - years[year][month] = 1 + (inflation/100)/12 +_years = None -for year in years: - months = years[year] - for month in range(1,13): - if month not in months: - years[year][month] = 1 + 0.02/12 # Lets say the ECB archives their target +def _loadYearsTable(maxCacheSeconds=3600): + if os.path.isfile('cache.json'): + with open('cache.json', 'r') as f: + cacheUpdate, cacheYears = json.loads(f.read()) + if (datetime.now() - dparser.isoparse(cacheUpdate)).total_seconds() < maxCacheSeconds: + # JSON does not allow integers as keys; so we convert them back here... + cacheYears = {int(y):{int(m):float(n) for m,n in ms.items()} for y,ms in cacheYears.items()} + return cacheYears + return _loadYearsTableWeb() + +def _loadYearsTableWeb(): + print('[i] Fetching new data from ECB-Servers...') + url = 'https://sdw.ecb.europa.eu/quickviewexport.do?SERIES_KEY=122.ICP.M.U2.N.000000.4.ANR&type=csv' + resp = requests.get(url) + lines = resp.text.split('\n')[6:] + years = {} # Will later contain the monthly factor of inflation (~1.0016667) for every month + for line in lines: + vals = line.split(',') + year = int(vals[0][:4]) + month = datetime.strptime(vals[0][4:],'%b').month + inflation = float(vals[1]) + if not year in years: + years[year] = {} + years[year][month] = 1 + (inflation/100)/12 + + for year in years: + months = years[year] + for month in range(1,13): + if month not in months: + years[year][month] = 1 + 0.02/12 # Lets say the ECB archives their target + with open('cache.json', 'w') as f: + f.write(json.dumps([datetime.now().isoformat(),years])) + return years # Gives you the exchange rate between euros and meuros for the given date. # (Should always be a float < 1) # date should be either a datetime-object or None (= current date) def exchangeRate(date=None): + global _years + if _years==None: + _years = _loadYearsTable() if date==None: date = datetime.now() month, year = date.month, date.year @@ -37,23 +56,24 @@ def exchangeRate(date=None): akk = 1 for fullYear in range(2001, year): yearlyInf = 1 - for m in years[fullYear]: - monthlyInf = years[fullYear][m] + for m in _years[fullYear]: + monthlyInf = _years[fullYear][m] yearlyInf *= monthlyInf akk *= yearlyInf for fullMonth in range(1, month): - monthlyInf = years[year][fullMonth] + monthlyInf = _years[year][fullMonth] akk *= monthlyInf beginningOfMonth = date.replace(hour=0, minute=0, second=0, microsecond=0, day=1) endOfMonth = beginningOfMonth + relativedelta.relativedelta(months=1) fracOfMonth = (date - beginningOfMonth).total_seconds() / (endOfMonth - beginningOfMonth).total_seconds() - inflationThisMonth = 1 + fracOfMonth * (years[year][month]-1) + inflationThisMonth = 1 + fracOfMonth * (_years[year][month]-1) akk *= inflationThisMonth return 1/akk + # Converts the given amount of euros to meuros for the given date. (wholeCents means it rounds to two decimal places) # date should be either a datetime-object or None (= current date) def euroToMeuro(eur,date=None,wholeCents=True):