test_timezones.py 14 KB

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