Skip to content

Commit 91407ff

Browse files
committed
Merge pull request pandas-dev#11627 from jreback/ambiguous
BUG: date_range creation with an ambiguous endpoint, pandas-dev#11619
2 parents e7ff318 + 0e9ce37 commit 91407ff

File tree

5 files changed

+62
-10
lines changed

5 files changed

+62
-10
lines changed

doc/source/whatsnew/v0.17.1.txt

+2-1
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,8 @@ Bug Fixes
120120
- Bug in ``HDFStore.append`` with strings whose encoded length exceded the max unencoded length (:issue:`11234`)
121121
- Bug in merging ``datetime64[ns, tz]`` dtypes (:issue:`11405`)
122122
- Bug in ``HDFStore.select`` when comparing with a numpy scalar in a where clause (:issue:`11283`)
123-
- Bug in using ``DataFrame.ix`` with a multi-index indexer(:issue:`11372`)
123+
- Bug in using ``DataFrame.ix`` with a multi-index indexer (:issue:`11372`)
124+
- Bug in ``date_range`` with ambigous endpoints (:issue:`11626`)
124125
- Prevent adding new attributes to the accessors ``.str``, ``.dt`` and ``.cat``. Retrieving such
125126
a value was not possible, so error out on setting it. (:issue:`10673`)
126127
- Bug in tz-conversions with an ambiguous time and ``.dt`` accessors (:issue:`11295`)

pandas/io/tests/test_pytables.py

+15
Original file line numberDiff line numberDiff line change
@@ -4988,6 +4988,21 @@ def test_legacy_datetimetz_object(self):
49884988
result = store['df']
49894989
assert_frame_equal(result, expected)
49904990

4991+
def test_dst_transitions(self):
4992+
# make sure we are not failing on transaitions
4993+
with ensure_clean_store(self.path) as store:
4994+
times = pd.date_range("2013-10-26 23:00", "2013-10-27 01:00",
4995+
tz="Europe/London",
4996+
freq="H",
4997+
ambiguous='infer')
4998+
4999+
for i in [times, times+pd.Timedelta('10min')]:
5000+
_maybe_remove(store, 'df')
5001+
df = DataFrame({'A' : range(len(i)), 'B' : i }, index=i)
5002+
store.append('df',df)
5003+
result = store.select('df')
5004+
assert_frame_equal(result, df)
5005+
49915006
def _test_sort(obj):
49925007
if isinstance(obj, DataFrame):
49935008
return obj.reindex(sorted(obj.index))

pandas/tests/test_frame.py

+20
Original file line numberDiff line numberDiff line change
@@ -15448,6 +15448,26 @@ def test_to_csv_date_format(self):
1544815448

1544915449
assert_frame_equal(test, nat_frame)
1545015450

15451+
def test_to_csv_with_dst_transitions(self):
15452+
pname = '__tmp_to_csv_date_format_with_dst__'
15453+
with ensure_clean(pname) as path:
15454+
# make sure we are not failing on transitions
15455+
times = pd.date_range("2013-10-26 23:00", "2013-10-27 01:00",
15456+
tz="Europe/London",
15457+
freq="H",
15458+
ambiguous='infer')
15459+
15460+
for i in [times, times+pd.Timedelta('10s')]:
15461+
df = DataFrame({'A' : range(len(i))}, index=i)
15462+
df.to_csv(path,index=True)
15463+
15464+
# we have to reconvert the index as we
15465+
# don't parse the tz's
15466+
result = read_csv(path,index_col=0)
15467+
result.index = pd.to_datetime(result.index).tz_localize('UTC').tz_convert('Europe/London')
15468+
assert_frame_equal(result,df)
15469+
15470+
1545115471
def test_concat_empty_dataframe_dtypes(self):
1545215472
df = DataFrame(columns=list("abc"))
1545315473
df['a'] = df['a'].astype(np.bool_)

pandas/tseries/index.py

+9-9
Original file line numberDiff line numberDiff line change
@@ -355,7 +355,7 @@ def __new__(cls, data=None,
355355
if freq is not None and not freq_infer:
356356
inferred = subarr.inferred_freq
357357
if inferred != freq.freqstr:
358-
on_freq = cls._generate(subarr[0], None, len(subarr), None, freq, tz=tz)
358+
on_freq = cls._generate(subarr[0], None, len(subarr), None, freq, tz=tz, ambiguous=ambiguous)
359359
if not np.array_equal(subarr.asi8, on_freq.asi8):
360360
raise ValueError('Inferred frequency {0} from passed dates does not '
361361
'conform to passed frequency {1}'.format(inferred, freq.freqstr))
@@ -440,17 +440,17 @@ def _generate(cls, start, end, periods, name, offset,
440440
if inferred_tz is None and tz is not None:
441441
# naive dates
442442
if start is not None and start.tz is None:
443-
start = start.tz_localize(tz)
443+
start = start.tz_localize(tz, ambiguous=False)
444444

445445
if end is not None and end.tz is None:
446-
end = end.tz_localize(tz)
446+
end = end.tz_localize(tz, ambiguous=False)
447447

448448
if start and end:
449449
if start.tz is None and end.tz is not None:
450-
start = start.tz_localize(end.tz)
450+
start = start.tz_localize(end.tz, ambiguous=False)
451451

452452
if end.tz is None and start.tz is not None:
453-
end = end.tz_localize(start.tz)
453+
end = end.tz_localize(start.tz, ambiguous=False)
454454

455455
if _use_cached_range(offset, _normalized, start, end):
456456
index = cls._cached_range(start, end, periods=periods,
@@ -1884,7 +1884,7 @@ def _generate_regular_range(start, end, periods, offset):
18841884

18851885

18861886
def date_range(start=None, end=None, periods=None, freq='D', tz=None,
1887-
normalize=False, name=None, closed=None):
1887+
normalize=False, name=None, closed=None, **kwargs):
18881888
"""
18891889
Return a fixed frequency datetime index, with day (calendar) as the default
18901890
frequency
@@ -1920,11 +1920,11 @@ def date_range(start=None, end=None, periods=None, freq='D', tz=None,
19201920
"""
19211921
return DatetimeIndex(start=start, end=end, periods=periods,
19221922
freq=freq, tz=tz, normalize=normalize, name=name,
1923-
closed=closed)
1923+
closed=closed, **kwargs)
19241924

19251925

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

19621962
return DatetimeIndex(start=start, end=end, periods=periods,
19631963
freq=freq, tz=tz, normalize=normalize, name=name,
1964-
closed=closed)
1964+
closed=closed, **kwargs)
19651965

19661966

19671967
def cdate_range(start=None, end=None, periods=None, freq='C', tz=None,

pandas/tseries/tests/test_timezones.py

+16
Original file line numberDiff line numberDiff line change
@@ -502,6 +502,22 @@ def test_ambiguous_flags(self):
502502
localized_is_dst = dr.tz_localize(tz, ambiguous=is_dst)
503503
self.assert_numpy_array_equal(localized, localized_is_dst)
504504

505+
# construction with an ambiguous end-point
506+
# GH 11626
507+
tz=self.tzstr("Europe/London")
508+
509+
def f():
510+
date_range("2013-10-26 23:00", "2013-10-27 01:00",
511+
tz="Europe/London",
512+
freq="H")
513+
self.assertRaises(pytz.AmbiguousTimeError, f)
514+
times = date_range("2013-10-26 23:00", "2013-10-27 01:00",
515+
freq="H",
516+
tz=tz,
517+
ambiguous='infer')
518+
self.assertEqual(times[0],Timestamp('2013-10-26 23:00',tz=tz))
519+
self.assertEqual(times[-1],Timestamp('2013-10-27 01:00',tz=tz))
520+
505521
def test_ambiguous_nat(self):
506522
tz = self.tz('US/Eastern')
507523
times = ['11/06/2011 00:00', '11/06/2011 01:00',

0 commit comments

Comments
 (0)