diff --git a/pandas/tseries/index.py b/pandas/tseries/index.py index c43360036d346..c91a1ebd5568f 100644 --- a/pandas/tseries/index.py +++ b/pandas/tseries/index.py @@ -298,7 +298,11 @@ def _generate(cls, start, end, periods, name, offset, if end is not None: end = Timestamp(end) - inferred_tz = tools._infer_tzinfo(start, end) + try: + inferred_tz = tools._infer_tzinfo(start, end) + except: + raise ValueError('Start and end cannot both be tz-aware with ' + 'different timezones') if tz is not None and inferred_tz is not None: assert(inferred_tz == tz) @@ -1538,17 +1542,21 @@ def _generate_regular_range(start, end, periods, offset): b = Timestamp(start).value e = Timestamp(end).value e += stride - e % stride + # end.tz == start.tz by this point due to _generate implementation + tz = start.tz elif start is not None: b = Timestamp(start).value e = b + periods * stride + tz = start.tz elif end is not None: e = Timestamp(end).value + stride b = e - periods * stride + tz = end.tz else: raise NotImplementedError data = np.arange(b, e, stride, dtype=np.int64) - data = data.view(_NS_DTYPE) + data = DatetimeIndex._simple_new(data, None, tz=tz) else: if isinstance(start, Timestamp): start = start.to_pydatetime() @@ -1723,7 +1731,8 @@ def _process_concat_data(to_concat, name): else: to_concat = [x.values for x in to_concat] - klass = DatetimeIndex + # well, technically not a "class" anymore...oh well + klass = DatetimeIndex._simple_new kwargs = {'tz': tz} concat = com._concat_compat else: diff --git a/pandas/tseries/tests/test_daterange.py b/pandas/tseries/tests/test_daterange.py index 1a844cdb4f77c..29b8d263a2592 100644 --- a/pandas/tseries/tests/test_daterange.py +++ b/pandas/tseries/tests/test_daterange.py @@ -15,10 +15,18 @@ import pandas.core.datetools as datetools +def _skip_if_no_pytz(): + try: + import pytz + except ImportError: + raise nose.SkipTest + + def eq_gen_range(kwargs, expected): rng = generate_range(**kwargs) assert(np.array_equal(list(rng), expected)) + START, END = datetime(2009, 1, 1), datetime(2010, 1, 1) @@ -246,11 +254,11 @@ def test_intersection_bug(self): def test_summary(self): self.rng.summary() self.rng[2:2].summary() - try: - import pytz - bdate_range('1/1/2005', '1/1/2009', tz=pytz.utc).summary() - except Exception: - pass + + def test_summary_pytz(self): + _skip_if_no_pytz() + import pytz + bdate_range('1/1/2005', '1/1/2009', tz=pytz.utc).summary() def test_misc(self): end = datetime(2009, 5, 13) @@ -298,6 +306,29 @@ def test_range_bug(self): exp_values = [start + i * offset for i in range(5)] self.assert_(np.array_equal(result, DatetimeIndex(exp_values))) + def test_range_tz(self): + # GH 2906 + _skip_if_no_pytz() + from pytz import timezone as tz + + start = datetime(2011, 1, 1, tzinfo=tz('US/Eastern')) + end = datetime(2011, 1, 3, tzinfo=tz('US/Eastern')) + + dr = date_range(start=start, periods=3) + self.assert_(dr.tz == tz('US/Eastern')) + self.assert_(dr[0] == start) + self.assert_(dr[2] == end) + + dr = date_range(end=end, periods=3) + self.assert_(dr.tz == tz('US/Eastern')) + self.assert_(dr[0] == start) + self.assert_(dr[2] == end) + + dr = date_range(start=start, end=end) + self.assert_(dr.tz == tz('US/Eastern')) + self.assert_(dr[0] == start) + self.assert_(dr[2] == end) + if __name__ == '__main__': import nose diff --git a/pandas/tseries/tests/test_timeseries.py b/pandas/tseries/tests/test_timeseries.py index 2b42fc5c42542..e43aca8bf764b 100644 --- a/pandas/tseries/tests/test_timeseries.py +++ b/pandas/tseries/tests/test_timeseries.py @@ -42,6 +42,13 @@ from numpy.testing.decorators import slow +def _skip_if_no_pytz(): + try: + import pytz + except ImportError: + raise nose.SkipTest + + class TestTimeSeriesDuplicates(unittest.TestCase): _multiprocess_can_split_ = True @@ -168,13 +175,6 @@ def assert_range_equal(left, right): assert(left.tz == right.tz) -def _skip_if_no_pytz(): - try: - import pytz - except ImportError: - raise nose.SkipTest - - class TestTimeSeries(unittest.TestCase): _multiprocess_can_split_ = True @@ -1265,6 +1265,29 @@ def test_append_concat(self): self.assert_(rng1.append(rng1).name == 'foo') self.assert_(rng1.append(rng2).name is None) + def test_append_concat_tz(self): + #GH 2938 + _skip_if_no_pytz() + + rng = date_range('5/8/2012 1:45', periods=10, freq='5T', + tz='US/Eastern') + rng2 = date_range('5/8/2012 2:35', periods=10, freq='5T', + tz='US/Eastern') + rng3 = date_range('5/8/2012 1:45', periods=20, freq='5T', + tz='US/Eastern') + ts = Series(np.random.randn(len(rng)), rng) + df = DataFrame(np.random.randn(len(rng), 4), index=rng) + ts2 = Series(np.random.randn(len(rng2)), rng2) + df2 = DataFrame(np.random.randn(len(rng2), 4), index=rng2) + + result = ts.append(ts2) + result_df = df.append(df2) + self.assert_(result.index.equals(rng3)) + self.assert_(result_df.index.equals(rng3)) + + appended = rng.append(rng2) + self.assert_(appended.equals(rng3)) + def test_set_dataframe_column_ns_dtype(self): x = DataFrame([datetime.now(), datetime.now()]) self.assert_(x[0].dtype == np.dtype('M8[ns]'))