Last active
November 15, 2024 15:20
-
-
Save ddelange/20e819b29793f422f4e53e968ad54276 to your computer and use it in GitHub Desktop.
Parse a GEP-2257 like duration string into a Python timedelta
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import re | |
from datetime import timedelta | |
# Ordered case-insensitive duration strings, loosely based on the [GEP-2257](https://gateway-api.sigs.k8s.io/geps/gep-2257/) spec | |
# Discrepancies between this pattern and GEP-2257 duration strings: | |
# - this pattern accepts units `w|d|h|m|s|ms|[uµ]s` (all units supported by the datetime.timedelta constructor), GEP-2257 accepts only `h|m|s|ms` | |
# - this pattern allows for optional whitespace around the units, GEP-2257 does not | |
# - this pattern is compiled to be case-insensitive, GEP-2257 expects lowercase units | |
# - this pattern expects ordered (descending) units, GEP-2257 allows arbitrary order | |
# - this pattern does not allow duplicate unit occurrences, GEP-2257 does | |
# - this pattern allows for negative integers, GEP-2257 does not | |
_TIMEDELTA_PATTERN = re.compile( | |
r"^(?:\s*)" # optional whitespace at the beginning of the string | |
r"(?:(-?\d+)\s*w\s*)?" # weeks with optional whitespace around unit | |
r"(?:(-?\d+)\s*d\s*)?" # days with optional whitespace around unit | |
r"(?:(-?\d+)\s*h\s*)?" # hours with optional whitespace around unit | |
r"(?:(-?\d+)\s*m\s*)?" # minutes with optional whitespace around unit | |
r"(?:(-?\d+)\s*s\s*)?" # seconds with optional whitespace around unit | |
r"(?:(-?\d+)\s*ms\s*)?" # milliseconds with optional whitespace around unit | |
r"(?:(-?\d+)\s*[µu]s\s*)?$", # microseconds with optional whitespace around unit | |
flags=re.IGNORECASE, | |
) | |
def parse_duration_string(value: str) -> timedelta | None: | |
"""Parse a GEP-2257 like duration string into a timedelta. | |
>>> parse_duration_string('42w 42d 42h 42m 42s 42ms 42us') | |
datetime.timedelta(days=337, seconds=67362, microseconds=42042) | |
""" | |
match = _TIMEDELTA_PATTERN.match(value) | |
if match is not None and any(groups := match.groups(default=0)): | |
return timedelta( | |
weeks=int(groups[0]), | |
days=int(groups[1]), | |
hours=int(groups[2]), | |
minutes=int(groups[3]), | |
seconds=int(groups[4]), | |
milliseconds=int(groups[5]), | |
microseconds=int(groups[6]), | |
) | |
parse_duration_string('5w -7us') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
ref sloria/environs#366