Skip to content

Commit cf04be5

Browse files
authored
Merge pull request pandas-dev#19 from Herdi2/refactor-to_time
refactor: Refactor to_time
2 parents 145cdd0 + 3d2b9d3 commit cf04be5

File tree

1 file changed

+75
-56
lines changed

1 file changed

+75
-56
lines changed

pandas/core/tools/times.py

Lines changed: 75 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -54,62 +54,6 @@ def to_time(
5454
if errors not in ("raise", "coerce"):
5555
raise ValueError("errors must be one of 'raise', or 'coerce'.")
5656

57-
def _convert_listlike(arg, format):
58-
if isinstance(arg, (list, tuple)):
59-
arg = np.array(arg, dtype="O")
60-
61-
elif getattr(arg, "ndim", 1) > 1:
62-
raise TypeError(
63-
"arg must be a string, datetime, list, tuple, 1-d array, or Series"
64-
)
65-
66-
arg = np.asarray(arg, dtype="O")
67-
68-
if infer_time_format and format is None:
69-
format = _guess_time_format_for_array(arg)
70-
71-
times: list[time | None] = []
72-
if format is not None:
73-
for element in arg:
74-
try:
75-
times.append(datetime.strptime(element, format).time())
76-
except (ValueError, TypeError) as err:
77-
if errors == "raise":
78-
msg = (
79-
f"Cannot convert {element} to a time with given "
80-
f"format {format}"
81-
)
82-
raise ValueError(msg) from err
83-
times.append(None)
84-
else:
85-
formats = _time_formats[:]
86-
format_found = False
87-
for element in arg:
88-
time_object = None
89-
try:
90-
time_object = time.fromisoformat(element)
91-
except (ValueError, TypeError):
92-
for time_format in formats:
93-
try:
94-
time_object = datetime.strptime(element, time_format).time()
95-
if not format_found:
96-
# Put the found format in front
97-
fmt = formats.pop(formats.index(time_format))
98-
formats.insert(0, fmt)
99-
format_found = True
100-
break
101-
except (ValueError, TypeError):
102-
continue
103-
104-
if time_object is not None:
105-
times.append(time_object)
106-
elif errors == "raise":
107-
raise ValueError(f"Cannot convert arg {arg} to a time")
108-
else:
109-
times.append(None)
110-
111-
return times
112-
11357
if arg is None:
11458
return arg
11559
elif isinstance(arg, time):
@@ -137,6 +81,81 @@ def _convert_listlike(arg, format):
13781
"%I%M%S%p",
13882
]
13983

84+
def _convert_listlike(
85+
arg,
86+
format: str | None = None,
87+
infer_time_format: bool = False,
88+
errors: DateTimeErrorChoices = "raise",
89+
):
90+
if isinstance(arg, (list, tuple)):
91+
arg = np.array(arg, dtype="O")
92+
93+
elif getattr(arg, "ndim", 1) > 1:
94+
raise TypeError(
95+
"arg must be a string, datetime, list, tuple, 1-d array, or Series"
96+
)
97+
98+
arg = np.asarray(arg, dtype="O")
99+
100+
if infer_time_format and format is None:
101+
format = _guess_time_format_for_array(arg)
102+
103+
# Parse times
104+
105+
if format is not None:
106+
return _parse_with_format(arg, format, errors)
107+
else:
108+
return _infer_and_parse(arg,errors)
109+
110+
111+
def _parse_with_format(arg, format, errors):
112+
"""Given format info in input, parse and returns the time."""
113+
times = []
114+
for element in arg:
115+
try:
116+
times.append(datetime.strptime(element, format).time())
117+
except (ValueError, TypeError) as err:
118+
_handle_error(errors, element, format, err, times)
119+
return times
120+
121+
def _infer_and_parse(arg, errors):
122+
"""Lacking format info, infer format from _time_formats array. Parses and returns the time."""
123+
formats = _time_formats[:]
124+
format_found = False
125+
times = []
126+
127+
for element in arg:
128+
time_object = _try_parse_time(element, formats, format_found)
129+
130+
if time_object is not None:
131+
times.append(time_object)
132+
elif errors == "raise":
133+
raise ValueError(f"Cannot convert arg {arg} to a time")
134+
else:
135+
times.append(None)
136+
137+
return times
138+
139+
def _try_parse_time(element, formats, format_found):
140+
"""Attempts parsing an element with different time formats."""
141+
try:
142+
return time.fromisoformat(element)
143+
except (ValueError, TypeError):
144+
for time_format in formats:
145+
try:
146+
parsed_time = datetime.strptime(element, time_format).time()
147+
if not format_found:
148+
formats.insert(0, formats.pop(formats.index(time_format)))
149+
return parsed_time
150+
except (ValueError, TypeError):
151+
continue
152+
return None
153+
154+
def _handle_error(errors, element, format, err, times):
155+
"""Handles errors when parsing times."""
156+
if errors == "raise":
157+
raise ValueError(f"Cannot convert {element} to a time with format {format}") from err
158+
times.append(None)
140159

141160
def _guess_time_format_for_array(arr):
142161
# Try to guess the format based on the first non-NaN element

0 commit comments

Comments
 (0)