|
| 1 | +# -*- coding: utf-8 -*- |
| 2 | +""" |
| 3 | +Tests for Series timezone-related methods |
| 4 | +""" |
| 5 | +from datetime import datetime |
| 6 | + |
| 7 | +import pytest |
| 8 | +import pytz |
| 9 | +import numpy as np |
| 10 | +from dateutil.tz import tzoffset |
| 11 | + |
| 12 | +import pandas.util.testing as tm |
| 13 | +from pandas._libs import tslib |
| 14 | +from pandas._libs.tslibs import timezones |
| 15 | +from pandas.compat import lrange |
| 16 | +from pandas.core.indexes.datetimes import date_range |
| 17 | +from pandas import Series, Timestamp, DatetimeIndex, Index |
| 18 | + |
| 19 | + |
| 20 | +class TestSeriesTimezones(object): |
| 21 | + # ----------------------------------------------------------------- |
| 22 | + # Series.tz_localize |
| 23 | + def test_series_tz_localize(self): |
| 24 | + |
| 25 | + rng = date_range('1/1/2011', periods=100, freq='H') |
| 26 | + ts = Series(1, index=rng) |
| 27 | + |
| 28 | + result = ts.tz_localize('utc') |
| 29 | + assert result.index.tz.zone == 'UTC' |
| 30 | + |
| 31 | + # Can't localize if already tz-aware |
| 32 | + rng = date_range('1/1/2011', periods=100, freq='H', tz='utc') |
| 33 | + ts = Series(1, index=rng) |
| 34 | + tm.assert_raises_regex(TypeError, 'Already tz-aware', |
| 35 | + ts.tz_localize, 'US/Eastern') |
| 36 | + |
| 37 | + def test_series_tz_localize_ambiguous_bool(self): |
| 38 | + # make sure that we are correctly accepting bool values as ambiguous |
| 39 | + |
| 40 | + # GH#14402 |
| 41 | + ts = Timestamp('2015-11-01 01:00:03') |
| 42 | + expected0 = Timestamp('2015-11-01 01:00:03-0500', tz='US/Central') |
| 43 | + expected1 = Timestamp('2015-11-01 01:00:03-0600', tz='US/Central') |
| 44 | + |
| 45 | + ser = Series([ts]) |
| 46 | + expected0 = Series([expected0]) |
| 47 | + expected1 = Series([expected1]) |
| 48 | + |
| 49 | + with pytest.raises(pytz.AmbiguousTimeError): |
| 50 | + ser.dt.tz_localize('US/Central') |
| 51 | + |
| 52 | + result = ser.dt.tz_localize('US/Central', ambiguous=True) |
| 53 | + tm.assert_series_equal(result, expected0) |
| 54 | + |
| 55 | + result = ser.dt.tz_localize('US/Central', ambiguous=[True]) |
| 56 | + tm.assert_series_equal(result, expected0) |
| 57 | + |
| 58 | + result = ser.dt.tz_localize('US/Central', ambiguous=False) |
| 59 | + tm.assert_series_equal(result, expected1) |
| 60 | + |
| 61 | + result = ser.dt.tz_localize('US/Central', ambiguous=[False]) |
| 62 | + tm.assert_series_equal(result, expected1) |
| 63 | + |
| 64 | + @pytest.mark.parametrize('tzstr', ['US/Eastern', 'dateutil/US/Eastern']) |
| 65 | + def test_series_tz_localize_empty(self, tzstr): |
| 66 | + # GH#2248 |
| 67 | + ser = Series() |
| 68 | + |
| 69 | + ser2 = ser.tz_localize('utc') |
| 70 | + assert ser2.index.tz == pytz.utc |
| 71 | + |
| 72 | + ser2 = ser.tz_localize(tzstr) |
| 73 | + timezones.tz_compare(ser2.index.tz, timezones.maybe_get_tz(tzstr)) |
| 74 | + |
| 75 | + # ----------------------------------------------------------------- |
| 76 | + # Series.tz_convert |
| 77 | + |
| 78 | + def test_series_tz_convert(self): |
| 79 | + rng = date_range('1/1/2011', periods=200, freq='D', tz='US/Eastern') |
| 80 | + ts = Series(1, index=rng) |
| 81 | + |
| 82 | + result = ts.tz_convert('Europe/Berlin') |
| 83 | + assert result.index.tz.zone == 'Europe/Berlin' |
| 84 | + |
| 85 | + # can't convert tz-naive |
| 86 | + rng = date_range('1/1/2011', periods=200, freq='D') |
| 87 | + ts = Series(1, index=rng) |
| 88 | + tm.assert_raises_regex(TypeError, "Cannot convert tz-naive", |
| 89 | + ts.tz_convert, 'US/Eastern') |
| 90 | + |
| 91 | + # ----------------------------------------------------------------- |
| 92 | + # Series.append |
| 93 | + |
| 94 | + def test_series_append_aware(self): |
| 95 | + rng1 = date_range('1/1/2011 01:00', periods=1, freq='H', |
| 96 | + tz='US/Eastern') |
| 97 | + rng2 = date_range('1/1/2011 02:00', periods=1, freq='H', |
| 98 | + tz='US/Eastern') |
| 99 | + ser1 = Series([1], index=rng1) |
| 100 | + ser2 = Series([2], index=rng2) |
| 101 | + ts_result = ser1.append(ser2) |
| 102 | + |
| 103 | + exp_index = DatetimeIndex(['2011-01-01 01:00', '2011-01-01 02:00'], |
| 104 | + tz='US/Eastern') |
| 105 | + exp = Series([1, 2], index=exp_index) |
| 106 | + tm.assert_series_equal(ts_result, exp) |
| 107 | + assert ts_result.index.tz == rng1.tz |
| 108 | + |
| 109 | + rng1 = date_range('1/1/2011 01:00', periods=1, freq='H', tz='UTC') |
| 110 | + rng2 = date_range('1/1/2011 02:00', periods=1, freq='H', tz='UTC') |
| 111 | + ser1 = Series([1], index=rng1) |
| 112 | + ser2 = Series([2], index=rng2) |
| 113 | + ts_result = ser1.append(ser2) |
| 114 | + |
| 115 | + exp_index = DatetimeIndex(['2011-01-01 01:00', '2011-01-01 02:00'], |
| 116 | + tz='UTC') |
| 117 | + exp = Series([1, 2], index=exp_index) |
| 118 | + tm.assert_series_equal(ts_result, exp) |
| 119 | + utc = rng1.tz |
| 120 | + assert utc == ts_result.index.tz |
| 121 | + |
| 122 | + # GH#7795 |
| 123 | + # different tz coerces to object dtype, not UTC |
| 124 | + rng1 = date_range('1/1/2011 01:00', periods=1, freq='H', |
| 125 | + tz='US/Eastern') |
| 126 | + rng2 = date_range('1/1/2011 02:00', periods=1, freq='H', |
| 127 | + tz='US/Central') |
| 128 | + ser1 = Series([1], index=rng1) |
| 129 | + ser2 = Series([2], index=rng2) |
| 130 | + ts_result = ser1.append(ser2) |
| 131 | + exp_index = Index([Timestamp('1/1/2011 01:00', tz='US/Eastern'), |
| 132 | + Timestamp('1/1/2011 02:00', tz='US/Central')]) |
| 133 | + exp = Series([1, 2], index=exp_index) |
| 134 | + tm.assert_series_equal(ts_result, exp) |
| 135 | + |
| 136 | + def test_series_append_aware_naive(self): |
| 137 | + rng1 = date_range('1/1/2011 01:00', periods=1, freq='H') |
| 138 | + rng2 = date_range('1/1/2011 02:00', periods=1, freq='H', |
| 139 | + tz='US/Eastern') |
| 140 | + ser1 = Series(np.random.randn(len(rng1)), index=rng1) |
| 141 | + ser2 = Series(np.random.randn(len(rng2)), index=rng2) |
| 142 | + ts_result = ser1.append(ser2) |
| 143 | + |
| 144 | + expected = ser1.index.astype(object).append(ser2.index.astype(object)) |
| 145 | + assert ts_result.index.equals(expected) |
| 146 | + |
| 147 | + # mixed |
| 148 | + rng1 = date_range('1/1/2011 01:00', periods=1, freq='H') |
| 149 | + rng2 = lrange(100) |
| 150 | + ser1 = Series(np.random.randn(len(rng1)), index=rng1) |
| 151 | + ser2 = Series(np.random.randn(len(rng2)), index=rng2) |
| 152 | + ts_result = ser1.append(ser2) |
| 153 | + |
| 154 | + expected = ser1.index.astype(object).append(ser2.index) |
| 155 | + assert ts_result.index.equals(expected) |
| 156 | + |
| 157 | + def test_series_append_dst(self): |
| 158 | + rng1 = date_range('1/1/2016 01:00', periods=3, freq='H', |
| 159 | + tz='US/Eastern') |
| 160 | + rng2 = date_range('8/1/2016 01:00', periods=3, freq='H', |
| 161 | + tz='US/Eastern') |
| 162 | + ser1 = Series([1, 2, 3], index=rng1) |
| 163 | + ser2 = Series([10, 11, 12], index=rng2) |
| 164 | + ts_result = ser1.append(ser2) |
| 165 | + |
| 166 | + exp_index = DatetimeIndex(['2016-01-01 01:00', '2016-01-01 02:00', |
| 167 | + '2016-01-01 03:00', '2016-08-01 01:00', |
| 168 | + '2016-08-01 02:00', '2016-08-01 03:00'], |
| 169 | + tz='US/Eastern') |
| 170 | + exp = Series([1, 2, 3, 10, 11, 12], index=exp_index) |
| 171 | + tm.assert_series_equal(ts_result, exp) |
| 172 | + assert ts_result.index.tz == rng1.tz |
| 173 | + |
| 174 | + # ----------------------------------------------------------------- |
| 175 | + |
| 176 | + def test_dateutil_tzoffset_support(self): |
| 177 | + values = [188.5, 328.25] |
| 178 | + tzinfo = tzoffset(None, 7200) |
| 179 | + index = [datetime(2012, 5, 11, 11, tzinfo=tzinfo), |
| 180 | + datetime(2012, 5, 11, 12, tzinfo=tzinfo)] |
| 181 | + series = Series(data=values, index=index) |
| 182 | + |
| 183 | + assert series.index.tz == tzinfo |
| 184 | + |
| 185 | + # it works! #2443 |
| 186 | + repr(series.index[0]) |
| 187 | + |
| 188 | + @pytest.mark.parametrize('tz', ['US/Eastern', 'dateutil/US/Eastern']) |
| 189 | + def test_tz_aware_asfreq(self, tz): |
| 190 | + dr = date_range('2011-12-01', '2012-07-20', freq='D', tz=tz) |
| 191 | + |
| 192 | + ser = Series(np.random.randn(len(dr)), index=dr) |
| 193 | + |
| 194 | + # it works! |
| 195 | + ser.asfreq('T') |
| 196 | + |
| 197 | + @pytest.mark.parametrize('tz', ['US/Eastern', 'dateutil/US/Eastern']) |
| 198 | + def test_string_index_alias_tz_aware(self, tz): |
| 199 | + rng = date_range('1/1/2000', periods=10, tz=tz) |
| 200 | + ser = Series(np.random.randn(len(rng)), index=rng) |
| 201 | + |
| 202 | + result = ser['1/3/2000'] |
| 203 | + tm.assert_almost_equal(result, ser[2]) |
| 204 | + |
| 205 | + # TODO: De-duplicate with test below |
| 206 | + def test_series_add_tz_mismatch_converts_to_utc_duplicate(self): |
| 207 | + rng = date_range('1/1/2011', periods=10, freq='H', tz='US/Eastern') |
| 208 | + ser = Series(np.random.randn(len(rng)), index=rng) |
| 209 | + |
| 210 | + ts_moscow = ser.tz_convert('Europe/Moscow') |
| 211 | + |
| 212 | + result = ser + ts_moscow |
| 213 | + assert result.index.tz is pytz.utc |
| 214 | + |
| 215 | + result = ts_moscow + ser |
| 216 | + assert result.index.tz is pytz.utc |
| 217 | + |
| 218 | + def test_series_add_tz_mismatch_converts_to_utc(self): |
| 219 | + rng = date_range('1/1/2011', periods=100, freq='H', tz='utc') |
| 220 | + |
| 221 | + perm = np.random.permutation(100)[:90] |
| 222 | + ser1 = Series(np.random.randn(90), |
| 223 | + index=rng.take(perm).tz_convert('US/Eastern')) |
| 224 | + |
| 225 | + perm = np.random.permutation(100)[:90] |
| 226 | + ser2 = Series(np.random.randn(90), |
| 227 | + index=rng.take(perm).tz_convert('Europe/Berlin')) |
| 228 | + |
| 229 | + result = ser1 + ser2 |
| 230 | + |
| 231 | + uts1 = ser1.tz_convert('utc') |
| 232 | + uts2 = ser2.tz_convert('utc') |
| 233 | + expected = uts1 + uts2 |
| 234 | + |
| 235 | + assert result.index.tz == pytz.UTC |
| 236 | + tm.assert_series_equal(result, expected) |
| 237 | + |
| 238 | + def test_series_add_aware_naive_raises(self): |
| 239 | + rng = date_range('1/1/2011', periods=10, freq='H') |
| 240 | + ser = Series(np.random.randn(len(rng)), index=rng) |
| 241 | + |
| 242 | + ser_utc = ser.tz_localize('utc') |
| 243 | + |
| 244 | + with pytest.raises(Exception): |
| 245 | + ser + ser_utc |
| 246 | + |
| 247 | + with pytest.raises(Exception): |
| 248 | + ser_utc + ser |
| 249 | + |
| 250 | + def test_series_align_aware(self): |
| 251 | + idx1 = date_range('2001', periods=5, freq='H', tz='US/Eastern') |
| 252 | + ser = Series(np.random.randn(len(idx1)), index=idx1) |
| 253 | + ser_central = ser.tz_convert('US/Central') |
| 254 | + # # different timezones convert to UTC |
| 255 | + |
| 256 | + new1, new2 = ser.align(ser_central) |
| 257 | + assert new1.index.tz == pytz.UTC |
| 258 | + assert new2.index.tz == pytz.UTC |
| 259 | + |
| 260 | + @pytest.mark.parametrize('tzstr', ['US/Eastern', 'dateutil/US/Eastern']) |
| 261 | + def test_localized_at_time_between_time(self, tzstr): |
| 262 | + from datetime import time |
| 263 | + tz = timezones.maybe_get_tz(tzstr) |
| 264 | + |
| 265 | + rng = date_range('4/16/2012', '5/1/2012', freq='H') |
| 266 | + ts = Series(np.random.randn(len(rng)), index=rng) |
| 267 | + |
| 268 | + ts_local = ts.tz_localize(tzstr) |
| 269 | + |
| 270 | + result = ts_local.at_time(time(10, 0)) |
| 271 | + expected = ts.at_time(time(10, 0)).tz_localize(tzstr) |
| 272 | + tm.assert_series_equal(result, expected) |
| 273 | + assert timezones.tz_compare(result.index.tz, tz) |
| 274 | + |
| 275 | + t1, t2 = time(10, 0), time(11, 0) |
| 276 | + result = ts_local.between_time(t1, t2) |
| 277 | + expected = ts.between_time(t1, t2).tz_localize(tzstr) |
| 278 | + tm.assert_series_equal(result, expected) |
| 279 | + assert timezones.tz_compare(result.index.tz, tz) |
| 280 | + |
| 281 | + @pytest.mark.parametrize('tzstr', ['Europe/Berlin', |
| 282 | + 'dateutil/Europe/Berlin']) |
| 283 | + def test_getitem_pydatetime_tz(self, tzstr): |
| 284 | + tz = timezones.maybe_get_tz(tzstr) |
| 285 | + |
| 286 | + index = date_range(start='2012-12-24 16:00', end='2012-12-24 18:00', |
| 287 | + freq='H', tz=tzstr) |
| 288 | + ts = Series(index=index, data=index.hour) |
| 289 | + time_pandas = Timestamp('2012-12-24 17:00', tz=tzstr) |
| 290 | + |
| 291 | + dt = datetime(2012, 12, 24, 17, 0) |
| 292 | + time_datetime = tslib._localize_pydatetime(dt, tz) |
| 293 | + assert ts[time_pandas] == ts[time_datetime] |
0 commit comments