diff --git a/src/corelibs/string_handling/timestamp_strings.py b/src/corelibs/string_handling/timestamp_strings.py index eb3d215..97baa26 100644 --- a/src/corelibs/string_handling/timestamp_strings.py +++ b/src/corelibs/string_handling/timestamp_strings.py @@ -2,10 +2,19 @@ Current timestamp strings and time zones """ +import re from datetime import datetime from zoneinfo import ZoneInfo, ZoneInfoNotFoundError +class TimeParseError(Exception): + """Custom exception for time parsing errors.""" + + +class TimeUnitError(Exception): + """Custom exception for time parsing errors.""" + + class TimestampStrings: """ set default time stamps @@ -24,3 +33,73 @@ class TimestampStrings: self.timestamp = self.timestamp_now.strftime("%Y-%m-%d %H:%M:%S") self.timestamp_tz = self.timestamp_now_tz.strftime("%Y-%m-%d %H:%M:%S %Z") self.timestamp_file = self.timestamp_now.strftime("%Y-%m-%d_%H%M%S") + + +def convert_to_seconds(time_string: str) -> int: + """ + Conver a string with time units into a seconds string + The following units are allowed + Y: 365 days + M: 30 days + d, h, m, s + + Arguments: + time_string {str} -- _description_ + + Raises: + ValueError: _description_ + + Returns: + int -- _description_ + """ + + # Define time unit conversion factors + unit_factors: dict[str, int] = { + 'Y': 31536000, # 365 days * 86400 seconds/day + 'M': 2592000 * 12, # 1 year in seconds (assuming 365 days per year) + 'd': 86400, # 1 day in seconds + 'h': 3600, # 1 hour in seconds + 'm': 60, # minutes to seconds + 's': 1 # 1 second in seconds + } + long_unit_names: dict[str, str] = { + 'year': 'Y', + 'years': 'Y', + 'month': 'M', + 'months': 'M', + 'day': 'd', + 'days': 'd', + 'hour': 'h', + 'hours': 'h', + 'minute': 'm', + 'minutes': 'm', + 'min': 'm', + 'second': 's', + 'seconds': 's', + 'sec': 's', + } + + total_seconds = 0 + + seen_units: list[str] = [] # Track units that have been encountered + + # Use regex to match number and time unit pairs + for match in re.finditer(r'(\d+)\s*([a-zA-Z]+)', time_string): + value, unit = int(match.group(1)), match.group(2) + + # full name check, fallback to original name + unit = long_unit_names.get(unit.lower(), unit) + + # Check for duplicate units + if unit in seen_units: + raise TimeParseError(f"Unit '{unit}' appears more than once.") + # Check invalid unit + if unit not in unit_factors: + raise TimeUnitError(f"Unit '{unit}' is not a valid unit name.") + # Add to total seconds based on the units + if unit in unit_factors: + total_seconds += value * unit_factors[unit] + + seen_units.append(unit) + + return total_seconds diff --git a/test-run/string_handling/timestamp_strings.py b/test-run/string_handling/timestamp_strings.py new file mode 100644 index 0000000..128d640 --- /dev/null +++ b/test-run/string_handling/timestamp_strings.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python3 + +""" +timestamp string checks +""" + +from corelibs.string_handling.timestamp_strings import convert_to_seconds, TimeParseError, TimeUnitError + + +def main() -> None: + """ + Comment + """ + test_cases = [ + "5M 6d", # 5 months, 6 days + "2h 30m 45s", # 2 hours, 30 minutes, 45 seconds + "1Y 2M 3d", # 1 year, 2 months, 3 days + "1h", # 1 hour + "30m", # 30 minutes + "2 hours 15 minutes", # 2 hours, 15 minutes + "1d 12h", # 1 day, 12 hours + "3M 2d 4h", # 3 months, 2 days, 4 hours + "45s", # 45 seconds + "1 year 2 months", # 1 year, 2 months + "2Y 6M 15d 8h 30m 45s", # Complex example + # ] + # invalid_test_cases = [ + "5M 6d 2M", # months appears twice + "2h 30m 45s 1h", # hours appears twice + "1d 2 days", # days appears twice (short and long form) + "30m 45 minutes", # minutes appears twice + "1Y 2 years", # years appears twice + "1x 2 yrs", # invalid names + ] + + for time_string in test_cases: + try: + result = convert_to_seconds(time_string) + print(f"{time_string} => {result}") + except (TimeParseError, TimeUnitError) as e: + print(f"Error encountered for {time_string}: {type(e).__name__}: {e}") + + +if __name__ == "__main__": + main() + +# __END__