diff --git a/core/models/wallets.py b/core/models/wallets.py index 0e57d2c..c18af41 100644 --- a/core/models/wallets.py +++ b/core/models/wallets.py @@ -21,45 +21,126 @@ YEAR_RANGE = (1975, 2050) def make_valid_date(walletname, date): """Take whatever garbage some fool has typed in and try to make it into a valid ISO-format date + + Attempts to parse various date string formats into a valid datetime.date object. + It prioritizes ISO format, then Euro format (dd-mm-yy), then ISO-like (yyyy-m-d) + using named capture groups for clear parsing. + + Args: + walletname: Contextual name for logging warnings/errors. + date: The raw date string input (e.g., '14.12.25', '14/12/2025', '2025-12-1'). + + Returns: + A datetime.date object if successful, otherwise None. """ + # Unify separators: . and / become - datestr = date.replace(".", "-").replace("/", "-") + + samedate = None + + # --- 1. Attempt Strict ISO format (yyyy-mm-dd) --- try: samedate = datetime.date.fromisoformat(datestr) return samedate except ValueError: - # Could be in std euro format e.g. 14/07/2023 - match = re.search(r'(\d{1,2})/(\d{1,2})/(\d{2,4})', datestr) - if match: - d = int(match.group(1)) - m = int(match.group(2)) - y = int(match.group(3)) - if y<2000: - y = y + 2000 - try: - samedate = datetime.date(y, m, d) - print(f"- - Warning, not in ISO format. '{datestr=}' but we tried to cope: {samedate.isoformat()} {walletname}") - return samedate - except: - print(f"! - Fail, tried to decompose date in dd/mm/yyyy format but failed: {datestr=} ") - return None - # probably a single digit day number or month number - match = re.search(r'(\d{4})-(\d{1,2})-(\d{1,2})', datestr) - if match: - y = int(match.group(1)) - m = int(match.group(2)) - d = int(match.group(3)) - try: - samedate = datetime.date(y, m, d) - print(f"- - Warning, 1 digit only for month or day '{datestr=}' but we coped: {samedate.isoformat()} ") - return samedate - except: - print(f"! - Fail, tried to decompose date in yyyy-mm-d or yyy-m-dd format but failed: {datestr=} ") - return None + pass # Fall through to alternative formats - if datestr: # might have been None - if datestr != "None": - print(f"! - Failed to understand date, none of our tricks worked {datestr=} ") - return None + # --- 2. Attempt European/DMY Format (dd-mm-yy or dd-mm-yyyy) --- + # Example: 14-12-25 or 14-12-2025 + dmy_regex = r'(?P\d{1,2})-(?P\d{1,2})-(?P\d{2,4})' + match = re.search(dmy_regex, datestr) + + if match: + data = match.groupdict() + d = int(data['day']) + m = int(data['month']) + y = int(data['year']) + + # Two-digit year handling + if y < 2000: + y = y + 2000 + + try: + samedate = datetime.date(y, m, d) + try: + swapdate = datetime.date(y, d, m) + print(f"! - ERROR, not in ISO format. datestr='{datestr}'day and month are ambiguous {samedate.isoformat()} {walletname}") + except ValueError: + # swapping day and month does not produce a valid date + print(f"- - Warning, not in ISO format. datestr='{datestr}' but we tried to guess: {samedate.isoformat()} {walletname}") + return samedate + except ValueError: + print(f"! - Fail, tried to decompose date in dd-mm-yyyy format but failed: datestr='{datestr}'") + return None # Stop processing + + # --- 3. Attempt ISO-Like Format (yyyy-m-d or yyyy-mm-dd) --- + # Catches cases where day/month are single digits but format is ISO-like. + # Example: 2025-1-14 or 2025-12-5 + ymd_regex = r'(?P\d{4})-(?P\d{1,2})-(?P\d{1,2})' + match = re.search(ymd_regex, datestr) + + if match: + data = match.groupdict() + y = int(data['year']) + m = int(data['month']) + d = int(data['day']) + + try: + samedate = datetime.date(y, m, d) + print(f"- - Warning, 1 digit only for month or day datestr='{datestr}' but we coped: {samedate.isoformat()} {walletname}") + return samedate + except ValueError: + print(f"! - Fail, tried to decompose date in yyyy-m-d format but failed: datestr='{datestr}'") + return None # Stop processing + + # --- 4. Final Failure Check --- + if datestr and datestr != "None": + print(f"! - Failed to understand date, none of our tricks worked datestr='{datestr}'") + + return None + + +# def make_valid_date(walletname, date): + # """Take whatever garbage some fool has typed in and try to make it into a valid ISO-format date + # """ + # datestr = date.replace(".", "-").replace("/", "-") + # try: + # samedate = datetime.date.fromisoformat(datestr) + # return samedate + # except ValueError: + # # Could be in std euro format e.g. 14/07/2023 + # match = re.search(r'(\d{1,2})/(\d{1,2})/(\d{2,4})', datestr) + # if match: + # d = int(match.group(1)) + # m = int(match.group(2)) + # y = int(match.group(3)) + # if y<2000: + # y = y + 2000 + # try: + # samedate = datetime.date(y, m, d) + # print(f"- - Warning, not in ISO format. '{datestr=}' but we tried to cope: {samedate.isoformat()} {walletname}") + # return samedate + # except: + # print(f"! - Fail, tried to decompose date in dd/mm/yyyy format but failed: {datestr=} ") + # return None + # # probably a single digit day number or month number + # match = re.search(r'(\d{4})-(\d{1,2})-(\d{1,2})', datestr) + # if match: + # y = int(match.group(1)) + # m = int(match.group(2)) + # d = int(match.group(3)) + # try: + # samedate = datetime.date(y, m, d) + # print(f"- - Warning, 1 digit only for month or day '{datestr=}' but we coped: {samedate.isoformat()} ") + # return samedate + # except: + # print(f"! - Fail, tried to decompose date in yyyy-mm-d or yyy-m-dd format but failed: {datestr=} ") + # return None + + # if datestr: # might have been None + # if datestr != "None": + # print(f"! - Failed to understand date, none of our tricks worked {datestr=} ") + # return None archaic_wallets = [ '1984AndysNotebook',