Skip to content

Commit 39d5f7e

Browse files
committed
Add a bad time parser
1 parent 61d4322 commit 39d5f7e

File tree

2 files changed

+57
-2
lines changed

2 files changed

+57
-2
lines changed

nmr/types/time/constants.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from collections import Counter
12
from enum import IntEnum, auto
23

34
MICROSECOND_TO_YOCTOSECOND: int = 10 ** (24 - 6)
@@ -81,5 +82,3 @@ class Interval(IntEnum):
8182
Interval.YOCTOSECOND: 10 ** (24 - 24),
8283
},
8384
}
84-
85-
assert set(i for s in SCALES.values() for i in s.values()) == set(Interval)

nmr/types/time/formats.py

+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
from __future__ import annotations
2+
3+
import itertools
4+
from datetime import datetime
5+
from functools import partial
6+
from typing import Callable, Iterable, Sequence
7+
8+
from .constants import Interval
9+
from .time import Time
10+
11+
12+
def from_string(s: str) -> Time:
13+
def parse(p: str) -> datetime | None:
14+
try:
15+
return datetime.strptime(s, p)
16+
except ValueError:
17+
return None
18+
19+
all_parsers = ((i, p) for i, parsers in PARSERS.items() for p in parsers)
20+
times = [Time(i, dt) for i, p in all_parsers if (dt := parse(p))]
21+
if not times:
22+
raise ValueError("No format matched")
23+
if len(times) > 1:
24+
raise ValueError(f"Multiple formats matched {times=}")
25+
return times[0]
26+
27+
28+
def to_string(t: Time) -> str:
29+
return t.time.strftime(PARSERS[t.interval][0])
30+
31+
32+
def _product(*patterns: str, sep: str = " /") -> Iterable[str]:
33+
yield from ("%" + f"{sep}%".join(c) for s, c in itertools.product(sep, *patterns))
34+
35+
36+
PARSERS: dict[Interval, Sequence[str]] = {
37+
Interval.SECOND: ["%H:%M:%S", "%I:%M:%S%p"],
38+
Interval.MINUTE: ["%H:%M", "%Hh%M", "%I:%M%p"],
39+
Interval.HOUR: ["%Hh", "%I%p"],
40+
Interval.DAY: [
41+
*_product("d", "bBm", "Yy"),
42+
*_product("Yy", "bBm", "d"),
43+
*_product("d", "bBm"),
44+
*_product("bBm", "d"),
45+
],
46+
# Interval.WEEK: ["%m/%y"],
47+
Interval.MONTH: [
48+
*_product("bBm", "Yy"),
49+
*_product("Yy", "bBm"),
50+
*_product("bBm"),
51+
*_product("d"),
52+
],
53+
Interval.YEAR: [*_product("Yy")],
54+
# Interval.DECADE: [_decade],
55+
# Interval.CENTURY: [_century],
56+
}

0 commit comments

Comments
 (0)