Skip to content

Commit ebecd1d

Browse files
committed
Match month and weekday names case-insensitively in from_format
Fixes #668 Agent: claude
1 parent e06dace commit ebecd1d

3 files changed

Lines changed: 17 additions & 2 deletions

File tree

‎src/pendulum/formatting/formatter.py‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,11 @@ class Formatter:
6868

6969
_FROM_FORMAT_RE: re.Pattern[str] = re.compile(r"(?<!\\\[)" + _TOKENS + r"(?!\\\])")
7070

71+
# Names are matched regardless of case, as in "14nov22" or "MONDAY".
72+
_CASE_INSENSITIVE_TOKENS: ClassVar[frozenset[str]] = frozenset(
73+
{"MMMM", "MMM", "dddd", "ddd", "dd"}
74+
)
75+
7176
_LOCALIZABLE_TOKENS: ClassVar[
7277
dict[str, str | Callable[[Locale], Sequence[str]] | None]
7378
] = {
@@ -694,5 +699,7 @@ def _replace_tokens(self, token: str, locale: Locale) -> str:
694699
candidates = (cast("str", candidates),)
695700

696701
pattern = f"(?P<{token}>{'|'.join(candidates)})"
702+
if token in self._CASE_INSENSITIVE_TOKENS:
703+
pattern = f"(?i:{pattern})"
697704

698705
return pattern

‎src/pendulum/locales/locale.py‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,10 +90,11 @@ def ordinalize(self, number: int) -> str:
9090

9191
def match_translation(self, key: str, value: Any) -> dict[str, str] | None:
9292
translations = self.translation(key)
93-
if value not in translations.values():
93+
by_value = {v.lower(): k for k, v in translations.items()}
94+
if value.lower() not in by_value:
9495
return None
9596

96-
return cast(Dict[str, str], {v: k for k, v in translations.items()}[value])
97+
return cast(Dict[str, str], by_value[value.lower()])
9798

9899
def __repr__(self) -> str:
99100
return f"{self.__class__.__name__}('{self._locale}')"

‎tests/datetime/test_from_format.py‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,11 @@ def test_from_format_with_invalid_padded_day():
104104
("1", "E", "2018-01-29T00:00:00+00:00", "2018-02-02"),
105105
("March", "MMMM", "2018-03-01T00:00:00+00:00", "2018-02-02"),
106106
("Mar", "MMM", "2018-03-01T00:00:00+00:00", "2018-02-02"),
107+
("mar", "MMM", "2018-03-01T00:00:00+00:00", "2018-02-02"),
108+
("MARCH", "MMMM", "2018-03-01T00:00:00+00:00", "2018-02-02"),
109+
("14nov22", "DDMMMYY", "2022-11-14T00:00:00+00:00", None),
110+
("monday", "dddd", "2018-01-29T00:00:00+00:00", "2018-02-02"),
111+
("MON", "ddd", "2018-01-29T00:00:00+00:00", "2018-02-02"),
107112
(
108113
"Thursday 25th December 1975 02:15:16 PM",
109114
"dddd Do MMMM YYYY hh:mm:ss A",
@@ -164,6 +169,8 @@ def test_from_format(text, fmt, expected, now):
164169
("lu", "dd", "2018-01-29T00:00:00+00:00"),
165170
("mars", "MMMM", "2018-03-01T00:00:00+00:00"),
166171
("mars", "MMM", "2018-03-01T00:00:00+00:00"),
172+
("Mars", "MMMM", "2018-03-01T00:00:00+00:00"),
173+
("LUNDI", "dddd", "2018-01-29T00:00:00+00:00"),
167174
],
168175
)
169176
def test_from_format_with_locale(text, fmt, expected):

0 commit comments

Comments
 (0)