Merge branch 'master' into less-regex
diff --git a/tests/data/extras/invalid/localtime/incomplete-localtime.toml b/tests/data/extras/invalid/localtime/incomplete-localtime.toml
new file mode 100644
index 0000000..348904c
--- /dev/null
+++ b/tests/data/extras/invalid/localtime/incomplete-localtime.toml
@@ -0,0 +1 @@
+t=23:59:5
diff --git a/tests/data/extras/invalid/localtime/too-many-minutes.toml b/tests/data/extras/invalid/localtime/too-many-minutes.toml
new file mode 100644
index 0000000..9aa1192
--- /dev/null
+++ b/tests/data/extras/invalid/localtime/too-many-minutes.toml
@@ -0,0 +1 @@
+t=23:60:59
diff --git a/tomli/_parser.py b/tomli/_parser.py
index d77a8f6..05d3115 100644
--- a/tomli/_parser.py
+++ b/tomli/_parser.py
@@ -5,14 +5,7 @@
 from types import MappingProxyType
 from typing import Any, BinaryIO, NamedTuple
 
-from tomli._re import (
-    RE_DATETIME,
-    RE_LOCALTIME,
-    RE_NUMBER,
-    match_to_datetime,
-    match_to_localtime,
-    match_to_number,
-)
+from tomli._re import match_to_datetime, match_to_localtime, match_to_number, regex
 from tomli._types import Key, ParseFloat, Pos
 
 ASCII_CTRL = frozenset(chr(i) for i in range(32)) | frozenset(chr(127))
@@ -612,21 +605,31 @@
         return parse_inline_table(src, pos, parse_float)
 
     # Dates and times
-    datetime_match = RE_DATETIME.match(src, pos)
-    if datetime_match:
-        try:
-            datetime_obj = match_to_datetime(datetime_match)
-        except ValueError as e:
-            raise suffixed_err(src, pos, "Invalid date or datetime") from e
-        return datetime_match.end(), datetime_obj
-    localtime_match = RE_LOCALTIME.match(src, pos)
-    if localtime_match:
-        return localtime_match.end(), match_to_localtime(localtime_match)
+    try:
+        fifth_char: str | None = src[pos + 4]
+    except IndexError:
+        fifth_char = None
+    if fifth_char == "-":
+        datetime_match = regex("datetime").match(src, pos)
+        if datetime_match:
+            try:
+                datetime_obj = match_to_datetime(datetime_match)
+            except ValueError as e:
+                raise suffixed_err(src, pos, "Invalid date or datetime") from e
+            return datetime_match.end(), datetime_obj
+    try:
+        third_char: str | None = src[pos + 2]
+    except IndexError:
+        third_char = None
+    if third_char == ":":
+        localtime_match = regex("localtime").match(src, pos)
+        if localtime_match:
+            return localtime_match.end(), match_to_localtime(localtime_match)
 
     # Integers and "normal" floats.
     # The regex will greedily match any type starting with a decimal
     # char, so needs to be located after handling of dates and times.
-    number_match = RE_NUMBER.match(src, pos)
+    number_match = regex("number").match(src, pos)
     if number_match:
         return number_match.end(), match_to_number(number_match, parse_float)
 
diff --git a/tomli/_re.py b/tomli/_re.py
index c13269d..bcec84c 100644
--- a/tomli/_re.py
+++ b/tomli/_re.py
@@ -12,8 +12,26 @@
 # - 00:32:00
 _TIME_RE_STR = r"([01][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])(?:\.([0-9]{1,6})[0-9]*)?"
 
-RE_NUMBER = re.compile(
-    r"""
+
+@lru_cache(maxsize=None)
+def regex(name: str) -> re.Pattern:
+    if name == "datetime":
+        return re.compile(
+            fr"""
+([0-9]{{4}})-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])  # date, e.g. 1988-10-27
+(?:
+    [Tt ]
+    {_TIME_RE_STR}
+    (?:([Zz])|([+-])([01][0-9]|2[0-3]):([0-5][0-9]))?  # optional time offset
+)?
+""",
+            flags=re.VERBOSE,
+        )
+    if name == "localtime":
+        return re.compile(_TIME_RE_STR)
+    # if name == "number":
+    return re.compile(
+        r"""
 0
 (?:
     x[0-9A-Fa-f](?:_?[0-9A-Fa-f])*   # hex
@@ -29,20 +47,8 @@
     (?:[eE][+-]?[0-9](?:_?[0-9])*)?  # optional exponent part
 )
 """,
-    flags=re.VERBOSE,
-)
-RE_LOCALTIME = re.compile(_TIME_RE_STR)
-RE_DATETIME = re.compile(
-    fr"""
-([0-9]{{4}})-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])  # date, e.g. 1988-10-27
-(?:
-    [Tt ]
-    {_TIME_RE_STR}
-    (?:([Zz])|([+-])([01][0-9]|2[0-3]):([0-5][0-9]))?  # optional time offset
-)?
-""",
-    flags=re.VERBOSE,
-)
+        flags=re.VERBOSE,
+    )
 
 
 def match_to_datetime(match: re.Match) -> datetime | date: