test_timezones.py 46 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161
  1. # -*- coding: utf-8 -*-
  2. """
  3. Tests for DatetimeIndex timezone-related methods
  4. """
  5. from datetime import date, datetime, time, timedelta, tzinfo
  6. from distutils.version import LooseVersion
  7. import dateutil
  8. from dateutil.tz import gettz, tzlocal
  9. import numpy as np
  10. import pytest
  11. import pytz
  12. from pandas._libs.tslibs import conversion, timezones
  13. from pandas.compat import PY3, lrange, zip
  14. import pandas.util._test_decorators as td
  15. import pandas as pd
  16. from pandas import (
  17. DatetimeIndex, Index, Timestamp, bdate_range, date_range, isna,
  18. to_datetime)
  19. import pandas.util.testing as tm
  20. class FixedOffset(tzinfo):
  21. """Fixed offset in minutes east from UTC."""
  22. def __init__(self, offset, name):
  23. self.__offset = timedelta(minutes=offset)
  24. self.__name = name
  25. def utcoffset(self, dt):
  26. return self.__offset
  27. def tzname(self, dt):
  28. return self.__name
  29. def dst(self, dt):
  30. return timedelta(0)
  31. fixed_off = FixedOffset(-420, '-07:00')
  32. fixed_off_no_name = FixedOffset(-330, None)
  33. class TestDatetimeIndexTimezones(object):
  34. # -------------------------------------------------------------
  35. # DatetimeIndex.tz_convert
  36. def test_tz_convert_nat(self):
  37. # GH#5546
  38. dates = [pd.NaT]
  39. idx = DatetimeIndex(dates)
  40. idx = idx.tz_localize('US/Pacific')
  41. tm.assert_index_equal(idx, DatetimeIndex(dates, tz='US/Pacific'))
  42. idx = idx.tz_convert('US/Eastern')
  43. tm.assert_index_equal(idx, DatetimeIndex(dates, tz='US/Eastern'))
  44. idx = idx.tz_convert('UTC')
  45. tm.assert_index_equal(idx, DatetimeIndex(dates, tz='UTC'))
  46. dates = ['2010-12-01 00:00', '2010-12-02 00:00', pd.NaT]
  47. idx = DatetimeIndex(dates)
  48. idx = idx.tz_localize('US/Pacific')
  49. tm.assert_index_equal(idx, DatetimeIndex(dates, tz='US/Pacific'))
  50. idx = idx.tz_convert('US/Eastern')
  51. expected = ['2010-12-01 03:00', '2010-12-02 03:00', pd.NaT]
  52. tm.assert_index_equal(idx, DatetimeIndex(expected, tz='US/Eastern'))
  53. idx = idx + pd.offsets.Hour(5)
  54. expected = ['2010-12-01 08:00', '2010-12-02 08:00', pd.NaT]
  55. tm.assert_index_equal(idx, DatetimeIndex(expected, tz='US/Eastern'))
  56. idx = idx.tz_convert('US/Pacific')
  57. expected = ['2010-12-01 05:00', '2010-12-02 05:00', pd.NaT]
  58. tm.assert_index_equal(idx, DatetimeIndex(expected, tz='US/Pacific'))
  59. idx = idx + np.timedelta64(3, 'h')
  60. expected = ['2010-12-01 08:00', '2010-12-02 08:00', pd.NaT]
  61. tm.assert_index_equal(idx, DatetimeIndex(expected, tz='US/Pacific'))
  62. idx = idx.tz_convert('US/Eastern')
  63. expected = ['2010-12-01 11:00', '2010-12-02 11:00', pd.NaT]
  64. tm.assert_index_equal(idx, DatetimeIndex(expected, tz='US/Eastern'))
  65. @pytest.mark.parametrize('prefix', ['', 'dateutil/'])
  66. def test_dti_tz_convert_compat_timestamp(self, prefix):
  67. strdates = ['1/1/2012', '3/1/2012', '4/1/2012']
  68. idx = DatetimeIndex(strdates, tz=prefix + 'US/Eastern')
  69. conv = idx[0].tz_convert(prefix + 'US/Pacific')
  70. expected = idx.tz_convert(prefix + 'US/Pacific')[0]
  71. assert conv == expected
  72. def test_dti_tz_convert_hour_overflow_dst(self):
  73. # Regression test for:
  74. # https://github.com/pandas-dev/pandas/issues/13306
  75. # sorted case US/Eastern -> UTC
  76. ts = ['2008-05-12 09:50:00',
  77. '2008-12-12 09:50:35',
  78. '2009-05-12 09:50:32']
  79. tt = DatetimeIndex(ts).tz_localize('US/Eastern')
  80. ut = tt.tz_convert('UTC')
  81. expected = Index([13, 14, 13])
  82. tm.assert_index_equal(ut.hour, expected)
  83. # sorted case UTC -> US/Eastern
  84. ts = ['2008-05-12 13:50:00',
  85. '2008-12-12 14:50:35',
  86. '2009-05-12 13:50:32']
  87. tt = DatetimeIndex(ts).tz_localize('UTC')
  88. ut = tt.tz_convert('US/Eastern')
  89. expected = Index([9, 9, 9])
  90. tm.assert_index_equal(ut.hour, expected)
  91. # unsorted case US/Eastern -> UTC
  92. ts = ['2008-05-12 09:50:00',
  93. '2008-12-12 09:50:35',
  94. '2008-05-12 09:50:32']
  95. tt = DatetimeIndex(ts).tz_localize('US/Eastern')
  96. ut = tt.tz_convert('UTC')
  97. expected = Index([13, 14, 13])
  98. tm.assert_index_equal(ut.hour, expected)
  99. # unsorted case UTC -> US/Eastern
  100. ts = ['2008-05-12 13:50:00',
  101. '2008-12-12 14:50:35',
  102. '2008-05-12 13:50:32']
  103. tt = DatetimeIndex(ts).tz_localize('UTC')
  104. ut = tt.tz_convert('US/Eastern')
  105. expected = Index([9, 9, 9])
  106. tm.assert_index_equal(ut.hour, expected)
  107. @pytest.mark.parametrize('tz', ['US/Eastern', 'dateutil/US/Eastern'])
  108. def test_dti_tz_convert_hour_overflow_dst_timestamps(self, tz):
  109. # Regression test for GH#13306
  110. # sorted case US/Eastern -> UTC
  111. ts = [Timestamp('2008-05-12 09:50:00', tz=tz),
  112. Timestamp('2008-12-12 09:50:35', tz=tz),
  113. Timestamp('2009-05-12 09:50:32', tz=tz)]
  114. tt = DatetimeIndex(ts)
  115. ut = tt.tz_convert('UTC')
  116. expected = Index([13, 14, 13])
  117. tm.assert_index_equal(ut.hour, expected)
  118. # sorted case UTC -> US/Eastern
  119. ts = [Timestamp('2008-05-12 13:50:00', tz='UTC'),
  120. Timestamp('2008-12-12 14:50:35', tz='UTC'),
  121. Timestamp('2009-05-12 13:50:32', tz='UTC')]
  122. tt = DatetimeIndex(ts)
  123. ut = tt.tz_convert('US/Eastern')
  124. expected = Index([9, 9, 9])
  125. tm.assert_index_equal(ut.hour, expected)
  126. # unsorted case US/Eastern -> UTC
  127. ts = [Timestamp('2008-05-12 09:50:00', tz=tz),
  128. Timestamp('2008-12-12 09:50:35', tz=tz),
  129. Timestamp('2008-05-12 09:50:32', tz=tz)]
  130. tt = DatetimeIndex(ts)
  131. ut = tt.tz_convert('UTC')
  132. expected = Index([13, 14, 13])
  133. tm.assert_index_equal(ut.hour, expected)
  134. # unsorted case UTC -> US/Eastern
  135. ts = [Timestamp('2008-05-12 13:50:00', tz='UTC'),
  136. Timestamp('2008-12-12 14:50:35', tz='UTC'),
  137. Timestamp('2008-05-12 13:50:32', tz='UTC')]
  138. tt = DatetimeIndex(ts)
  139. ut = tt.tz_convert('US/Eastern')
  140. expected = Index([9, 9, 9])
  141. tm.assert_index_equal(ut.hour, expected)
  142. @pytest.mark.parametrize('freq, n', [('H', 1), ('T', 60), ('S', 3600)])
  143. def test_dti_tz_convert_trans_pos_plus_1__bug(self, freq, n):
  144. # Regression test for tslib.tz_convert(vals, tz1, tz2).
  145. # See https://github.com/pandas-dev/pandas/issues/4496 for details.
  146. idx = date_range(datetime(2011, 3, 26, 23),
  147. datetime(2011, 3, 27, 1), freq=freq)
  148. idx = idx.tz_localize('UTC')
  149. idx = idx.tz_convert('Europe/Moscow')
  150. expected = np.repeat(np.array([3, 4, 5]), np.array([n, n, 1]))
  151. tm.assert_index_equal(idx.hour, Index(expected))
  152. def test_dti_tz_convert_dst(self):
  153. for freq, n in [('H', 1), ('T', 60), ('S', 3600)]:
  154. # Start DST
  155. idx = date_range('2014-03-08 23:00', '2014-03-09 09:00', freq=freq,
  156. tz='UTC')
  157. idx = idx.tz_convert('US/Eastern')
  158. expected = np.repeat(np.array([18, 19, 20, 21, 22, 23,
  159. 0, 1, 3, 4, 5]),
  160. np.array([n, n, n, n, n, n, n, n, n, n, 1]))
  161. tm.assert_index_equal(idx.hour, Index(expected))
  162. idx = date_range('2014-03-08 18:00', '2014-03-09 05:00', freq=freq,
  163. tz='US/Eastern')
  164. idx = idx.tz_convert('UTC')
  165. expected = np.repeat(np.array([23, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]),
  166. np.array([n, n, n, n, n, n, n, n, n, n, 1]))
  167. tm.assert_index_equal(idx.hour, Index(expected))
  168. # End DST
  169. idx = date_range('2014-11-01 23:00', '2014-11-02 09:00', freq=freq,
  170. tz='UTC')
  171. idx = idx.tz_convert('US/Eastern')
  172. expected = np.repeat(np.array([19, 20, 21, 22, 23,
  173. 0, 1, 1, 2, 3, 4]),
  174. np.array([n, n, n, n, n, n, n, n, n, n, 1]))
  175. tm.assert_index_equal(idx.hour, Index(expected))
  176. idx = date_range('2014-11-01 18:00', '2014-11-02 05:00', freq=freq,
  177. tz='US/Eastern')
  178. idx = idx.tz_convert('UTC')
  179. expected = np.repeat(np.array([22, 23, 0, 1, 2, 3, 4, 5, 6,
  180. 7, 8, 9, 10]),
  181. np.array([n, n, n, n, n, n, n, n, n,
  182. n, n, n, 1]))
  183. tm.assert_index_equal(idx.hour, Index(expected))
  184. # daily
  185. # Start DST
  186. idx = date_range('2014-03-08 00:00', '2014-03-09 00:00', freq='D',
  187. tz='UTC')
  188. idx = idx.tz_convert('US/Eastern')
  189. tm.assert_index_equal(idx.hour, Index([19, 19]))
  190. idx = date_range('2014-03-08 00:00', '2014-03-09 00:00', freq='D',
  191. tz='US/Eastern')
  192. idx = idx.tz_convert('UTC')
  193. tm.assert_index_equal(idx.hour, Index([5, 5]))
  194. # End DST
  195. idx = date_range('2014-11-01 00:00', '2014-11-02 00:00', freq='D',
  196. tz='UTC')
  197. idx = idx.tz_convert('US/Eastern')
  198. tm.assert_index_equal(idx.hour, Index([20, 20]))
  199. idx = date_range('2014-11-01 00:00', '2014-11-02 000:00', freq='D',
  200. tz='US/Eastern')
  201. idx = idx.tz_convert('UTC')
  202. tm.assert_index_equal(idx.hour, Index([4, 4]))
  203. def test_tz_convert_roundtrip(self, tz_aware_fixture):
  204. tz = tz_aware_fixture
  205. idx1 = date_range(start='2014-01-01', end='2014-12-31', freq='M',
  206. tz='UTC')
  207. exp1 = date_range(start='2014-01-01', end='2014-12-31', freq='M')
  208. idx2 = date_range(start='2014-01-01', end='2014-12-31', freq='D',
  209. tz='UTC')
  210. exp2 = date_range(start='2014-01-01', end='2014-12-31', freq='D')
  211. idx3 = date_range(start='2014-01-01', end='2014-03-01', freq='H',
  212. tz='UTC')
  213. exp3 = date_range(start='2014-01-01', end='2014-03-01', freq='H')
  214. idx4 = date_range(start='2014-08-01', end='2014-10-31', freq='T',
  215. tz='UTC')
  216. exp4 = date_range(start='2014-08-01', end='2014-10-31', freq='T')
  217. for idx, expected in [(idx1, exp1), (idx2, exp2), (idx3, exp3),
  218. (idx4, exp4)]:
  219. converted = idx.tz_convert(tz)
  220. reset = converted.tz_convert(None)
  221. tm.assert_index_equal(reset, expected)
  222. assert reset.tzinfo is None
  223. expected = converted.tz_convert('UTC').tz_localize(None)
  224. tm.assert_index_equal(reset, expected)
  225. def test_dti_tz_convert_tzlocal(self):
  226. # GH#13583
  227. # tz_convert doesn't affect to internal
  228. dti = date_range(start='2001-01-01', end='2001-03-01', tz='UTC')
  229. dti2 = dti.tz_convert(dateutil.tz.tzlocal())
  230. tm.assert_numpy_array_equal(dti2.asi8, dti.asi8)
  231. dti = date_range(start='2001-01-01', end='2001-03-01',
  232. tz=dateutil.tz.tzlocal())
  233. dti2 = dti.tz_convert(None)
  234. tm.assert_numpy_array_equal(dti2.asi8, dti.asi8)
  235. @pytest.mark.parametrize('tz', ['US/Eastern', 'dateutil/US/Eastern',
  236. pytz.timezone('US/Eastern'),
  237. gettz('US/Eastern')])
  238. def test_dti_tz_convert_utc_to_local_no_modify(self, tz):
  239. rng = date_range('3/11/2012', '3/12/2012', freq='H', tz='utc')
  240. rng_eastern = rng.tz_convert(tz)
  241. # Values are unmodified
  242. tm.assert_numpy_array_equal(rng.asi8, rng_eastern.asi8)
  243. assert timezones.tz_compare(rng_eastern.tz, timezones.maybe_get_tz(tz))
  244. @pytest.mark.parametrize('tzstr', ['US/Eastern', 'dateutil/US/Eastern'])
  245. def test_tz_convert_unsorted(self, tzstr):
  246. dr = date_range('2012-03-09', freq='H', periods=100, tz='utc')
  247. dr = dr.tz_convert(tzstr)
  248. result = dr[::-1].hour
  249. exp = dr.hour[::-1]
  250. tm.assert_almost_equal(result, exp)
  251. # -------------------------------------------------------------
  252. # DatetimeIndex.tz_localize
  253. def test_dti_tz_localize_nonexistent_raise_coerce(self):
  254. # GH#13057
  255. times = ['2015-03-08 01:00', '2015-03-08 02:00', '2015-03-08 03:00']
  256. index = DatetimeIndex(times)
  257. tz = 'US/Eastern'
  258. with pytest.raises(pytz.NonExistentTimeError):
  259. index.tz_localize(tz=tz)
  260. with pytest.raises(pytz.NonExistentTimeError):
  261. with tm.assert_produces_warning(FutureWarning):
  262. index.tz_localize(tz=tz, errors='raise')
  263. with tm.assert_produces_warning(FutureWarning,
  264. clear=FutureWarning,
  265. check_stacklevel=False):
  266. result = index.tz_localize(tz=tz, errors='coerce')
  267. test_times = ['2015-03-08 01:00-05:00', 'NaT',
  268. '2015-03-08 03:00-04:00']
  269. dti = to_datetime(test_times, utc=True)
  270. expected = dti.tz_convert('US/Eastern')
  271. tm.assert_index_equal(result, expected)
  272. @pytest.mark.parametrize('tz', [pytz.timezone('US/Eastern'),
  273. gettz('US/Eastern')])
  274. def test_dti_tz_localize_ambiguous_infer(self, tz):
  275. # November 6, 2011, fall back, repeat 2 AM hour
  276. # With no repeated hours, we cannot infer the transition
  277. dr = date_range(datetime(2011, 11, 6, 0), periods=5,
  278. freq=pd.offsets.Hour())
  279. with pytest.raises(pytz.AmbiguousTimeError):
  280. dr.tz_localize(tz)
  281. # With repeated hours, we can infer the transition
  282. dr = date_range(datetime(2011, 11, 6, 0), periods=5,
  283. freq=pd.offsets.Hour(), tz=tz)
  284. times = ['11/06/2011 00:00', '11/06/2011 01:00', '11/06/2011 01:00',
  285. '11/06/2011 02:00', '11/06/2011 03:00']
  286. di = DatetimeIndex(times)
  287. localized = di.tz_localize(tz, ambiguous='infer')
  288. tm.assert_index_equal(dr, localized)
  289. tm.assert_index_equal(dr, DatetimeIndex(times, tz=tz,
  290. ambiguous='infer'))
  291. # When there is no dst transition, nothing special happens
  292. dr = date_range(datetime(2011, 6, 1, 0), periods=10,
  293. freq=pd.offsets.Hour())
  294. localized = dr.tz_localize(tz)
  295. localized_infer = dr.tz_localize(tz, ambiguous='infer')
  296. tm.assert_index_equal(localized, localized_infer)
  297. @pytest.mark.parametrize('tz', [pytz.timezone('US/Eastern'),
  298. gettz('US/Eastern')])
  299. def test_dti_tz_localize_ambiguous_times(self, tz):
  300. # March 13, 2011, spring forward, skip from 2 AM to 3 AM
  301. dr = date_range(datetime(2011, 3, 13, 1, 30), periods=3,
  302. freq=pd.offsets.Hour())
  303. with pytest.raises(pytz.NonExistentTimeError):
  304. dr.tz_localize(tz)
  305. # after dst transition, it works
  306. dr = date_range(datetime(2011, 3, 13, 3, 30), periods=3,
  307. freq=pd.offsets.Hour(), tz=tz)
  308. # November 6, 2011, fall back, repeat 2 AM hour
  309. dr = date_range(datetime(2011, 11, 6, 1, 30), periods=3,
  310. freq=pd.offsets.Hour())
  311. with pytest.raises(pytz.AmbiguousTimeError):
  312. dr.tz_localize(tz)
  313. # UTC is OK
  314. dr = date_range(datetime(2011, 3, 13), periods=48,
  315. freq=pd.offsets.Minute(30), tz=pytz.utc)
  316. @pytest.mark.parametrize('tzstr', ['US/Eastern', 'dateutil/US/Eastern'])
  317. def test_dti_tz_localize_pass_dates_to_utc(self, tzstr):
  318. strdates = ['1/1/2012', '3/1/2012', '4/1/2012']
  319. idx = DatetimeIndex(strdates)
  320. conv = idx.tz_localize(tzstr)
  321. fromdates = DatetimeIndex(strdates, tz=tzstr)
  322. assert conv.tz == fromdates.tz
  323. tm.assert_numpy_array_equal(conv.values, fromdates.values)
  324. @pytest.mark.parametrize('prefix', ['', 'dateutil/'])
  325. def test_dti_tz_localize(self, prefix):
  326. tzstr = prefix + 'US/Eastern'
  327. dti = pd.date_range(start='1/1/2005', end='1/1/2005 0:00:30.256',
  328. freq='L')
  329. dti2 = dti.tz_localize(tzstr)
  330. dti_utc = pd.date_range(start='1/1/2005 05:00',
  331. end='1/1/2005 5:00:30.256', freq='L', tz='utc')
  332. tm.assert_numpy_array_equal(dti2.values, dti_utc.values)
  333. dti3 = dti2.tz_convert(prefix + 'US/Pacific')
  334. tm.assert_numpy_array_equal(dti3.values, dti_utc.values)
  335. dti = pd.date_range(start='11/6/2011 1:59', end='11/6/2011 2:00',
  336. freq='L')
  337. with pytest.raises(pytz.AmbiguousTimeError):
  338. dti.tz_localize(tzstr)
  339. dti = pd.date_range(start='3/13/2011 1:59', end='3/13/2011 2:00',
  340. freq='L')
  341. with pytest.raises(pytz.NonExistentTimeError):
  342. dti.tz_localize(tzstr)
  343. @pytest.mark.parametrize('tz', ['US/Eastern', 'dateutil/US/Eastern',
  344. pytz.timezone('US/Eastern'),
  345. gettz('US/Eastern')])
  346. def test_dti_tz_localize_utc_conversion(self, tz):
  347. # Localizing to time zone should:
  348. # 1) check for DST ambiguities
  349. # 2) convert to UTC
  350. rng = date_range('3/10/2012', '3/11/2012', freq='30T')
  351. converted = rng.tz_localize(tz)
  352. expected_naive = rng + pd.offsets.Hour(5)
  353. tm.assert_numpy_array_equal(converted.asi8, expected_naive.asi8)
  354. # DST ambiguity, this should fail
  355. rng = date_range('3/11/2012', '3/12/2012', freq='30T')
  356. # Is this really how it should fail??
  357. with pytest.raises(pytz.NonExistentTimeError):
  358. rng.tz_localize(tz)
  359. @pytest.mark.parametrize('idx', [
  360. date_range(start='2014-01-01', end='2014-12-31', freq='M'),
  361. date_range(start='2014-01-01', end='2014-12-31', freq='D'),
  362. date_range(start='2014-01-01', end='2014-03-01', freq='H'),
  363. date_range(start='2014-08-01', end='2014-10-31', freq='T')
  364. ])
  365. def test_dti_tz_localize_roundtrip(self, tz_aware_fixture, idx):
  366. tz = tz_aware_fixture
  367. localized = idx.tz_localize(tz)
  368. expected = date_range(start=idx[0], end=idx[-1], freq=idx.freq,
  369. tz=tz)
  370. tm.assert_index_equal(localized, expected)
  371. with pytest.raises(TypeError):
  372. localized.tz_localize(tz)
  373. reset = localized.tz_localize(None)
  374. tm.assert_index_equal(reset, idx)
  375. assert reset.tzinfo is None
  376. def test_dti_tz_localize_naive(self):
  377. rng = date_range('1/1/2011', periods=100, freq='H')
  378. conv = rng.tz_localize('US/Pacific')
  379. exp = date_range('1/1/2011', periods=100, freq='H', tz='US/Pacific')
  380. tm.assert_index_equal(conv, exp)
  381. def test_dti_tz_localize_tzlocal(self):
  382. # GH#13583
  383. offset = dateutil.tz.tzlocal().utcoffset(datetime(2011, 1, 1))
  384. offset = int(offset.total_seconds() * 1000000000)
  385. dti = date_range(start='2001-01-01', end='2001-03-01')
  386. dti2 = dti.tz_localize(dateutil.tz.tzlocal())
  387. tm.assert_numpy_array_equal(dti2.asi8 + offset, dti.asi8)
  388. dti = date_range(start='2001-01-01', end='2001-03-01',
  389. tz=dateutil.tz.tzlocal())
  390. dti2 = dti.tz_localize(None)
  391. tm.assert_numpy_array_equal(dti2.asi8 - offset, dti.asi8)
  392. @pytest.mark.parametrize('tz', [pytz.timezone('US/Eastern'),
  393. gettz('US/Eastern')])
  394. def test_dti_tz_localize_ambiguous_nat(self, tz):
  395. times = ['11/06/2011 00:00', '11/06/2011 01:00', '11/06/2011 01:00',
  396. '11/06/2011 02:00', '11/06/2011 03:00']
  397. di = DatetimeIndex(times)
  398. localized = di.tz_localize(tz, ambiguous='NaT')
  399. times = ['11/06/2011 00:00', np.NaN, np.NaN, '11/06/2011 02:00',
  400. '11/06/2011 03:00']
  401. di_test = DatetimeIndex(times, tz='US/Eastern')
  402. # left dtype is datetime64[ns, US/Eastern]
  403. # right is datetime64[ns, tzfile('/usr/share/zoneinfo/US/Eastern')]
  404. tm.assert_numpy_array_equal(di_test.values, localized.values)
  405. @pytest.mark.parametrize('tz', [pytz.timezone('US/Eastern'),
  406. gettz('US/Eastern')])
  407. def test_dti_tz_localize_ambiguous_flags(self, tz):
  408. # November 6, 2011, fall back, repeat 2 AM hour
  409. # Pass in flags to determine right dst transition
  410. dr = date_range(datetime(2011, 11, 6, 0), periods=5,
  411. freq=pd.offsets.Hour(), tz=tz)
  412. times = ['11/06/2011 00:00', '11/06/2011 01:00', '11/06/2011 01:00',
  413. '11/06/2011 02:00', '11/06/2011 03:00']
  414. # Test tz_localize
  415. di = DatetimeIndex(times)
  416. is_dst = [1, 1, 0, 0, 0]
  417. localized = di.tz_localize(tz, ambiguous=is_dst)
  418. tm.assert_index_equal(dr, localized)
  419. tm.assert_index_equal(dr, DatetimeIndex(times, tz=tz,
  420. ambiguous=is_dst))
  421. localized = di.tz_localize(tz, ambiguous=np.array(is_dst))
  422. tm.assert_index_equal(dr, localized)
  423. localized = di.tz_localize(tz,
  424. ambiguous=np.array(is_dst).astype('bool'))
  425. tm.assert_index_equal(dr, localized)
  426. # Test constructor
  427. localized = DatetimeIndex(times, tz=tz, ambiguous=is_dst)
  428. tm.assert_index_equal(dr, localized)
  429. # Test duplicate times where inferring the dst fails
  430. times += times
  431. di = DatetimeIndex(times)
  432. # When the sizes are incompatible, make sure error is raised
  433. with pytest.raises(Exception):
  434. di.tz_localize(tz, ambiguous=is_dst)
  435. # When sizes are compatible and there are repeats ('infer' won't work)
  436. is_dst = np.hstack((is_dst, is_dst))
  437. localized = di.tz_localize(tz, ambiguous=is_dst)
  438. dr = dr.append(dr)
  439. tm.assert_index_equal(dr, localized)
  440. # When there is no dst transition, nothing special happens
  441. dr = date_range(datetime(2011, 6, 1, 0), periods=10,
  442. freq=pd.offsets.Hour())
  443. is_dst = np.array([1] * 10)
  444. localized = dr.tz_localize(tz)
  445. localized_is_dst = dr.tz_localize(tz, ambiguous=is_dst)
  446. tm.assert_index_equal(localized, localized_is_dst)
  447. # TODO: belongs outside tz_localize tests?
  448. @pytest.mark.parametrize('tz', ['Europe/London', 'dateutil/Europe/London'])
  449. def test_dti_construction_ambiguous_endpoint(self, tz):
  450. # construction with an ambiguous end-point
  451. # GH#11626
  452. # FIXME: This next block fails to raise; it was taken from an older
  453. # version of this test that had an indention mistake that caused it
  454. # to not get executed.
  455. # with pytest.raises(pytz.AmbiguousTimeError):
  456. # date_range("2013-10-26 23:00", "2013-10-27 01:00",
  457. # tz="Europe/London", freq="H")
  458. times = date_range("2013-10-26 23:00", "2013-10-27 01:00", freq="H",
  459. tz=tz, ambiguous='infer')
  460. assert times[0] == Timestamp('2013-10-26 23:00', tz=tz, freq="H")
  461. if str(tz).startswith('dateutil'):
  462. if LooseVersion(dateutil.__version__) < LooseVersion('2.6.0'):
  463. # see GH#14621
  464. assert times[-1] == Timestamp('2013-10-27 01:00:00+0000',
  465. tz=tz, freq="H")
  466. elif LooseVersion(dateutil.__version__) > LooseVersion('2.6.0'):
  467. # fixed ambiguous behavior
  468. assert times[-1] == Timestamp('2013-10-27 01:00:00+0100',
  469. tz=tz, freq="H")
  470. else:
  471. assert times[-1] == Timestamp('2013-10-27 01:00:00+0000',
  472. tz=tz, freq="H")
  473. def test_dti_tz_localize_bdate_range(self):
  474. dr = pd.bdate_range('1/1/2009', '1/1/2010')
  475. dr_utc = pd.bdate_range('1/1/2009', '1/1/2010', tz=pytz.utc)
  476. localized = dr.tz_localize(pytz.utc)
  477. tm.assert_index_equal(dr_utc, localized)
  478. @pytest.mark.parametrize('tz', ['Europe/Warsaw', 'dateutil/Europe/Warsaw'])
  479. @pytest.mark.parametrize('method, exp', [
  480. ['NaT', pd.NaT],
  481. ['raise', None],
  482. ['foo', 'invalid']
  483. ])
  484. def test_dti_tz_localize_nonexistent(self, tz, method, exp):
  485. # GH 8917
  486. n = 60
  487. dti = date_range(start='2015-03-29 02:00:00', periods=n, freq='min')
  488. if method == 'raise':
  489. with pytest.raises(pytz.NonExistentTimeError):
  490. dti.tz_localize(tz, nonexistent=method)
  491. elif exp == 'invalid':
  492. with pytest.raises(ValueError):
  493. dti.tz_localize(tz, nonexistent=method)
  494. else:
  495. result = dti.tz_localize(tz, nonexistent=method)
  496. expected = DatetimeIndex([exp] * n, tz=tz)
  497. tm.assert_index_equal(result, expected)
  498. @pytest.mark.parametrize('start_ts, tz, end_ts, shift', [
  499. ['2015-03-29 02:20:00', 'Europe/Warsaw', '2015-03-29 03:00:00',
  500. 'forward'],
  501. ['2015-03-29 02:20:00', 'Europe/Warsaw',
  502. '2015-03-29 01:59:59.999999999', 'backward'],
  503. ['2015-03-29 02:20:00', 'Europe/Warsaw',
  504. '2015-03-29 03:20:00', timedelta(hours=1)],
  505. ['2015-03-29 02:20:00', 'Europe/Warsaw',
  506. '2015-03-29 01:20:00', timedelta(hours=-1)],
  507. ['2018-03-11 02:33:00', 'US/Pacific', '2018-03-11 03:00:00',
  508. 'forward'],
  509. ['2018-03-11 02:33:00', 'US/Pacific', '2018-03-11 01:59:59.999999999',
  510. 'backward'],
  511. ['2018-03-11 02:33:00', 'US/Pacific', '2018-03-11 03:33:00',
  512. timedelta(hours=1)],
  513. ['2018-03-11 02:33:00', 'US/Pacific', '2018-03-11 01:33:00',
  514. timedelta(hours=-1)]
  515. ])
  516. @pytest.mark.parametrize('tz_type', ['', 'dateutil/'])
  517. def test_dti_tz_localize_nonexistent_shift(self, start_ts, tz,
  518. end_ts, shift,
  519. tz_type):
  520. # GH 8917
  521. tz = tz_type + tz
  522. if isinstance(shift, str):
  523. shift = 'shift_' + shift
  524. dti = DatetimeIndex([Timestamp(start_ts)])
  525. result = dti.tz_localize(tz, nonexistent=shift)
  526. expected = DatetimeIndex([Timestamp(end_ts)]).tz_localize(tz)
  527. tm.assert_index_equal(result, expected)
  528. @pytest.mark.parametrize('offset', [-1, 1])
  529. @pytest.mark.parametrize('tz_type', ['', 'dateutil/'])
  530. def test_dti_tz_localize_nonexistent_shift_invalid(self, offset, tz_type):
  531. # GH 8917
  532. tz = tz_type + 'Europe/Warsaw'
  533. dti = DatetimeIndex([Timestamp('2015-03-29 02:20:00')])
  534. msg = "The provided timedelta will relocalize on a nonexistent time"
  535. with pytest.raises(ValueError, match=msg):
  536. dti.tz_localize(tz, nonexistent=timedelta(seconds=offset))
  537. @pytest.mark.filterwarnings('ignore::FutureWarning')
  538. def test_dti_tz_localize_errors_deprecation(self):
  539. # GH 22644
  540. tz = 'Europe/Warsaw'
  541. n = 60
  542. dti = date_range(start='2015-03-29 02:00:00', periods=n, freq='min')
  543. with tm.assert_produces_warning(FutureWarning, check_stacklevel=False):
  544. with pytest.raises(ValueError):
  545. dti.tz_localize(tz, errors='foo')
  546. # make sure errors='coerce' gets mapped correctly to nonexistent
  547. result = dti.tz_localize(tz, errors='coerce')
  548. expected = dti.tz_localize(tz, nonexistent='NaT')
  549. tm.assert_index_equal(result, expected)
  550. # -------------------------------------------------------------
  551. # DatetimeIndex.normalize
  552. def test_normalize_tz(self):
  553. rng = date_range('1/1/2000 9:30', periods=10, freq='D',
  554. tz='US/Eastern')
  555. result = rng.normalize()
  556. expected = date_range('1/1/2000', periods=10, freq='D',
  557. tz='US/Eastern')
  558. tm.assert_index_equal(result, expected)
  559. assert result.is_normalized
  560. assert not rng.is_normalized
  561. rng = date_range('1/1/2000 9:30', periods=10, freq='D', tz='UTC')
  562. result = rng.normalize()
  563. expected = date_range('1/1/2000', periods=10, freq='D', tz='UTC')
  564. tm.assert_index_equal(result, expected)
  565. assert result.is_normalized
  566. assert not rng.is_normalized
  567. rng = date_range('1/1/2000 9:30', periods=10, freq='D', tz=tzlocal())
  568. result = rng.normalize()
  569. expected = date_range('1/1/2000', periods=10, freq='D', tz=tzlocal())
  570. tm.assert_index_equal(result, expected)
  571. assert result.is_normalized
  572. assert not rng.is_normalized
  573. @td.skip_if_windows
  574. @pytest.mark.parametrize('timezone', ['US/Pacific', 'US/Eastern', 'UTC',
  575. 'Asia/Kolkata', 'Asia/Shanghai',
  576. 'Australia/Canberra'])
  577. def test_normalize_tz_local(self, timezone):
  578. # GH#13459
  579. with tm.set_timezone(timezone):
  580. rng = date_range('1/1/2000 9:30', periods=10, freq='D',
  581. tz=tzlocal())
  582. result = rng.normalize()
  583. expected = date_range('1/1/2000', periods=10, freq='D',
  584. tz=tzlocal())
  585. tm.assert_index_equal(result, expected)
  586. assert result.is_normalized
  587. assert not rng.is_normalized
  588. # ------------------------------------------------------------
  589. # DatetimeIndex.__new__
  590. @pytest.mark.parametrize('prefix', ['', 'dateutil/'])
  591. def test_dti_constructor_static_tzinfo(self, prefix):
  592. # it works!
  593. index = DatetimeIndex([datetime(2012, 1, 1)], tz=prefix + 'EST')
  594. index.hour
  595. index[0]
  596. def test_dti_constructor_with_fixed_tz(self):
  597. off = FixedOffset(420, '+07:00')
  598. start = datetime(2012, 3, 11, 5, 0, 0, tzinfo=off)
  599. end = datetime(2012, 6, 11, 5, 0, 0, tzinfo=off)
  600. rng = date_range(start=start, end=end)
  601. assert off == rng.tz
  602. rng2 = date_range(start, periods=len(rng), tz=off)
  603. tm.assert_index_equal(rng, rng2)
  604. rng3 = date_range('3/11/2012 05:00:00+07:00',
  605. '6/11/2012 05:00:00+07:00')
  606. assert (rng.values == rng3.values).all()
  607. @pytest.mark.parametrize('tzstr', ['US/Eastern', 'dateutil/US/Eastern'])
  608. def test_dti_convert_datetime_list(self, tzstr):
  609. dr = date_range('2012-06-02', periods=10,
  610. tz=tzstr, name='foo')
  611. dr2 = DatetimeIndex(list(dr), name='foo')
  612. tm.assert_index_equal(dr, dr2)
  613. assert dr.tz == dr2.tz
  614. assert dr2.name == 'foo'
  615. def test_dti_construction_univalent(self):
  616. rng = date_range('03/12/2012 00:00', periods=10, freq='W-FRI',
  617. tz='US/Eastern')
  618. rng2 = DatetimeIndex(data=rng, tz='US/Eastern')
  619. tm.assert_index_equal(rng, rng2)
  620. @pytest.mark.parametrize('tz', [pytz.timezone('US/Eastern'),
  621. gettz('US/Eastern')])
  622. def test_dti_from_tzaware_datetime(self, tz):
  623. d = [datetime(2012, 8, 19, tzinfo=tz)]
  624. index = DatetimeIndex(d)
  625. assert timezones.tz_compare(index.tz, tz)
  626. @pytest.mark.parametrize('tzstr', ['US/Eastern', 'dateutil/US/Eastern'])
  627. def test_dti_tz_constructors(self, tzstr):
  628. """ Test different DatetimeIndex constructions with timezone
  629. Follow-up of GH#4229
  630. """
  631. arr = ['11/10/2005 08:00:00', '11/10/2005 09:00:00']
  632. idx1 = to_datetime(arr).tz_localize(tzstr)
  633. idx2 = pd.date_range(start="2005-11-10 08:00:00", freq='H', periods=2,
  634. tz=tzstr)
  635. idx3 = DatetimeIndex(arr, tz=tzstr)
  636. idx4 = DatetimeIndex(np.array(arr), tz=tzstr)
  637. for other in [idx2, idx3, idx4]:
  638. tm.assert_index_equal(idx1, other)
  639. # -------------------------------------------------------------
  640. # Unsorted
  641. def test_join_utc_convert(self, join_type):
  642. rng = date_range('1/1/2011', periods=100, freq='H', tz='utc')
  643. left = rng.tz_convert('US/Eastern')
  644. right = rng.tz_convert('Europe/Berlin')
  645. result = left.join(left[:-5], how=join_type)
  646. assert isinstance(result, DatetimeIndex)
  647. assert result.tz == left.tz
  648. result = left.join(right[:-5], how=join_type)
  649. assert isinstance(result, DatetimeIndex)
  650. assert result.tz.zone == 'UTC'
  651. @pytest.mark.parametrize("dtype", [
  652. None, 'datetime64[ns, CET]',
  653. 'datetime64[ns, EST]', 'datetime64[ns, UTC]'
  654. ])
  655. def test_date_accessor(self, dtype):
  656. # Regression test for GH#21230
  657. expected = np.array([date(2018, 6, 4), pd.NaT])
  658. index = DatetimeIndex(['2018-06-04 10:00:00', pd.NaT], dtype=dtype)
  659. result = index.date
  660. tm.assert_numpy_array_equal(result, expected)
  661. @pytest.mark.parametrize("dtype", [
  662. None, 'datetime64[ns, CET]',
  663. 'datetime64[ns, EST]', 'datetime64[ns, UTC]'
  664. ])
  665. def test_time_accessor(self, dtype):
  666. # Regression test for GH#21267
  667. expected = np.array([time(10, 20, 30), pd.NaT])
  668. index = DatetimeIndex(['2018-06-04 10:20:30', pd.NaT], dtype=dtype)
  669. result = index.time
  670. tm.assert_numpy_array_equal(result, expected)
  671. def test_timetz_accessor(self, tz_naive_fixture):
  672. # GH21358
  673. tz = timezones.maybe_get_tz(tz_naive_fixture)
  674. expected = np.array([time(10, 20, 30, tzinfo=tz), pd.NaT])
  675. index = DatetimeIndex(['2018-06-04 10:20:30', pd.NaT], tz=tz)
  676. result = index.timetz
  677. tm.assert_numpy_array_equal(result, expected)
  678. def test_dti_drop_dont_lose_tz(self):
  679. # GH#2621
  680. ind = date_range("2012-12-01", periods=10, tz="utc")
  681. ind = ind.drop(ind[-1])
  682. assert ind.tz is not None
  683. def test_drop_dst_boundary(self):
  684. # see gh-18031
  685. tz = "Europe/Brussels"
  686. freq = "15min"
  687. start = pd.Timestamp("201710290100", tz=tz)
  688. end = pd.Timestamp("201710290300", tz=tz)
  689. index = pd.date_range(start=start, end=end, freq=freq)
  690. expected = DatetimeIndex(["201710290115", "201710290130",
  691. "201710290145", "201710290200",
  692. "201710290215", "201710290230",
  693. "201710290245", "201710290200",
  694. "201710290215", "201710290230",
  695. "201710290245", "201710290300"],
  696. tz=tz, freq=freq,
  697. ambiguous=[True, True, True, True,
  698. True, True, True, False,
  699. False, False, False, False])
  700. result = index.drop(index[0])
  701. tm.assert_index_equal(result, expected)
  702. def test_date_range_localize(self):
  703. rng = date_range('3/11/2012 03:00', periods=15, freq='H',
  704. tz='US/Eastern')
  705. rng2 = DatetimeIndex(['3/11/2012 03:00', '3/11/2012 04:00'],
  706. tz='US/Eastern')
  707. rng3 = date_range('3/11/2012 03:00', periods=15, freq='H')
  708. rng3 = rng3.tz_localize('US/Eastern')
  709. tm.assert_index_equal(rng, rng3)
  710. # DST transition time
  711. val = rng[0]
  712. exp = Timestamp('3/11/2012 03:00', tz='US/Eastern')
  713. assert val.hour == 3
  714. assert exp.hour == 3
  715. assert val == exp # same UTC value
  716. tm.assert_index_equal(rng[:2], rng2)
  717. # Right before the DST transition
  718. rng = date_range('3/11/2012 00:00', periods=2, freq='H',
  719. tz='US/Eastern')
  720. rng2 = DatetimeIndex(['3/11/2012 00:00', '3/11/2012 01:00'],
  721. tz='US/Eastern')
  722. tm.assert_index_equal(rng, rng2)
  723. exp = Timestamp('3/11/2012 00:00', tz='US/Eastern')
  724. assert exp.hour == 0
  725. assert rng[0] == exp
  726. exp = Timestamp('3/11/2012 01:00', tz='US/Eastern')
  727. assert exp.hour == 1
  728. assert rng[1] == exp
  729. rng = date_range('3/11/2012 00:00', periods=10, freq='H',
  730. tz='US/Eastern')
  731. assert rng[2].hour == 3
  732. def test_timestamp_equality_different_timezones(self):
  733. utc_range = date_range('1/1/2000', periods=20, tz='UTC')
  734. eastern_range = utc_range.tz_convert('US/Eastern')
  735. berlin_range = utc_range.tz_convert('Europe/Berlin')
  736. for a, b, c in zip(utc_range, eastern_range, berlin_range):
  737. assert a == b
  738. assert b == c
  739. assert a == c
  740. assert (utc_range == eastern_range).all()
  741. assert (utc_range == berlin_range).all()
  742. assert (berlin_range == eastern_range).all()
  743. def test_dti_intersection(self):
  744. rng = date_range('1/1/2011', periods=100, freq='H', tz='utc')
  745. left = rng[10:90][::-1]
  746. right = rng[20:80][::-1]
  747. assert left.tz == rng.tz
  748. result = left.intersection(right)
  749. assert result.tz == left.tz
  750. def test_dti_equals_with_tz(self):
  751. left = date_range('1/1/2011', periods=100, freq='H', tz='utc')
  752. right = date_range('1/1/2011', periods=100, freq='H', tz='US/Eastern')
  753. assert not left.equals(right)
  754. @pytest.mark.parametrize('tzstr', ['US/Eastern', 'dateutil/US/Eastern'])
  755. def test_dti_tz_nat(self, tzstr):
  756. idx = DatetimeIndex([Timestamp("2013-1-1", tz=tzstr), pd.NaT])
  757. assert isna(idx[1])
  758. assert idx[0].tzinfo is not None
  759. @pytest.mark.parametrize('tzstr', ['US/Eastern', 'dateutil/US/Eastern'])
  760. def test_dti_astype_asobject_tzinfos(self, tzstr):
  761. # GH#1345
  762. # dates around a dst transition
  763. rng = date_range('2/13/2010', '5/6/2010', tz=tzstr)
  764. objs = rng.astype(object)
  765. for i, x in enumerate(objs):
  766. exval = rng[i]
  767. assert x == exval
  768. assert x.tzinfo == exval.tzinfo
  769. objs = rng.astype(object)
  770. for i, x in enumerate(objs):
  771. exval = rng[i]
  772. assert x == exval
  773. assert x.tzinfo == exval.tzinfo
  774. @pytest.mark.parametrize('tzstr', ['US/Eastern', 'dateutil/US/Eastern'])
  775. def test_dti_with_timezone_repr(self, tzstr):
  776. rng = date_range('4/13/2010', '5/6/2010')
  777. rng_eastern = rng.tz_localize(tzstr)
  778. rng_repr = repr(rng_eastern)
  779. assert '2010-04-13 00:00:00' in rng_repr
  780. @pytest.mark.parametrize('tzstr', ['US/Eastern', 'dateutil/US/Eastern'])
  781. def test_dti_take_dont_lose_meta(self, tzstr):
  782. rng = date_range('1/1/2000', periods=20, tz=tzstr)
  783. result = rng.take(lrange(5))
  784. assert result.tz == rng.tz
  785. assert result.freq == rng.freq
  786. @pytest.mark.parametrize('tzstr', ['US/Eastern', 'dateutil/US/Eastern'])
  787. def test_utc_box_timestamp_and_localize(self, tzstr):
  788. tz = timezones.maybe_get_tz(tzstr)
  789. rng = date_range('3/11/2012', '3/12/2012', freq='H', tz='utc')
  790. rng_eastern = rng.tz_convert(tzstr)
  791. expected = rng[-1].astimezone(tz)
  792. stamp = rng_eastern[-1]
  793. assert stamp == expected
  794. assert stamp.tzinfo == expected.tzinfo
  795. # right tzinfo
  796. rng = date_range('3/13/2012', '3/14/2012', freq='H', tz='utc')
  797. rng_eastern = rng.tz_convert(tzstr)
  798. # test not valid for dateutil timezones.
  799. # assert 'EDT' in repr(rng_eastern[0].tzinfo)
  800. assert ('EDT' in repr(rng_eastern[0].tzinfo) or
  801. 'tzfile' in repr(rng_eastern[0].tzinfo))
  802. def test_dti_to_pydatetime(self):
  803. dt = dateutil.parser.parse('2012-06-13T01:39:00Z')
  804. dt = dt.replace(tzinfo=tzlocal())
  805. arr = np.array([dt], dtype=object)
  806. result = to_datetime(arr, utc=True)
  807. assert result.tz is pytz.utc
  808. rng = date_range('2012-11-03 03:00', '2012-11-05 03:00', tz=tzlocal())
  809. arr = rng.to_pydatetime()
  810. result = to_datetime(arr, utc=True)
  811. assert result.tz is pytz.utc
  812. def test_dti_to_pydatetime_fizedtz(self):
  813. dates = np.array([datetime(2000, 1, 1, tzinfo=fixed_off),
  814. datetime(2000, 1, 2, tzinfo=fixed_off),
  815. datetime(2000, 1, 3, tzinfo=fixed_off)])
  816. dti = DatetimeIndex(dates)
  817. result = dti.to_pydatetime()
  818. tm.assert_numpy_array_equal(dates, result)
  819. result = dti._mpl_repr()
  820. tm.assert_numpy_array_equal(dates, result)
  821. @pytest.mark.parametrize('tz', [pytz.timezone('US/Central'),
  822. gettz('US/Central')])
  823. def test_with_tz(self, tz):
  824. # just want it to work
  825. start = datetime(2011, 3, 12, tzinfo=pytz.utc)
  826. dr = bdate_range(start, periods=50, freq=pd.offsets.Hour())
  827. assert dr.tz is pytz.utc
  828. # DateRange with naive datetimes
  829. dr = bdate_range('1/1/2005', '1/1/2009', tz=pytz.utc)
  830. dr = bdate_range('1/1/2005', '1/1/2009', tz=tz)
  831. # normalized
  832. central = dr.tz_convert(tz)
  833. assert central.tz is tz
  834. naive = central[0].to_pydatetime().replace(tzinfo=None)
  835. comp = conversion.localize_pydatetime(naive, tz).tzinfo
  836. assert central[0].tz is comp
  837. # compare vs a localized tz
  838. naive = dr[0].to_pydatetime().replace(tzinfo=None)
  839. comp = conversion.localize_pydatetime(naive, tz).tzinfo
  840. assert central[0].tz is comp
  841. # datetimes with tzinfo set
  842. dr = bdate_range(datetime(2005, 1, 1, tzinfo=pytz.utc),
  843. datetime(2009, 1, 1, tzinfo=pytz.utc))
  844. with pytest.raises(Exception):
  845. bdate_range(datetime(2005, 1, 1, tzinfo=pytz.utc), '1/1/2009',
  846. tz=tz)
  847. @pytest.mark.parametrize('prefix', ['', 'dateutil/'])
  848. def test_field_access_localize(self, prefix):
  849. strdates = ['1/1/2012', '3/1/2012', '4/1/2012']
  850. rng = DatetimeIndex(strdates, tz=prefix + 'US/Eastern')
  851. assert (rng.hour == 0).all()
  852. # a more unusual time zone, #1946
  853. dr = date_range('2011-10-02 00:00', freq='h', periods=10,
  854. tz=prefix + 'America/Atikokan')
  855. expected = Index(np.arange(10, dtype=np.int64))
  856. tm.assert_index_equal(dr.hour, expected)
  857. @pytest.mark.parametrize('tz', [pytz.timezone('US/Eastern'),
  858. gettz('US/Eastern')])
  859. def test_dti_convert_tz_aware_datetime_datetime(self, tz):
  860. # GH#1581
  861. dates = [datetime(2000, 1, 1), datetime(2000, 1, 2),
  862. datetime(2000, 1, 3)]
  863. dates_aware = [conversion.localize_pydatetime(x, tz) for x in dates]
  864. result = DatetimeIndex(dates_aware)
  865. assert timezones.tz_compare(result.tz, tz)
  866. converted = to_datetime(dates_aware, utc=True)
  867. ex_vals = np.array([Timestamp(x).value for x in dates_aware])
  868. tm.assert_numpy_array_equal(converted.asi8, ex_vals)
  869. assert converted.tz is pytz.utc
  870. def test_dti_union_aware(self):
  871. # non-overlapping
  872. rng = date_range("2012-11-15 00:00:00", periods=6, freq="H",
  873. tz="US/Central")
  874. rng2 = date_range("2012-11-15 12:00:00", periods=6, freq="H",
  875. tz="US/Eastern")
  876. result = rng.union(rng2)
  877. assert result.tz.zone == 'UTC'
  878. @pytest.mark.parametrize('tz', [None, 'UTC', "US/Central",
  879. dateutil.tz.tzoffset(None, -28800)])
  880. @pytest.mark.usefixtures("datetime_tz_utc")
  881. @pytest.mark.skipif(not PY3, reason="datetime.timezone not in PY2")
  882. def test_iteration_preserves_nanoseconds(self, tz):
  883. # GH 19603
  884. index = DatetimeIndex(["2018-02-08 15:00:00.168456358",
  885. "2018-02-08 15:00:00.168456359"], tz=tz)
  886. for i, ts in enumerate(index):
  887. assert ts == index[i]
  888. class TestDateRange(object):
  889. """Tests for date_range with timezones"""
  890. def test_hongkong_tz_convert(self):
  891. # GH#1673 smoke test
  892. dr = date_range('2012-01-01', '2012-01-10', freq='D', tz='Hongkong')
  893. # it works!
  894. dr.hour
  895. @pytest.mark.parametrize('tzstr', ['US/Eastern', 'dateutil/US/Eastern'])
  896. def test_date_range_span_dst_transition(self, tzstr):
  897. # GH#1778
  898. # Standard -> Daylight Savings Time
  899. dr = date_range('03/06/2012 00:00', periods=200, freq='W-FRI',
  900. tz='US/Eastern')
  901. assert (dr.hour == 0).all()
  902. dr = date_range('2012-11-02', periods=10, tz=tzstr)
  903. result = dr.hour
  904. expected = Index([0] * 10)
  905. tm.assert_index_equal(result, expected)
  906. @pytest.mark.parametrize('tzstr', ['US/Eastern', 'dateutil/US/Eastern'])
  907. def test_date_range_timezone_str_argument(self, tzstr):
  908. tz = timezones.maybe_get_tz(tzstr)
  909. result = date_range('1/1/2000', periods=10, tz=tzstr)
  910. expected = date_range('1/1/2000', periods=10, tz=tz)
  911. tm.assert_index_equal(result, expected)
  912. def test_date_range_with_fixedoffset_noname(self):
  913. off = fixed_off_no_name
  914. start = datetime(2012, 3, 11, 5, 0, 0, tzinfo=off)
  915. end = datetime(2012, 6, 11, 5, 0, 0, tzinfo=off)
  916. rng = date_range(start=start, end=end)
  917. assert off == rng.tz
  918. idx = Index([start, end])
  919. assert off == idx.tz
  920. @pytest.mark.parametrize('tzstr', ['US/Eastern', 'dateutil/US/Eastern'])
  921. def test_date_range_with_tz(self, tzstr):
  922. stamp = Timestamp('3/11/2012 05:00', tz=tzstr)
  923. assert stamp.hour == 5
  924. rng = date_range('3/11/2012 04:00', periods=10, freq='H',
  925. tz=tzstr)
  926. assert stamp == rng[1]
  927. class TestToDatetime(object):
  928. """Tests for the to_datetime constructor with timezones"""
  929. def test_to_datetime_utc(self):
  930. arr = np.array([dateutil.parser.parse('2012-06-13T01:39:00Z')],
  931. dtype=object)
  932. result = to_datetime(arr, utc=True)
  933. assert result.tz is pytz.utc
  934. def test_to_datetime_fixed_offset(self):
  935. dates = [datetime(2000, 1, 1, tzinfo=fixed_off),
  936. datetime(2000, 1, 2, tzinfo=fixed_off),
  937. datetime(2000, 1, 3, tzinfo=fixed_off)]
  938. result = to_datetime(dates)
  939. assert result.tz == fixed_off