11from __future__ import annotations
2-
3- from datetime import (
4- datetime ,
5- time ,
6- )
7- from typing import TYPE_CHECKING
8-
2+ from datetime import datetime , time
3+ from typing import TYPE_CHECKING , List , Union
94import numpy as np
10-
115from pandas ._libs .lib import is_list_like
12-
13- from pandas .core .dtypes .generic import (
14- ABCIndex ,
15- ABCSeries ,
16- )
6+ from pandas .core .dtypes .generic import ABCIndex , ABCSeries
177from pandas .core .dtypes .missing import notna
188
199if TYPE_CHECKING :
2010 from pandas ._typing import DateTimeErrorChoices
2111
2212
2313def to_time (
24- arg ,
25- format : str | None = None ,
26- infer_time_format : bool = False ,
27- errors : DateTimeErrorChoices = "raise" ,
14+ arg ,
15+ format : Union [str , List [str ], None ] = None ,
16+ infer_time_format : bool = False ,
17+ errors : DateTimeErrorChoices = "raise" ,
18+ custom_formats : List [str ] = None ,
2819):
2920 """
30- Parse time strings to time objects using fixed strptime formats ("%H:%M",
31- "%H%M", "%I:%M%p", "%I%M%p", "%H:%M:%S", "%H%M%S", "%I:%M:%S%p",
32- "%I%M%S%p")
33-
34- Use infer_time_format if all the strings are in the same format to speed
35- up conversion.
36-
37- Parameters
38- ----------
39- arg : string in time format, datetime.time, list, tuple, 1-d array, Series
40- format : str, default None
41- Format used to convert arg into a time object. If None, fixed formats
42- are used.
43- infer_time_format: bool, default False
44- Infer the time format based on the first non-NaN element. If all
45- strings are in the same format, this will speed up conversion.
46- errors : {'raise', 'coerce'}, default 'raise'
47- - If 'raise', then invalid parsing will raise an exception
48- - If 'coerce', then invalid parsing will be set as None
49-
50- Returns
51- -------
52- datetime.time
53- """
21+ Parse time strings to time objects using fixed strptime formats ("%H:%M",
22+ "%H%M", "%I:%M%p", "%I%M%p", "%H:%M:%S", "%H%M%S", "%I:%M:%S%p",
23+ "%I%M%S%p") and additional custom formats.
24+
25+ Use infer_time_format if all the strings are in the same format to speed
26+ up conversion.
27+
28+ Parameters
29+ ----------
30+ arg : string in time format, datetime.time, list, tuple, 1-d array, Series
31+ format : str or list of str, default None
32+ Format(s) used to convert arg into a time object. If None, fixed
33+ formats are used.
34+ infer_time_format: bool, default False
35+ Infer the time format based on the first non-NaN element. If all
36+ strings are in the same format, this will speed up conversion.
37+ errors : {'raise', 'coerce'}, default 'raise'
38+ - If 'raise', then invalid parsing will raise an exception
39+ - If 'coerce', then invalid parsing will be set as None
40+ custom_formats : list of str, default None
41+ Additional custom time formats to use.
42+ Returns
43+ -------
44+ datetime.time or list of datetime.time
45+ """
5446 if errors not in ("raise" , "coerce" ):
5547 raise ValueError ("errors must be one of 'raise', or 'coerce'." )
5648
@@ -62,28 +54,37 @@ def _convert_listlike(arg, format):
6254 raise TypeError (
6355 "arg must be a string, datetime, list, tuple, 1-d array, or Series"
6456 )
65-
6657 arg = np .asarray (arg , dtype = "O" )
6758
6859 if infer_time_format and format is None :
6960 format = _guess_time_format_for_array (arg )
70-
71- times : list [time | None ] = []
61+ times = []
7262 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 )
63+ if isinstance (format , list ):
64+ for element in arg :
65+ for fmt in format :
66+ try :
67+ times .append (datetime .strptime (element , fmt ).time ())
68+ break
69+ except (ValueError , TypeError ):
70+ continue
71+ else :
72+ if errors == "raise" :
73+ msg = (
74+ f"Cannot convert { element } to a time with given " f"formats { format } " )
75+ raise ValueError (msg )
76+ times .append (None )
77+ else :
78+ for element in arg :
79+ try :
80+ times .append (datetime .strptime (element , format ).time ())
81+ except (ValueError , TypeError ) as err :
82+ if errors == "raise" :
83+ msg = (f"Cannot convert { element } to a time withgiven " f"format { format } " )
84+ raise ValueError (msg ) from err
85+ times .append (None )
8486 else :
85- formats = _time_formats [:]
86- format_found = False
87+ formats = _time_formats + (custom_formats or [])
8788 for element in arg :
8889 time_object = None
8990 try :
@@ -92,22 +93,15 @@ def _convert_listlike(arg, format):
9293 for time_format in formats :
9394 try :
9495 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
10096 break
10197 except (ValueError , TypeError ):
10298 continue
103-
10499 if time_object is not None :
105100 times .append (time_object )
106101 elif errors == "raise" :
107102 raise ValueError (f"Cannot convert arg { arg } to a time" )
108103 else :
109104 times .append (None )
110-
111105 return times
112106
113107 if arg is None :
@@ -121,7 +115,6 @@ def _convert_listlike(arg, format):
121115 return _convert_listlike (arg , format )
122116 elif is_list_like (arg ):
123117 return _convert_listlike (arg , format )
124-
125118 return _convert_listlike (np .array ([arg ]), format )[0 ]
126119
127120
@@ -149,5 +142,4 @@ def _guess_time_format_for_array(arr):
149142 return time_format
150143 except ValueError :
151144 pass
152-
153145 return None
0 commit comments