Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 9c71dbf

Browse files
rockgjreback
authored andcommittedJan 3, 2016
ERR/ENH: between_time checks argument types and new to_time function, #11818
1 parent ab1eb2a commit 9c71dbf

File tree

6 files changed

+296
-78
lines changed

6 files changed

+296
-78
lines changed
 

‎doc/source/whatsnew/v0.18.0.txt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,19 @@ other anchored offsets like ``MonthBegin`` and ``YearBegin``.
266266
Other API Changes
267267
^^^^^^^^^^^^^^^^^
268268

269+
- ``DataFrame.between_time`` and ``Series.between_time`` now only parse a fixed set of time strings. Parsing
270+
of date strings is no longer supported and raises a ValueError. (:issue:`11818`)
271+
272+
.. code-block:: python
273+
274+
In [3]: s = pd.Series(range(10), pd.date_range('2015-01-01', freq='H', periods=10))
275+
276+
In [4]: s.between_time("7:00am", "9:00am")
277+
Out[4]:
278+
2015-01-01 07:00:00 7
279+
2015-01-01 08:00:00 8
280+
2015-01-01 09:00:00 9
281+
Freq: H, dtype: int64
269282

270283

271284

‎pandas/tseries/index.py

Lines changed: 15 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
Resolution)
2222
from pandas.tseries.base import DatelikeOps, TimelikeOps, DatetimeIndexOpsMixin
2323
from pandas.tseries.offsets import DateOffset, generate_range, Tick, CDay
24-
from pandas.tseries.tools import parse_time_string, normalize_date
24+
from pandas.tseries.tools import parse_time_string, normalize_date, to_time
2525
from pandas.tseries.timedeltas import to_timedelta
2626
from pandas.util.decorators import cache_readonly, deprecate_kwarg
2727
import pandas.core.common as com
@@ -109,12 +109,12 @@ def _ensure_datetime64(other):
109109
return other
110110
raise TypeError('%s type object %s' % (type(other), str(other)))
111111

112-
113112
_midnight = time(0, 0)
114113

114+
115115
def _new_DatetimeIndex(cls, d):
116-
""" This is called upon unpickling, rather than the default which doesn't have arguments
117-
and breaks __new__ """
116+
""" This is called upon unpickling, rather than the default which doesn't
117+
have arguments and breaks __new__ """
118118

119119
# data are already in UTC
120120
# so need to localize
@@ -1755,12 +1755,18 @@ def indexer_at_time(self, time, asof=False):
17551755
def indexer_between_time(self, start_time, end_time, include_start=True,
17561756
include_end=True):
17571757
"""
1758-
Select values between particular times of day (e.g., 9:00-9:30AM)
1758+
Select values between particular times of day (e.g., 9:00-9:30AM).
1759+
1760+
Return values of the index between two times. If start_time or
1761+
end_time are strings then tseres.tools.to_time is used to convert to
1762+
a time object.
17591763
17601764
Parameters
17611765
----------
1762-
start_time : datetime.time or string
1763-
end_time : datetime.time or string
1766+
start_time, end_time : datetime.time, str
1767+
datetime.time or string in appropriate format ("%H:%M", "%H%M",
1768+
"%I:%M%p", "%I%M%p", "%H:%M:%S", "%H%M%S", "%I:%M:%S%p",
1769+
"%I%M%S%p")
17641770
include_start : boolean, default True
17651771
include_end : boolean, default True
17661772
tz : string or pytz.timezone or dateutil.tz.tzfile, default None
@@ -1769,18 +1775,8 @@ def indexer_between_time(self, start_time, end_time, include_start=True,
17691775
-------
17701776
values_between_time : TimeSeries
17711777
"""
1772-
from dateutil.parser import parse
1773-
1774-
if isinstance(start_time, compat.string_types):
1775-
start_time = parse(start_time).time()
1776-
1777-
if isinstance(end_time, compat.string_types):
1778-
end_time = parse(end_time).time()
1779-
1780-
if start_time.tzinfo or end_time.tzinfo:
1781-
raise NotImplementedError("argument 'time' with timezone info is "
1782-
"not supported")
1783-
1778+
start_time = to_time(start_time)
1779+
end_time = to_time(end_time)
17841780
time_micros = self._get_time_micros()
17851781
start_micros = _time_to_micros(start_time)
17861782
end_micros = _time_to_micros(end_time)

‎pandas/tseries/tests/test_timeseries.py

Lines changed: 64 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -5,29 +5,27 @@
55
import operator
66
import warnings
77
import nose
8-
98
import numpy as np
10-
randn = np.random.randn
11-
9+
import pandas.tseries.frequencies as frequencies
10+
import pandas.lib as lib
11+
import pandas.tslib as tslib
12+
import pandas.index as _index
13+
import pandas as pd
1214
from pandas import (Index, Series, DataFrame,
1315
isnull, date_range, Timestamp, Period, DatetimeIndex,
1416
Int64Index, to_datetime, bdate_range, Float64Index,
15-
TimedeltaIndex, NaT, timedelta_range, Timedelta)
17+
NaT, timedelta_range, Timedelta)
1618

1719
import pandas.core.datetools as datetools
1820
import pandas.tseries.offsets as offsets
1921
import pandas.tseries.tools as tools
20-
import pandas.tseries.frequencies as frequencies
21-
import pandas as pd
2222

23-
from pandas.util.testing import assert_series_equal, assert_almost_equal
24-
import pandas.util.testing as tm
2523

26-
from pandas.tslib import NaT, iNaT
27-
import pandas.lib as lib
28-
import pandas.tslib as tslib
24+
from pandas.util.testing import assert_series_equal, assert_almost_equal,\
25+
_skip_if_has_locale
26+
import pandas.util.testing as tm
2927

30-
import pandas.index as _index
28+
from pandas.tslib import iNaT
3129

3230
from pandas.compat import range, long, StringIO, lrange, lmap, zip, product
3331
from numpy.random import rand
@@ -40,12 +38,7 @@
4038

4139
from numpy.testing.decorators import slow
4240

43-
44-
def _skip_if_has_locale():
45-
import locale
46-
lang, _ = locale.getlocale()
47-
if lang is not None:
48-
raise nose.SkipTest("Specific locale is set {0}".format(lang))
41+
randn = np.random.randn
4942

5043

5144
class TestTimeSeriesDuplicates(tm.TestCase):
@@ -93,7 +86,8 @@ def test_index_unique(self):
9386
self.assertEqual(idx.nunique(), 20)
9487
self.assertEqual(idx.nunique(dropna=False), 21)
9588

96-
arr = [ Timestamp('2013-06-09 02:42:28') + timedelta(seconds=t) for t in range(20) ] + [NaT]
89+
arr = [Timestamp('2013-06-09 02:42:28') + timedelta(seconds=t) for
90+
t in range(20) ] + [NaT]
9791
idx = DatetimeIndex(arr * 3)
9892
self.assertTrue(idx.unique().equals(DatetimeIndex(arr)))
9993
self.assertEqual(idx.nunique(), 20)
@@ -258,23 +252,29 @@ def test_indexing(self):
258252
assert_series_equal(expected, result)
259253

260254
# GH3546 (not including times on the last day)
261-
idx = date_range(start='2013-05-31 00:00', end='2013-05-31 23:00', freq='H')
255+
idx = date_range(start='2013-05-31 00:00', end='2013-05-31 23:00',
256+
freq='H')
262257
ts = Series(lrange(len(idx)), index=idx)
263258
expected = ts['2013-05']
264259
assert_series_equal(expected, ts)
265260

266-
idx = date_range(start='2013-05-31 00:00', end='2013-05-31 23:59', freq='S')
261+
idx = date_range(start='2013-05-31 00:00', end='2013-05-31 23:59',
262+
freq='S')
267263
ts = Series(lrange(len(idx)), index=idx)
268264
expected = ts['2013-05']
269265
assert_series_equal(expected,ts)
270266

271-
idx = [ Timestamp('2013-05-31 00:00'), Timestamp(datetime(2013,5,31,23,59,59,999999))]
272-
ts = Series(lrange(len(idx)), index=idx)
267+
idx = [Timestamp('2013-05-31 00:00'),
268+
Timestamp(datetime(2013,5,31,23,59,59,999999))]
269+
ts = Series(lrange(len(idx)), index=idx)
273270
expected = ts['2013']
274271
assert_series_equal(expected,ts)
275272

276273
# GH 3925, indexing with a seconds resolution string / datetime object
277-
df = DataFrame(randn(5,5),columns=['open','high','low','close','volume'],index=date_range('2012-01-02 18:01:00',periods=5,tz='US/Central',freq='s'))
274+
df = DataFrame(randn(5,5),
275+
columns=['open', 'high', 'low', 'close', 'volume'],
276+
index=date_range('2012-01-02 18:01:00',
277+
periods=5, tz='US/Central', freq='s'))
278278
expected = df.loc[[df.index[2]]]
279279
result = df['2012-01-02 18:01:02']
280280
assert_frame_equal(result,expected)
@@ -283,14 +283,16 @@ def test_indexing(self):
283283
self.assertRaises(KeyError, df.__getitem__, df.index[2],)
284284

285285
def test_recreate_from_data(self):
286-
freqs = ['M', 'Q', 'A', 'D', 'B', 'BH', 'T', 'S', 'L', 'U', 'H', 'N', 'C']
286+
freqs = ['M', 'Q', 'A', 'D', 'B', 'BH', 'T',
287+
'S', 'L', 'U', 'H', 'N', 'C']
287288

288289
for f in freqs:
289290
org = DatetimeIndex(start='2001/02/01 09:00', freq=f, periods=1)
290291
idx = DatetimeIndex(org, freq=f)
291292
self.assertTrue(idx.equals(org))
292293

293-
org = DatetimeIndex(start='2001/02/01 09:00', freq=f, tz='US/Pacific', periods=1)
294+
org = DatetimeIndex(start='2001/02/01 09:00', freq=f,
295+
tz='US/Pacific', periods=1)
294296
idx = DatetimeIndex(org, freq=f, tz='US/Pacific')
295297
self.assertTrue(idx.equals(org))
296298

@@ -459,7 +461,8 @@ def _check_rng(rng):
459461
self.assertEqual(x.tzinfo, stamp.tzinfo)
460462

461463
rng = date_range('20090415', '20090519')
462-
rng_eastern = date_range('20090415', '20090519', tz=pytz.timezone('US/Eastern'))
464+
rng_eastern = date_range('20090415', '20090519',
465+
tz=pytz.timezone('US/Eastern'))
463466
rng_utc = date_range('20090415', '20090519', tz=pytz.utc)
464467

465468
_check_rng(rng)
@@ -479,7 +482,8 @@ def _check_rng(rng):
479482
self.assertEqual(x.tzinfo, stamp.tzinfo)
480483

481484
rng = date_range('20090415', '20090519')
482-
rng_eastern = date_range('20090415', '20090519', tz='dateutil/US/Eastern')
485+
rng_eastern = date_range('20090415', '20090519',
486+
tz='dateutil/US/Eastern')
483487
rng_utc = date_range('20090415', '20090519', tz=dateutil.tz.tzutc())
484488

485489
_check_rng(rng)
@@ -1524,6 +1528,38 @@ def test_between_time_frame(self):
15241528
else:
15251529
self.assertTrue((t < etime) or (t >= stime))
15261530

1531+
def test_between_time_types(self):
1532+
# GH11818
1533+
rng = date_range('1/1/2000', '1/5/2000', freq='5min')
1534+
self.assertRaises(ValueError, rng.indexer_between_time,
1535+
datetime(2010, 1, 2, 1), datetime(2010, 1, 2, 5))
1536+
1537+
frame = DataFrame({'A': 0}, index=rng)
1538+
self.assertRaises(ValueError, frame.between_time,
1539+
datetime(2010, 1, 2, 1), datetime(2010, 1, 2, 5))
1540+
1541+
series = Series(0, index=rng)
1542+
self.assertRaises(ValueError, series.between_time,
1543+
datetime(2010, 1, 2, 1), datetime(2010, 1, 2, 5))
1544+
1545+
def test_between_time_formats(self):
1546+
# GH11818
1547+
_skip_if_has_locale()
1548+
1549+
rng = date_range('1/1/2000', '1/5/2000', freq='5min')
1550+
ts = DataFrame(np.random.randn(len(rng), 2), index=rng)
1551+
1552+
strings = [("2:00", "2:30"), ("0200", "0230"),
1553+
("2:00am", "2:30am"), ("0200am", "0230am"),
1554+
("2:00:00", "2:30:00"), ("020000", "023000"),
1555+
("2:00:00am", "2:30:00am"), ("020000am", "023000am")]
1556+
expected_length = 28
1557+
1558+
for time_string in strings:
1559+
self.assertEqual(len(ts.between_time(*time_string)),
1560+
expected_length,
1561+
"%s - %s" % time_string)
1562+
15271563
def test_dti_constructor_preserve_dti_freq(self):
15281564
rng = date_range('1/1/2000', '1/2/2000', freq='5min')
15291565

‎pandas/tseries/tests/test_tslib.py

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,7 @@
1515
import pandas.tseries.offsets as offsets
1616
import pandas.util.testing as tm
1717
import pandas.compat as compat
18-
from pandas.util.testing import assert_series_equal
19-
import pandas.compat as compat
18+
from pandas.util.testing import assert_series_equal, _skip_if_has_locale
2019

2120

2221
class TestTimestamp(tm.TestCase):
@@ -617,6 +616,41 @@ def test_parsers_timestring(self):
617616
self.assertEqual(result4, exp_now)
618617
self.assertEqual(result5, exp_now)
619618

619+
def test_parsers_time(self):
620+
# GH11818
621+
_skip_if_has_locale()
622+
strings = ["14:15", "1415", "2:15pm", "0215pm", "14:15:00", "141500",
623+
"2:15:00pm", "021500pm", datetime.time(14, 15)]
624+
expected = datetime.time(14, 15)
625+
626+
for time_string in strings:
627+
self.assertEqual(tools.to_time(time_string), expected)
628+
629+
new_string = "14.15"
630+
self.assertRaises(ValueError, tools.to_time, new_string)
631+
self.assertEqual(tools.to_time(new_string, format="%H.%M"), expected)
632+
tools.add_time_format("%H.%M")
633+
self.assertEqual(tools.to_time(new_string), expected)
634+
635+
arg = ["14:15", "20:20"]
636+
expected_arr = [datetime.time(14, 15), datetime.time(20, 20)]
637+
self.assertEqual(tools.to_time(arg), expected_arr)
638+
self.assertEqual(tools.to_time(arg, format="%H:%M"), expected_arr)
639+
self.assertEqual(tools.to_time(arg, infer_time_format=True),
640+
expected_arr)
641+
self.assertEqual(tools.to_time(arg, format="%I:%M%p", errors="coerce"),
642+
[None, None])
643+
self.assert_numpy_array_equal(tools.to_time(arg, format="%I:%M%p",
644+
errors="ignore"),
645+
np.array(arg))
646+
self.assertRaises(ValueError, lambda: tools.to_time(arg,
647+
format="%I:%M%p",
648+
errors="raise"))
649+
self.assert_series_equal(tools.to_time(Series(arg, name="test")),
650+
Series(expected_arr, name="test"))
651+
self.assert_numpy_array_equal(tools.to_time(np.array(arg)),
652+
np.array(expected_arr))
653+
620654
def test_parsers_monthfreq(self):
621655
cases = {'201101': datetime.datetime(2011, 1, 1, 0, 0),
622656
'200005': datetime.datetime(2000, 5, 1, 0, 0)}

‎pandas/tseries/tools.py

Lines changed: 158 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
1-
from datetime import datetime, timedelta
2-
import re
1+
from datetime import datetime, timedelta, time
32
import sys
43

54
import numpy as np
65

76
import pandas.lib as lib
87
import pandas.tslib as tslib
98
import pandas.core.common as com
10-
from pandas.compat import StringIO, callable
119
from pandas.core.common import ABCIndexClass
1210
import pandas.compat as compat
1311
from pandas.util.decorators import deprecate_kwarg
@@ -33,7 +31,7 @@
3331
if hasattr(_timelex, 'split'):
3432
def _lexer_split_from_str(dt_str):
3533
# The StringIO(str(_)) is for dateutil 2.2 compatibility
36-
return _timelex.split(StringIO(str(dt_str)))
34+
return _timelex.split(compat.StringIO(str(dt_str)))
3735

3836
_DATEUTIL_LEXER_SPLIT = _lexer_split_from_str
3937
except (ImportError, AttributeError):
@@ -68,7 +66,7 @@ def _guess_datetime_format(dt_str, dayfirst=False,
6866
If True parses dates with the day first, eg 20/01/2005
6967
Warning: dayfirst=True is not strict, but will prefer to parse
7068
with day first (this is a known bug).
71-
dt_str_parse : function, defaults to `compate.parse_date` (dateutil)
69+
dt_str_parse : function, defaults to `compat.parse_date` (dateutil)
7270
This function should take in a datetime string and return
7371
a `datetime.datetime` guess that the datetime string represents
7472
dt_str_split : function, defaults to `_DATEUTIL_LEXER_SPLIT` (dateutil)
@@ -78,7 +76,7 @@ def _guess_datetime_format(dt_str, dayfirst=False,
7876
7977
Returns
8078
-------
81-
ret : datetime formatt string (for `strftime` or `strptime`)
79+
ret : datetime format string (for `strftime` or `strptime`)
8280
"""
8381
if dt_str_parse is None or dt_str_split is None:
8482
return None
@@ -329,9 +327,8 @@ def _convert_listlike(arg, box, format, name=None):
329327
# special case
330328
format_is_iso8601 = (
331329
('%Y-%m-%dT%H:%M:%S.%f'.startswith(format) or
332-
'%Y-%m-%d %H:%M:%S.%f'.startswith(format)) and
333-
format != '%Y'
334-
)
330+
'%Y-%m-%d %H:%M:%S.%f'.startswith(format)) and
331+
format != '%Y')
335332
if format_is_iso8601:
336333
require_iso8601 = not infer_datetime_format
337334
format = None
@@ -345,14 +342,15 @@ def _convert_listlike(arg, box, format, name=None):
345342
try:
346343
result = _attempt_YYYYMMDD(arg, errors=errors)
347344
except:
348-
raise ValueError("cannot convert the input to '%Y%m%d' date format")
345+
raise ValueError("cannot convert the input to "
346+
"'%Y%m%d' date format")
349347

350348
# fallback
351349
if result is None:
352350
try:
353351
result = tslib.array_strptime(
354352
arg, format, exact=exact, errors=errors)
355-
except (tslib.OutOfBoundsDatetime):
353+
except tslib.OutOfBoundsDatetime:
356354
if errors == 'raise':
357355
raise
358356
result = arg
@@ -366,14 +364,17 @@ def _convert_listlike(arg, box, format, name=None):
366364
result = arg
367365

368366
if result is None and (format is None or infer_datetime_format):
369-
result = tslib.array_to_datetime(arg, errors=errors,
370-
utc=utc, dayfirst=dayfirst,
371-
yearfirst=yearfirst, freq=freq,
372-
unit=unit,
373-
require_iso8601=require_iso8601)
367+
result = tslib.array_to_datetime(
368+
arg, errors=errors,
369+
utc=utc, dayfirst=dayfirst,
370+
yearfirst=yearfirst,
371+
freq=freq, unit=unit,
372+
require_iso8601=require_iso8601)
374373

375374
if com.is_datetime64_dtype(result) and box:
376-
result = DatetimeIndex(result, tz='utc' if utc else None, name=name)
375+
result = DatetimeIndex(result,
376+
tz='utc' if utc else None,
377+
name=name)
377378
return result
378379

379380
except ValueError as e:
@@ -400,24 +401,28 @@ def _convert_listlike(arg, box, format, name=None):
400401

401402
def _attempt_YYYYMMDD(arg, errors):
402403
""" try to parse the YYYYMMDD/%Y%m%d format, try to deal with NaT-like,
403-
arg is a passed in as an object dtype, but could really be ints/strings with nan-like/or floats (e.g. with nan)
404+
arg is a passed in as an object dtype, but could really be ints/strings
405+
with nan-like/or floats (e.g. with nan)
404406
405-
Parameters
406-
----------
407-
arg : passed value
408-
errors : 'raise','ignore','coerce'
409-
"""
407+
Parameters
408+
----------
409+
arg : passed value
410+
errors : 'raise','ignore','coerce'
411+
"""
410412

411413
def calc(carg):
412414
# calculate the actual result
413415
carg = carg.astype(object)
414-
return tslib.array_to_datetime(lib.try_parse_year_month_day(carg/10000,carg/100 % 100, carg % 100), errors=errors)
416+
return tslib.array_to_datetime(
417+
lib.try_parse_year_month_day(carg/10000, carg/100 % 100,
418+
carg % 100), errors=errors)
415419

416-
def calc_with_mask(carg,mask):
420+
def calc_with_mask(carg, mask):
417421
result = np.empty(carg.shape, dtype='M8[ns]')
418422
iresult = result.view('i8')
419423
iresult[~mask] = tslib.iNaT
420-
result[mask] = calc(carg[mask].astype(np.float64).astype(np.int64)).astype('M8[ns]')
424+
result[mask] = calc(carg[mask].astype(np.float64).astype(np.int64)).\
425+
astype('M8[ns]')
421426
return result
422427

423428
# try intlike / strings that are ints
@@ -475,14 +480,140 @@ def parse_time_string(arg, freq=None, dayfirst=None, yearfirst=None):
475480
if yearfirst is None:
476481
yearfirst = get_option("display.date_yearfirst")
477482

478-
return tslib.parse_datetime_string_with_reso(arg, freq=freq, dayfirst=dayfirst,
483+
return tslib.parse_datetime_string_with_reso(arg, freq=freq,
484+
dayfirst=dayfirst,
479485
yearfirst=yearfirst)
480486

481487

482488
DateParseError = tslib.DateParseError
483489
normalize_date = tslib.normalize_date
484490

485491

492+
# Fixed time formats for time parsing
493+
_time_formats = ["%H:%M", "%H%M", "%I:%M%p", "%I%M%p",
494+
"%H:%M:%S", "%H%M%S", "%I:%M:%S%p", "%I%M%S%p"]
495+
496+
497+
def add_time_format(time_format):
498+
_time_formats.append(time_format)
499+
500+
501+
def _guess_time_format_for_array(arr):
502+
# Try to guess the format based on the first non-NaN element
503+
non_nan_elements = com.notnull(arr).nonzero()[0]
504+
if len(non_nan_elements):
505+
element = arr[non_nan_elements[0]]
506+
for time_format in _time_formats:
507+
try:
508+
datetime.strptime(element, time_format)
509+
return time_format
510+
except ValueError:
511+
pass
512+
513+
return None
514+
515+
516+
def to_time(arg, format=None, infer_time_format=False, errors='raise'):
517+
"""
518+
Parse time strings to time objects using fixed strptime formats ("%H:%M",
519+
"%H%M", "%I:%M%p", "%I%M%p", "%H:%M:%S", "%H%M%S", "%I:%M:%S%p",
520+
"%I%M%S%p")
521+
522+
Use infer_time_format if all the strings are in the same format to speed
523+
up conversion.
524+
525+
Parameters
526+
----------
527+
arg : string in time format, datetime.time, list, tuple, 1-d array, Series
528+
format : str, default None
529+
Format used to convert arg into a time object. If None, fixed formats
530+
are used. Use tools.add_time_format to add an additional fixed format.
531+
infer_time_format: bool, default False
532+
Infer the time format based on the first non-NaN element. If all
533+
strings are in the same format, this will speed up conversion.
534+
errors : {'ignore', 'raise', 'coerce'}, default 'raise'
535+
- If 'raise', then invalid parsing will raise an exception
536+
- If 'coerce', then invalid parsing will be set as None
537+
- If 'ignore', then invalid parsing will return the input
538+
539+
Returns
540+
-------
541+
datetime.time
542+
"""
543+
from pandas.core.series import Series
544+
545+
def _convert_listlike(arg, format):
546+
547+
if isinstance(arg, (list, tuple)):
548+
arg = np.array(arg, dtype='O')
549+
550+
elif getattr(arg, 'ndim', 1) > 1:
551+
raise TypeError('arg must be a string, datetime, list, tuple, '
552+
'1-d array, or Series')
553+
554+
arg = com._ensure_object(arg)
555+
556+
if infer_time_format and format is None:
557+
format = _guess_time_format_for_array(arg)
558+
559+
times = []
560+
if format is not None:
561+
for element in arg:
562+
try:
563+
times.append(datetime.strptime(element, format).time())
564+
except (ValueError, TypeError):
565+
if errors == 'raise':
566+
raise ValueError("Cannot convert %s to a time with "
567+
"given format %s" % (element, format))
568+
elif errors == 'ignore':
569+
return arg
570+
else:
571+
times.append(None)
572+
else:
573+
formats = _time_formats[:]
574+
format_found = False
575+
for element in arg:
576+
time_object = None
577+
for time_format in formats:
578+
try:
579+
time_object = datetime.strptime(element,
580+
time_format).time()
581+
if not format_found:
582+
# Put the found format in front
583+
formats.insert(0, formats.pop(
584+
formats.index(time_format)))
585+
format_found = True
586+
break
587+
except (ValueError, TypeError):
588+
continue
589+
590+
if time_object is not None:
591+
times.append(time_object)
592+
elif errors == 'raise':
593+
raise ValueError("Cannot convert arg %s to a time. Pass "
594+
"in format or add default format." % arg)
595+
elif errors == 'ignore':
596+
return arg
597+
else:
598+
times.append(None)
599+
600+
return times
601+
602+
if arg is None:
603+
return arg
604+
elif isinstance(arg, time):
605+
return arg
606+
elif isinstance(arg, Series):
607+
values = _convert_listlike(arg._values, format)
608+
return Series(values, index=arg.index, name=arg.name)
609+
elif isinstance(arg, ABCIndexClass):
610+
return _convert_listlike(arg, format)
611+
elif com.is_list_like(arg):
612+
return _convert_listlike(arg, format)
613+
614+
return _convert_listlike(np.array([arg]), format)[0]
615+
616+
486617
def format(dt):
487618
"""Returns date in YYYYMMDD format."""
488619
return dt.strftime('%Y%m%d')

‎pandas/util/testing.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -303,11 +303,19 @@ def skip_if_no_ne(engine='numexpr'):
303303
"%s" % ne.__version__)
304304

305305

306+
def _skip_if_has_locale():
307+
import locale
308+
lang, _ = locale.getlocale()
309+
if lang is not None:
310+
import nose
311+
raise nose.SkipTest("Specific locale is set {0}".format(lang))
306312

307-
#------------------------------------------------------------------------------
313+
# -----------------------------------------------------------------------------
308314
# locale utilities
309315

310-
def check_output(*popenargs, **kwargs): # shamelessly taken from Python 2.7 source
316+
317+
def check_output(*popenargs, **kwargs):
318+
# shamelessly taken from Python 2.7 source
311319
r"""Run command with arguments and return its output as a byte string.
312320
313321
If the exit code was non-zero it raises a CalledProcessError. The

0 commit comments

Comments
 (0)
Please sign in to comment.