367 lines
13 KiB
Python
367 lines
13 KiB
Python
"""
|
|
Tests for Series timezone-related methods
|
|
"""
|
|
from datetime import datetime
|
|
|
|
from dateutil.tz import tzoffset
|
|
import numpy as np
|
|
import pytest
|
|
import pytz
|
|
|
|
from pandas._libs.tslibs import conversion, timezones
|
|
|
|
from pandas import DatetimeIndex, Index, NaT, Series, Timestamp
|
|
import pandas._testing as tm
|
|
from pandas.core.indexes.datetimes import date_range
|
|
|
|
|
|
class TestSeriesTimezones:
|
|
# -----------------------------------------------------------------
|
|
# Series.tz_localize
|
|
def test_series_tz_localize(self):
|
|
|
|
rng = date_range("1/1/2011", periods=100, freq="H")
|
|
ts = Series(1, index=rng)
|
|
|
|
result = ts.tz_localize("utc")
|
|
assert result.index.tz.zone == "UTC"
|
|
|
|
# Can't localize if already tz-aware
|
|
rng = date_range("1/1/2011", periods=100, freq="H", tz="utc")
|
|
ts = Series(1, index=rng)
|
|
|
|
with pytest.raises(TypeError, match="Already tz-aware"):
|
|
ts.tz_localize("US/Eastern")
|
|
|
|
def test_series_tz_localize_ambiguous_bool(self):
|
|
# make sure that we are correctly accepting bool values as ambiguous
|
|
|
|
# GH#14402
|
|
ts = Timestamp("2015-11-01 01:00:03")
|
|
expected0 = Timestamp("2015-11-01 01:00:03-0500", tz="US/Central")
|
|
expected1 = Timestamp("2015-11-01 01:00:03-0600", tz="US/Central")
|
|
|
|
ser = Series([ts])
|
|
expected0 = Series([expected0])
|
|
expected1 = Series([expected1])
|
|
|
|
with pytest.raises(pytz.AmbiguousTimeError):
|
|
ser.dt.tz_localize("US/Central")
|
|
|
|
result = ser.dt.tz_localize("US/Central", ambiguous=True)
|
|
tm.assert_series_equal(result, expected0)
|
|
|
|
result = ser.dt.tz_localize("US/Central", ambiguous=[True])
|
|
tm.assert_series_equal(result, expected0)
|
|
|
|
result = ser.dt.tz_localize("US/Central", ambiguous=False)
|
|
tm.assert_series_equal(result, expected1)
|
|
|
|
result = ser.dt.tz_localize("US/Central", ambiguous=[False])
|
|
tm.assert_series_equal(result, expected1)
|
|
|
|
@pytest.mark.parametrize("tz", ["Europe/Warsaw", "dateutil/Europe/Warsaw"])
|
|
@pytest.mark.parametrize(
|
|
"method, exp",
|
|
[
|
|
["shift_forward", "2015-03-29 03:00:00"],
|
|
["NaT", NaT],
|
|
["raise", None],
|
|
["foo", "invalid"],
|
|
],
|
|
)
|
|
def test_series_tz_localize_nonexistent(self, tz, method, exp):
|
|
# GH 8917
|
|
n = 60
|
|
dti = date_range(start="2015-03-29 02:00:00", periods=n, freq="min")
|
|
s = Series(1, dti)
|
|
if method == "raise":
|
|
with pytest.raises(pytz.NonExistentTimeError):
|
|
s.tz_localize(tz, nonexistent=method)
|
|
elif exp == "invalid":
|
|
with pytest.raises(ValueError):
|
|
dti.tz_localize(tz, nonexistent=method)
|
|
else:
|
|
result = s.tz_localize(tz, nonexistent=method)
|
|
expected = Series(1, index=DatetimeIndex([exp] * n, tz=tz))
|
|
tm.assert_series_equal(result, expected)
|
|
|
|
@pytest.mark.parametrize("tzstr", ["US/Eastern", "dateutil/US/Eastern"])
|
|
def test_series_tz_localize_empty(self, tzstr):
|
|
# GH#2248
|
|
ser = Series(dtype=object)
|
|
|
|
ser2 = ser.tz_localize("utc")
|
|
assert ser2.index.tz == pytz.utc
|
|
|
|
ser2 = ser.tz_localize(tzstr)
|
|
timezones.tz_compare(ser2.index.tz, timezones.maybe_get_tz(tzstr))
|
|
|
|
# -----------------------------------------------------------------
|
|
# Series.tz_convert
|
|
|
|
def test_series_tz_convert(self):
|
|
rng = date_range("1/1/2011", periods=200, freq="D", tz="US/Eastern")
|
|
ts = Series(1, index=rng)
|
|
|
|
result = ts.tz_convert("Europe/Berlin")
|
|
assert result.index.tz.zone == "Europe/Berlin"
|
|
|
|
# can't convert tz-naive
|
|
rng = date_range("1/1/2011", periods=200, freq="D")
|
|
ts = Series(1, index=rng)
|
|
|
|
with pytest.raises(TypeError, match="Cannot convert tz-naive"):
|
|
ts.tz_convert("US/Eastern")
|
|
|
|
def test_series_tz_convert_to_utc(self):
|
|
base = DatetimeIndex(["2011-01-01", "2011-01-02", "2011-01-03"], tz="UTC")
|
|
idx1 = base.tz_convert("Asia/Tokyo")[:2]
|
|
idx2 = base.tz_convert("US/Eastern")[1:]
|
|
|
|
res = Series([1, 2], index=idx1) + Series([1, 1], index=idx2)
|
|
tm.assert_series_equal(res, Series([np.nan, 3, np.nan], index=base))
|
|
|
|
# -----------------------------------------------------------------
|
|
# Series.append
|
|
|
|
def test_series_append_aware(self):
|
|
rng1 = date_range("1/1/2011 01:00", periods=1, freq="H", tz="US/Eastern")
|
|
rng2 = date_range("1/1/2011 02:00", periods=1, freq="H", tz="US/Eastern")
|
|
ser1 = Series([1], index=rng1)
|
|
ser2 = Series([2], index=rng2)
|
|
ts_result = ser1.append(ser2)
|
|
|
|
exp_index = DatetimeIndex(
|
|
["2011-01-01 01:00", "2011-01-01 02:00"], tz="US/Eastern"
|
|
)
|
|
exp = Series([1, 2], index=exp_index)
|
|
tm.assert_series_equal(ts_result, exp)
|
|
assert ts_result.index.tz == rng1.tz
|
|
|
|
rng1 = date_range("1/1/2011 01:00", periods=1, freq="H", tz="UTC")
|
|
rng2 = date_range("1/1/2011 02:00", periods=1, freq="H", tz="UTC")
|
|
ser1 = Series([1], index=rng1)
|
|
ser2 = Series([2], index=rng2)
|
|
ts_result = ser1.append(ser2)
|
|
|
|
exp_index = DatetimeIndex(["2011-01-01 01:00", "2011-01-01 02:00"], tz="UTC")
|
|
exp = Series([1, 2], index=exp_index)
|
|
tm.assert_series_equal(ts_result, exp)
|
|
utc = rng1.tz
|
|
assert utc == ts_result.index.tz
|
|
|
|
# GH#7795
|
|
# different tz coerces to object dtype, not UTC
|
|
rng1 = date_range("1/1/2011 01:00", periods=1, freq="H", tz="US/Eastern")
|
|
rng2 = date_range("1/1/2011 02:00", periods=1, freq="H", tz="US/Central")
|
|
ser1 = Series([1], index=rng1)
|
|
ser2 = Series([2], index=rng2)
|
|
ts_result = ser1.append(ser2)
|
|
exp_index = Index(
|
|
[
|
|
Timestamp("1/1/2011 01:00", tz="US/Eastern"),
|
|
Timestamp("1/1/2011 02:00", tz="US/Central"),
|
|
]
|
|
)
|
|
exp = Series([1, 2], index=exp_index)
|
|
tm.assert_series_equal(ts_result, exp)
|
|
|
|
def test_series_append_aware_naive(self):
|
|
rng1 = date_range("1/1/2011 01:00", periods=1, freq="H")
|
|
rng2 = date_range("1/1/2011 02:00", periods=1, freq="H", tz="US/Eastern")
|
|
ser1 = Series(np.random.randn(len(rng1)), index=rng1)
|
|
ser2 = Series(np.random.randn(len(rng2)), index=rng2)
|
|
ts_result = ser1.append(ser2)
|
|
|
|
expected = ser1.index.astype(object).append(ser2.index.astype(object))
|
|
assert ts_result.index.equals(expected)
|
|
|
|
# mixed
|
|
rng1 = date_range("1/1/2011 01:00", periods=1, freq="H")
|
|
rng2 = range(100)
|
|
ser1 = Series(np.random.randn(len(rng1)), index=rng1)
|
|
ser2 = Series(np.random.randn(len(rng2)), index=rng2)
|
|
ts_result = ser1.append(ser2)
|
|
|
|
expected = ser1.index.astype(object).append(ser2.index)
|
|
assert ts_result.index.equals(expected)
|
|
|
|
def test_series_append_dst(self):
|
|
rng1 = date_range("1/1/2016 01:00", periods=3, freq="H", tz="US/Eastern")
|
|
rng2 = date_range("8/1/2016 01:00", periods=3, freq="H", tz="US/Eastern")
|
|
ser1 = Series([1, 2, 3], index=rng1)
|
|
ser2 = Series([10, 11, 12], index=rng2)
|
|
ts_result = ser1.append(ser2)
|
|
|
|
exp_index = DatetimeIndex(
|
|
[
|
|
"2016-01-01 01:00",
|
|
"2016-01-01 02:00",
|
|
"2016-01-01 03:00",
|
|
"2016-08-01 01:00",
|
|
"2016-08-01 02:00",
|
|
"2016-08-01 03:00",
|
|
],
|
|
tz="US/Eastern",
|
|
)
|
|
exp = Series([1, 2, 3, 10, 11, 12], index=exp_index)
|
|
tm.assert_series_equal(ts_result, exp)
|
|
assert ts_result.index.tz == rng1.tz
|
|
|
|
# -----------------------------------------------------------------
|
|
|
|
def test_dateutil_tzoffset_support(self):
|
|
values = [188.5, 328.25]
|
|
tzinfo = tzoffset(None, 7200)
|
|
index = [
|
|
datetime(2012, 5, 11, 11, tzinfo=tzinfo),
|
|
datetime(2012, 5, 11, 12, tzinfo=tzinfo),
|
|
]
|
|
series = Series(data=values, index=index)
|
|
|
|
assert series.index.tz == tzinfo
|
|
|
|
# it works! #2443
|
|
repr(series.index[0])
|
|
|
|
@pytest.mark.parametrize("tz", ["US/Eastern", "dateutil/US/Eastern"])
|
|
def test_tz_aware_asfreq(self, tz):
|
|
dr = date_range("2011-12-01", "2012-07-20", freq="D", tz=tz)
|
|
|
|
ser = Series(np.random.randn(len(dr)), index=dr)
|
|
|
|
# it works!
|
|
ser.asfreq("T")
|
|
|
|
@pytest.mark.parametrize("tz", ["US/Eastern", "dateutil/US/Eastern"])
|
|
def test_string_index_alias_tz_aware(self, tz):
|
|
rng = date_range("1/1/2000", periods=10, tz=tz)
|
|
ser = Series(np.random.randn(len(rng)), index=rng)
|
|
|
|
result = ser["1/3/2000"]
|
|
tm.assert_almost_equal(result, ser[2])
|
|
|
|
# TODO: De-duplicate with test below
|
|
def test_series_add_tz_mismatch_converts_to_utc_duplicate(self):
|
|
rng = date_range("1/1/2011", periods=10, freq="H", tz="US/Eastern")
|
|
ser = Series(np.random.randn(len(rng)), index=rng)
|
|
|
|
ts_moscow = ser.tz_convert("Europe/Moscow")
|
|
|
|
result = ser + ts_moscow
|
|
assert result.index.tz is pytz.utc
|
|
|
|
result = ts_moscow + ser
|
|
assert result.index.tz is pytz.utc
|
|
|
|
def test_series_add_tz_mismatch_converts_to_utc(self):
|
|
rng = date_range("1/1/2011", periods=100, freq="H", tz="utc")
|
|
|
|
perm = np.random.permutation(100)[:90]
|
|
ser1 = Series(
|
|
np.random.randn(90), index=rng.take(perm).tz_convert("US/Eastern")
|
|
)
|
|
|
|
perm = np.random.permutation(100)[:90]
|
|
ser2 = Series(
|
|
np.random.randn(90), index=rng.take(perm).tz_convert("Europe/Berlin")
|
|
)
|
|
|
|
result = ser1 + ser2
|
|
|
|
uts1 = ser1.tz_convert("utc")
|
|
uts2 = ser2.tz_convert("utc")
|
|
expected = uts1 + uts2
|
|
|
|
assert result.index.tz == pytz.UTC
|
|
tm.assert_series_equal(result, expected)
|
|
|
|
def test_series_add_aware_naive_raises(self):
|
|
rng = date_range("1/1/2011", periods=10, freq="H")
|
|
ser = Series(np.random.randn(len(rng)), index=rng)
|
|
|
|
ser_utc = ser.tz_localize("utc")
|
|
|
|
with pytest.raises(Exception):
|
|
ser + ser_utc
|
|
|
|
with pytest.raises(Exception):
|
|
ser_utc + ser
|
|
|
|
def test_series_align_aware(self):
|
|
idx1 = date_range("2001", periods=5, freq="H", tz="US/Eastern")
|
|
ser = Series(np.random.randn(len(idx1)), index=idx1)
|
|
ser_central = ser.tz_convert("US/Central")
|
|
# # different timezones convert to UTC
|
|
|
|
new1, new2 = ser.align(ser_central)
|
|
assert new1.index.tz == pytz.UTC
|
|
assert new2.index.tz == pytz.UTC
|
|
|
|
@pytest.mark.parametrize("tzstr", ["US/Eastern", "dateutil/US/Eastern"])
|
|
def test_localized_at_time_between_time(self, tzstr):
|
|
from datetime import time
|
|
|
|
tz = timezones.maybe_get_tz(tzstr)
|
|
|
|
rng = date_range("4/16/2012", "5/1/2012", freq="H")
|
|
ts = Series(np.random.randn(len(rng)), index=rng)
|
|
|
|
ts_local = ts.tz_localize(tzstr)
|
|
|
|
result = ts_local.at_time(time(10, 0))
|
|
expected = ts.at_time(time(10, 0)).tz_localize(tzstr)
|
|
tm.assert_series_equal(result, expected)
|
|
assert timezones.tz_compare(result.index.tz, tz)
|
|
|
|
t1, t2 = time(10, 0), time(11, 0)
|
|
result = ts_local.between_time(t1, t2)
|
|
expected = ts.between_time(t1, t2).tz_localize(tzstr)
|
|
tm.assert_series_equal(result, expected)
|
|
assert timezones.tz_compare(result.index.tz, tz)
|
|
|
|
@pytest.mark.parametrize("tzstr", ["Europe/Berlin", "dateutil/Europe/Berlin"])
|
|
def test_getitem_pydatetime_tz(self, tzstr):
|
|
tz = timezones.maybe_get_tz(tzstr)
|
|
|
|
index = date_range(
|
|
start="2012-12-24 16:00", end="2012-12-24 18:00", freq="H", tz=tzstr
|
|
)
|
|
ts = Series(index=index, data=index.hour)
|
|
time_pandas = Timestamp("2012-12-24 17:00", tz=tzstr)
|
|
|
|
dt = datetime(2012, 12, 24, 17, 0)
|
|
time_datetime = conversion.localize_pydatetime(dt, tz)
|
|
assert ts[time_pandas] == ts[time_datetime]
|
|
|
|
def test_series_truncate_datetimeindex_tz(self):
|
|
# GH 9243
|
|
idx = date_range("4/1/2005", "4/30/2005", freq="D", tz="US/Pacific")
|
|
s = Series(range(len(idx)), index=idx)
|
|
result = s.truncate(datetime(2005, 4, 2), datetime(2005, 4, 4))
|
|
expected = Series([1, 2, 3], index=idx[1:4])
|
|
tm.assert_series_equal(result, expected)
|
|
|
|
@pytest.mark.parametrize("copy", [True, False])
|
|
@pytest.mark.parametrize(
|
|
"method, tz", [["tz_localize", None], ["tz_convert", "Europe/Berlin"]]
|
|
)
|
|
def test_tz_localize_convert_copy_inplace_mutate(self, copy, method, tz):
|
|
# GH 6326
|
|
result = Series(
|
|
np.arange(0, 5), index=date_range("20131027", periods=5, freq="1H", tz=tz)
|
|
)
|
|
getattr(result, method)("UTC", copy=copy)
|
|
expected = Series(
|
|
np.arange(0, 5), index=date_range("20131027", periods=5, freq="1H", tz=tz)
|
|
)
|
|
tm.assert_series_equal(result, expected)
|
|
|
|
def test_constructor_data_aware_dtype_naive(self, tz_aware_fixture):
|
|
# GH 25843
|
|
tz = tz_aware_fixture
|
|
result = Series([Timestamp("2019", tz=tz)], dtype="datetime64[ns]")
|
|
expected = Series([Timestamp("2019")])
|
|
tm.assert_series_equal(result, expected)
|