Parse a time string that can be either relative (e.g., "1h", "42m", "2d") or absolute (e.g., "2025-10-03T12:24:36Z"). Args: time_str: Time string in relative or absolute format Returns: datetime object in UTC timezone Raises: ValueError: If the time st
(time_str: str)
| 44 | |
| 45 | |
| 46 | def _parse_time_string(time_str: str) -> datetime: |
| 47 | """ |
| 48 | Parse a time string that can be either relative (e.g., "1h", "42m", "2d") |
| 49 | or absolute (e.g., "2025-10-03T12:24:36Z"). |
| 50 | |
| 51 | Args: |
| 52 | time_str: Time string in relative or absolute format |
| 53 | |
| 54 | Returns: |
| 55 | datetime object in UTC timezone |
| 56 | |
| 57 | Raises: |
| 58 | ValueError: If the time string cannot be parsed |
| 59 | """ |
| 60 | if not time_str: |
| 61 | raise ValueError("Time string cannot be empty") |
| 62 | |
| 63 | # Handle relative time formats (e.g., "1h", "42m", "2d", "0m") |
| 64 | relative_pattern = r"^(\d+)([smhd])$" |
| 65 | match = re.match(relative_pattern, time_str.lower()) |
| 66 | |
| 67 | if match: |
| 68 | value = int(match.group(1)) |
| 69 | unit = match.group(2) |
| 70 | |
| 71 | now = datetime.now(timezone.utc) |
| 72 | |
| 73 | if unit == "s": |
| 74 | delta = timedelta(seconds=value) |
| 75 | elif unit == "m": |
| 76 | delta = timedelta(minutes=value) |
| 77 | elif unit == "h": |
| 78 | delta = timedelta(hours=value) |
| 79 | elif unit == "d": |
| 80 | delta = timedelta(days=value) |
| 81 | else: |
| 82 | raise ValueError(f"Unsupported time unit: {unit}") |
| 83 | |
| 84 | return now - delta |
| 85 | |
| 86 | # Handle absolute time formats using dateutil parser |
| 87 | try: |
| 88 | parsed_dt = parser.parse(time_str) |
| 89 | |
| 90 | # Ensure timezone awareness |
| 91 | if parsed_dt.tzinfo is None: |
| 92 | # Assume UTC if no timezone info |
| 93 | parsed_dt = parsed_dt.replace(tzinfo=timezone.utc) |
| 94 | else: |
| 95 | # Convert to UTC |
| 96 | parsed_dt = parsed_dt.astimezone(timezone.utc) |
| 97 | except (ValueError, TypeError) as e: |
| 98 | raise ValueError(f"Unable to parse time string '{time_str}': {e}") |
| 99 | |
| 100 | return parsed_dt |
| 101 | |
| 102 | |
| 103 | app = TrackedTyper( |