Coverage for src/mlopus/utils/time_utils.py: 100%

15 statements  

« prev     ^ index     » next       coverage.py v7.6.1, created at 2025-07-13 14:49 +0000

1import re 

2from datetime import datetime 

3from typing import TypeVar 

4 

5import pytz 

6 

7T = TypeVar("T") # Any type 

8 

9 

10class Patterns: 

11 """Datetime patterns.""" 

12 

13 SAFE_REPR = re.compile(r"^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{6}\+00:00$") # Match output format of `safe_repr` 

14 

15 

16def to_utc(dt: datetime) -> datetime: 

17 """Get equivalent datetime in UTC. 

18 

19 Example: 

20 utc_plus_2 = pytz.FixedOffset(+2 * 60) 

21 

22 noon = datetime(2024, 4, 1, 12) 

23 

24 noon_in_berlin = utc_plus_2.localize(noon) 

25 

26 to_utc(noon_in_berlin) # 10 AM 

27 """ 

28 return dt.astimezone(pytz.utc) 

29 

30 

31def safe_repr(dt: datetime) -> str: 

32 """Get safe string representation of datetime (UTC ISO with microseconds precision.) 

33 

34 This representation is lossless, independent of locale and preserves datetime sorting. 

35 """ 

36 return to_utc(dt).isoformat(timespec="microseconds") 

37 

38 

39def maybe_parse_safe_repr(val: T) -> T | datetime: 

40 """Parse safe datetime representation if matches, no change otherwise.""" 

41 if isinstance(val, str) and Patterns.SAFE_REPR.fullmatch(val): 

42 val = datetime.fromisoformat(val) 

43 return val