Skip to content

Commit

Permalink
Merge pull request pandas-dev#11627 from jreback/ambiguous
Browse files Browse the repository at this point in the history
BUG: date_range creation with an ambiguous endpoint, pandas-dev#11619
  • Loading branch information
jreback committed Nov 17, 2015
2 parents e7ff318 + 0e9ce37 commit 91407ff
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 10 deletions.
3 changes: 2 additions & 1 deletion doc/source/whatsnew/v0.17.1.txt
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,8 @@ Bug Fixes
- Bug in ``HDFStore.append`` with strings whose encoded length exceded the max unencoded length (:issue:`11234`)
- Bug in merging ``datetime64[ns, tz]`` dtypes (:issue:`11405`)
- Bug in ``HDFStore.select`` when comparing with a numpy scalar in a where clause (:issue:`11283`)
- Bug in using ``DataFrame.ix`` with a multi-index indexer(:issue:`11372`)
- Bug in using ``DataFrame.ix`` with a multi-index indexer (:issue:`11372`)
- Bug in ``date_range`` with ambigous endpoints (:issue:`11626`)
- Prevent adding new attributes to the accessors ``.str``, ``.dt`` and ``.cat``. Retrieving such
a value was not possible, so error out on setting it. (:issue:`10673`)
- Bug in tz-conversions with an ambiguous time and ``.dt`` accessors (:issue:`11295`)
Expand Down
15 changes: 15 additions & 0 deletions pandas/io/tests/test_pytables.py
Original file line number Diff line number Diff line change
Expand Up @@ -4988,6 +4988,21 @@ def test_legacy_datetimetz_object(self):
result = store['df']
assert_frame_equal(result, expected)

def test_dst_transitions(self):
# make sure we are not failing on transaitions
with ensure_clean_store(self.path) as store:
times = pd.date_range("2013-10-26 23:00", "2013-10-27 01:00",
tz="Europe/London",
freq="H",
ambiguous='infer')

for i in [times, times+pd.Timedelta('10min')]:
_maybe_remove(store, 'df')
df = DataFrame({'A' : range(len(i)), 'B' : i }, index=i)
store.append('df',df)
result = store.select('df')
assert_frame_equal(result, df)

def _test_sort(obj):
if isinstance(obj, DataFrame):
return obj.reindex(sorted(obj.index))
Expand Down
20 changes: 20 additions & 0 deletions pandas/tests/test_frame.py
Original file line number Diff line number Diff line change
Expand Up @@ -15448,6 +15448,26 @@ def test_to_csv_date_format(self):

assert_frame_equal(test, nat_frame)

def test_to_csv_with_dst_transitions(self):
pname = '__tmp_to_csv_date_format_with_dst__'
with ensure_clean(pname) as path:
# make sure we are not failing on transitions
times = pd.date_range("2013-10-26 23:00", "2013-10-27 01:00",
tz="Europe/London",
freq="H",
ambiguous='infer')

for i in [times, times+pd.Timedelta('10s')]:
df = DataFrame({'A' : range(len(i))}, index=i)
df.to_csv(path,index=True)

# we have to reconvert the index as we
# don't parse the tz's
result = read_csv(path,index_col=0)
result.index = pd.to_datetime(result.index).tz_localize('UTC').tz_convert('Europe/London')
assert_frame_equal(result,df)


def test_concat_empty_dataframe_dtypes(self):
df = DataFrame(columns=list("abc"))
df['a'] = df['a'].astype(np.bool_)
Expand Down
18 changes: 9 additions & 9 deletions pandas/tseries/index.py
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,7 @@ def __new__(cls, data=None,
if freq is not None and not freq_infer:
inferred = subarr.inferred_freq
if inferred != freq.freqstr:
on_freq = cls._generate(subarr[0], None, len(subarr), None, freq, tz=tz)
on_freq = cls._generate(subarr[0], None, len(subarr), None, freq, tz=tz, ambiguous=ambiguous)
if not np.array_equal(subarr.asi8, on_freq.asi8):
raise ValueError('Inferred frequency {0} from passed dates does not '
'conform to passed frequency {1}'.format(inferred, freq.freqstr))
Expand Down Expand Up @@ -440,17 +440,17 @@ def _generate(cls, start, end, periods, name, offset,
if inferred_tz is None and tz is not None:
# naive dates
if start is not None and start.tz is None:
start = start.tz_localize(tz)
start = start.tz_localize(tz, ambiguous=False)

if end is not None and end.tz is None:
end = end.tz_localize(tz)
end = end.tz_localize(tz, ambiguous=False)

if start and end:
if start.tz is None and end.tz is not None:
start = start.tz_localize(end.tz)
start = start.tz_localize(end.tz, ambiguous=False)

if end.tz is None and start.tz is not None:
end = end.tz_localize(start.tz)
end = end.tz_localize(start.tz, ambiguous=False)

if _use_cached_range(offset, _normalized, start, end):
index = cls._cached_range(start, end, periods=periods,
Expand Down Expand Up @@ -1884,7 +1884,7 @@ def _generate_regular_range(start, end, periods, offset):


def date_range(start=None, end=None, periods=None, freq='D', tz=None,
normalize=False, name=None, closed=None):
normalize=False, name=None, closed=None, **kwargs):
"""
Return a fixed frequency datetime index, with day (calendar) as the default
frequency
Expand Down Expand Up @@ -1920,11 +1920,11 @@ def date_range(start=None, end=None, periods=None, freq='D', tz=None,
"""
return DatetimeIndex(start=start, end=end, periods=periods,
freq=freq, tz=tz, normalize=normalize, name=name,
closed=closed)
closed=closed, **kwargs)


def bdate_range(start=None, end=None, periods=None, freq='B', tz=None,
normalize=True, name=None, closed=None):
normalize=True, name=None, closed=None, **kwargs):
"""
Return a fixed frequency datetime index, with business day as the default
frequency
Expand Down Expand Up @@ -1961,7 +1961,7 @@ def bdate_range(start=None, end=None, periods=None, freq='B', tz=None,

return DatetimeIndex(start=start, end=end, periods=periods,
freq=freq, tz=tz, normalize=normalize, name=name,
closed=closed)
closed=closed, **kwargs)


def cdate_range(start=None, end=None, periods=None, freq='C', tz=None,
Expand Down
16 changes: 16 additions & 0 deletions pandas/tseries/tests/test_timezones.py
Original file line number Diff line number Diff line change
Expand Up @@ -502,6 +502,22 @@ def test_ambiguous_flags(self):
localized_is_dst = dr.tz_localize(tz, ambiguous=is_dst)
self.assert_numpy_array_equal(localized, localized_is_dst)

# construction with an ambiguous end-point
# GH 11626
tz=self.tzstr("Europe/London")

def f():
date_range("2013-10-26 23:00", "2013-10-27 01:00",
tz="Europe/London",
freq="H")
self.assertRaises(pytz.AmbiguousTimeError, f)
times = date_range("2013-10-26 23:00", "2013-10-27 01:00",
freq="H",
tz=tz,
ambiguous='infer')
self.assertEqual(times[0],Timestamp('2013-10-26 23:00',tz=tz))
self.assertEqual(times[-1],Timestamp('2013-10-27 01:00',tz=tz))

def test_ambiguous_nat(self):
tz = self.tz('US/Eastern')
times = ['11/06/2011 00:00', '11/06/2011 01:00',
Expand Down

0 comments on commit 91407ff

Please sign in to comment.