Skip to content

BUG: timezone offset double counted using date_range and DateTimeIndex.append (fixes #2906, #2938) #2935

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Mar 13, 2013
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 12 additions & 3 deletions pandas/tseries/index.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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:
Expand Down
41 changes: 36 additions & 5 deletions pandas/tseries/tests/test_daterange.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)


Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand Down
37 changes: 30 additions & 7 deletions pandas/tseries/tests/test_timeseries.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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]'))
Expand Down