1""" 2Tests for DatetimeIndex timezone-related methods 3""" 4from datetime import date, datetime, time, timedelta, tzinfo 5 6import dateutil 7from dateutil.tz import gettz, tzlocal 8import numpy as np 9import pytest 10import pytz 11 12from pandas._libs.tslibs import conversion, timezones 13import pandas.util._test_decorators as td 14 15import pandas as pd 16from pandas import ( 17 DatetimeIndex, 18 Index, 19 Timestamp, 20 bdate_range, 21 date_range, 22 isna, 23 to_datetime, 24) 25import pandas._testing as tm 26 27 28class FixedOffset(tzinfo): 29 """Fixed offset in minutes east from UTC.""" 30 31 def __init__(self, offset, name): 32 self.__offset = timedelta(minutes=offset) 33 self.__name = name 34 35 def utcoffset(self, dt): 36 return self.__offset 37 38 def tzname(self, dt): 39 return self.__name 40 41 def dst(self, dt): 42 return timedelta(0) 43 44 45fixed_off = FixedOffset(-420, "-07:00") 46fixed_off_no_name = FixedOffset(-330, None) 47 48 49class TestDatetimeIndexTimezones: 50 # ------------------------------------------------------------- 51 # DatetimeIndex.tz_convert 52 def test_tz_convert_nat(self): 53 # GH#5546 54 dates = [pd.NaT] 55 idx = DatetimeIndex(dates) 56 idx = idx.tz_localize("US/Pacific") 57 tm.assert_index_equal(idx, DatetimeIndex(dates, tz="US/Pacific")) 58 idx = idx.tz_convert("US/Eastern") 59 tm.assert_index_equal(idx, DatetimeIndex(dates, tz="US/Eastern")) 60 idx = idx.tz_convert("UTC") 61 tm.assert_index_equal(idx, DatetimeIndex(dates, tz="UTC")) 62 63 dates = ["2010-12-01 00:00", "2010-12-02 00:00", pd.NaT] 64 idx = DatetimeIndex(dates) 65 idx = idx.tz_localize("US/Pacific") 66 tm.assert_index_equal(idx, DatetimeIndex(dates, tz="US/Pacific")) 67 idx = idx.tz_convert("US/Eastern") 68 expected = ["2010-12-01 03:00", "2010-12-02 03:00", pd.NaT] 69 tm.assert_index_equal(idx, DatetimeIndex(expected, tz="US/Eastern")) 70 71 idx = idx + pd.offsets.Hour(5) 72 expected = ["2010-12-01 08:00", "2010-12-02 08:00", pd.NaT] 73 tm.assert_index_equal(idx, DatetimeIndex(expected, tz="US/Eastern")) 74 idx = idx.tz_convert("US/Pacific") 75 expected = ["2010-12-01 05:00", "2010-12-02 05:00", pd.NaT] 76 tm.assert_index_equal(idx, DatetimeIndex(expected, tz="US/Pacific")) 77 78 idx = idx + np.timedelta64(3, "h") 79 expected = ["2010-12-01 08:00", "2010-12-02 08:00", pd.NaT] 80 tm.assert_index_equal(idx, DatetimeIndex(expected, tz="US/Pacific")) 81 82 idx = idx.tz_convert("US/Eastern") 83 expected = ["2010-12-01 11:00", "2010-12-02 11:00", pd.NaT] 84 tm.assert_index_equal(idx, DatetimeIndex(expected, tz="US/Eastern")) 85 86 @pytest.mark.parametrize("prefix", ["", "dateutil/"]) 87 def test_dti_tz_convert_compat_timestamp(self, prefix): 88 strdates = ["1/1/2012", "3/1/2012", "4/1/2012"] 89 idx = DatetimeIndex(strdates, tz=prefix + "US/Eastern") 90 91 conv = idx[0].tz_convert(prefix + "US/Pacific") 92 expected = idx.tz_convert(prefix + "US/Pacific")[0] 93 94 assert conv == expected 95 96 def test_dti_tz_convert_hour_overflow_dst(self): 97 # Regression test for: 98 # https://github.com/pandas-dev/pandas/issues/13306 99 100 # sorted case US/Eastern -> UTC 101 ts = ["2008-05-12 09:50:00", "2008-12-12 09:50:35", "2009-05-12 09:50:32"] 102 tt = DatetimeIndex(ts).tz_localize("US/Eastern") 103 ut = tt.tz_convert("UTC") 104 expected = Index([13, 14, 13]) 105 tm.assert_index_equal(ut.hour, expected) 106 107 # sorted case UTC -> US/Eastern 108 ts = ["2008-05-12 13:50:00", "2008-12-12 14:50:35", "2009-05-12 13:50:32"] 109 tt = DatetimeIndex(ts).tz_localize("UTC") 110 ut = tt.tz_convert("US/Eastern") 111 expected = Index([9, 9, 9]) 112 tm.assert_index_equal(ut.hour, expected) 113 114 # unsorted case US/Eastern -> UTC 115 ts = ["2008-05-12 09:50:00", "2008-12-12 09:50:35", "2008-05-12 09:50:32"] 116 tt = DatetimeIndex(ts).tz_localize("US/Eastern") 117 ut = tt.tz_convert("UTC") 118 expected = Index([13, 14, 13]) 119 tm.assert_index_equal(ut.hour, expected) 120 121 # unsorted case UTC -> US/Eastern 122 ts = ["2008-05-12 13:50:00", "2008-12-12 14:50:35", "2008-05-12 13:50:32"] 123 tt = DatetimeIndex(ts).tz_localize("UTC") 124 ut = tt.tz_convert("US/Eastern") 125 expected = Index([9, 9, 9]) 126 tm.assert_index_equal(ut.hour, expected) 127 128 @pytest.mark.parametrize("tz", ["US/Eastern", "dateutil/US/Eastern"]) 129 def test_dti_tz_convert_hour_overflow_dst_timestamps(self, tz): 130 # Regression test for GH#13306 131 132 # sorted case US/Eastern -> UTC 133 ts = [ 134 Timestamp("2008-05-12 09:50:00", tz=tz), 135 Timestamp("2008-12-12 09:50:35", tz=tz), 136 Timestamp("2009-05-12 09:50:32", tz=tz), 137 ] 138 tt = DatetimeIndex(ts) 139 ut = tt.tz_convert("UTC") 140 expected = Index([13, 14, 13]) 141 tm.assert_index_equal(ut.hour, expected) 142 143 # sorted case UTC -> US/Eastern 144 ts = [ 145 Timestamp("2008-05-12 13:50:00", tz="UTC"), 146 Timestamp("2008-12-12 14:50:35", tz="UTC"), 147 Timestamp("2009-05-12 13:50:32", tz="UTC"), 148 ] 149 tt = DatetimeIndex(ts) 150 ut = tt.tz_convert("US/Eastern") 151 expected = Index([9, 9, 9]) 152 tm.assert_index_equal(ut.hour, expected) 153 154 # unsorted case US/Eastern -> UTC 155 ts = [ 156 Timestamp("2008-05-12 09:50:00", tz=tz), 157 Timestamp("2008-12-12 09:50:35", tz=tz), 158 Timestamp("2008-05-12 09:50:32", tz=tz), 159 ] 160 tt = DatetimeIndex(ts) 161 ut = tt.tz_convert("UTC") 162 expected = Index([13, 14, 13]) 163 tm.assert_index_equal(ut.hour, expected) 164 165 # unsorted case UTC -> US/Eastern 166 ts = [ 167 Timestamp("2008-05-12 13:50:00", tz="UTC"), 168 Timestamp("2008-12-12 14:50:35", tz="UTC"), 169 Timestamp("2008-05-12 13:50:32", tz="UTC"), 170 ] 171 tt = DatetimeIndex(ts) 172 ut = tt.tz_convert("US/Eastern") 173 expected = Index([9, 9, 9]) 174 tm.assert_index_equal(ut.hour, expected) 175 176 @pytest.mark.parametrize("freq, n", [("H", 1), ("T", 60), ("S", 3600)]) 177 def test_dti_tz_convert_trans_pos_plus_1__bug(self, freq, n): 178 # Regression test for tslib.tz_convert(vals, tz1, tz2). 179 # See https://github.com/pandas-dev/pandas/issues/4496 for details. 180 idx = date_range(datetime(2011, 3, 26, 23), datetime(2011, 3, 27, 1), freq=freq) 181 idx = idx.tz_localize("UTC") 182 idx = idx.tz_convert("Europe/Moscow") 183 184 expected = np.repeat(np.array([3, 4, 5]), np.array([n, n, 1])) 185 tm.assert_index_equal(idx.hour, Index(expected)) 186 187 def test_dti_tz_convert_dst(self): 188 for freq, n in [("H", 1), ("T", 60), ("S", 3600)]: 189 # Start DST 190 idx = date_range( 191 "2014-03-08 23:00", "2014-03-09 09:00", freq=freq, tz="UTC" 192 ) 193 idx = idx.tz_convert("US/Eastern") 194 expected = np.repeat( 195 np.array([18, 19, 20, 21, 22, 23, 0, 1, 3, 4, 5]), 196 np.array([n, n, n, n, n, n, n, n, n, n, 1]), 197 ) 198 tm.assert_index_equal(idx.hour, Index(expected)) 199 200 idx = date_range( 201 "2014-03-08 18:00", "2014-03-09 05:00", freq=freq, tz="US/Eastern" 202 ) 203 idx = idx.tz_convert("UTC") 204 expected = np.repeat( 205 np.array([23, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]), 206 np.array([n, n, n, n, n, n, n, n, n, n, 1]), 207 ) 208 tm.assert_index_equal(idx.hour, Index(expected)) 209 210 # End DST 211 idx = date_range( 212 "2014-11-01 23:00", "2014-11-02 09:00", freq=freq, tz="UTC" 213 ) 214 idx = idx.tz_convert("US/Eastern") 215 expected = np.repeat( 216 np.array([19, 20, 21, 22, 23, 0, 1, 1, 2, 3, 4]), 217 np.array([n, n, n, n, n, n, n, n, n, n, 1]), 218 ) 219 tm.assert_index_equal(idx.hour, Index(expected)) 220 221 idx = date_range( 222 "2014-11-01 18:00", "2014-11-02 05:00", freq=freq, tz="US/Eastern" 223 ) 224 idx = idx.tz_convert("UTC") 225 expected = np.repeat( 226 np.array([22, 23, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]), 227 np.array([n, n, n, n, n, n, n, n, n, n, n, n, 1]), 228 ) 229 tm.assert_index_equal(idx.hour, Index(expected)) 230 231 # daily 232 # Start DST 233 idx = date_range("2014-03-08 00:00", "2014-03-09 00:00", freq="D", tz="UTC") 234 idx = idx.tz_convert("US/Eastern") 235 tm.assert_index_equal(idx.hour, Index([19, 19])) 236 237 idx = date_range( 238 "2014-03-08 00:00", "2014-03-09 00:00", freq="D", tz="US/Eastern" 239 ) 240 idx = idx.tz_convert("UTC") 241 tm.assert_index_equal(idx.hour, Index([5, 5])) 242 243 # End DST 244 idx = date_range("2014-11-01 00:00", "2014-11-02 00:00", freq="D", tz="UTC") 245 idx = idx.tz_convert("US/Eastern") 246 tm.assert_index_equal(idx.hour, Index([20, 20])) 247 248 idx = date_range( 249 "2014-11-01 00:00", "2014-11-02 000:00", freq="D", tz="US/Eastern" 250 ) 251 idx = idx.tz_convert("UTC") 252 tm.assert_index_equal(idx.hour, Index([4, 4])) 253 254 def test_tz_convert_roundtrip(self, tz_aware_fixture): 255 tz = tz_aware_fixture 256 idx1 = date_range(start="2014-01-01", end="2014-12-31", freq="M", tz="UTC") 257 exp1 = date_range(start="2014-01-01", end="2014-12-31", freq="M") 258 259 idx2 = date_range(start="2014-01-01", end="2014-12-31", freq="D", tz="UTC") 260 exp2 = date_range(start="2014-01-01", end="2014-12-31", freq="D") 261 262 idx3 = date_range(start="2014-01-01", end="2014-03-01", freq="H", tz="UTC") 263 exp3 = date_range(start="2014-01-01", end="2014-03-01", freq="H") 264 265 idx4 = date_range(start="2014-08-01", end="2014-10-31", freq="T", tz="UTC") 266 exp4 = date_range(start="2014-08-01", end="2014-10-31", freq="T") 267 268 for idx, expected in [(idx1, exp1), (idx2, exp2), (idx3, exp3), (idx4, exp4)]: 269 converted = idx.tz_convert(tz) 270 reset = converted.tz_convert(None) 271 tm.assert_index_equal(reset, expected) 272 assert reset.tzinfo is None 273 expected = converted.tz_convert("UTC").tz_localize(None) 274 expected = expected._with_freq("infer") 275 tm.assert_index_equal(reset, expected) 276 277 def test_dti_tz_convert_tzlocal(self): 278 # GH#13583 279 # tz_convert doesn't affect to internal 280 dti = date_range(start="2001-01-01", end="2001-03-01", tz="UTC") 281 dti2 = dti.tz_convert(dateutil.tz.tzlocal()) 282 tm.assert_numpy_array_equal(dti2.asi8, dti.asi8) 283 284 dti = date_range(start="2001-01-01", end="2001-03-01", tz=dateutil.tz.tzlocal()) 285 dti2 = dti.tz_convert(None) 286 tm.assert_numpy_array_equal(dti2.asi8, dti.asi8) 287 288 @pytest.mark.parametrize( 289 "tz", 290 [ 291 "US/Eastern", 292 "dateutil/US/Eastern", 293 pytz.timezone("US/Eastern"), 294 gettz("US/Eastern"), 295 ], 296 ) 297 def test_dti_tz_convert_utc_to_local_no_modify(self, tz): 298 rng = date_range("3/11/2012", "3/12/2012", freq="H", tz="utc") 299 rng_eastern = rng.tz_convert(tz) 300 301 # Values are unmodified 302 tm.assert_numpy_array_equal(rng.asi8, rng_eastern.asi8) 303 304 assert timezones.tz_compare(rng_eastern.tz, timezones.maybe_get_tz(tz)) 305 306 @pytest.mark.parametrize("tzstr", ["US/Eastern", "dateutil/US/Eastern"]) 307 def test_tz_convert_unsorted(self, tzstr): 308 dr = date_range("2012-03-09", freq="H", periods=100, tz="utc") 309 dr = dr.tz_convert(tzstr) 310 311 result = dr[::-1].hour 312 exp = dr.hour[::-1] 313 tm.assert_almost_equal(result, exp) 314 315 # ------------------------------------------------------------- 316 # DatetimeIndex.tz_localize 317 318 def test_dti_tz_localize_nonexistent_raise_coerce(self): 319 # GH#13057 320 times = ["2015-03-08 01:00", "2015-03-08 02:00", "2015-03-08 03:00"] 321 index = DatetimeIndex(times) 322 tz = "US/Eastern" 323 with pytest.raises(pytz.NonExistentTimeError, match="|".join(times)): 324 index.tz_localize(tz=tz) 325 326 with pytest.raises(pytz.NonExistentTimeError, match="|".join(times)): 327 index.tz_localize(tz=tz, nonexistent="raise") 328 329 result = index.tz_localize(tz=tz, nonexistent="NaT") 330 test_times = ["2015-03-08 01:00-05:00", "NaT", "2015-03-08 03:00-04:00"] 331 dti = to_datetime(test_times, utc=True) 332 expected = dti.tz_convert("US/Eastern") 333 tm.assert_index_equal(result, expected) 334 335 @pytest.mark.parametrize("tz", [pytz.timezone("US/Eastern"), gettz("US/Eastern")]) 336 def test_dti_tz_localize_ambiguous_infer(self, tz): 337 # November 6, 2011, fall back, repeat 2 AM hour 338 # With no repeated hours, we cannot infer the transition 339 dr = date_range(datetime(2011, 11, 6, 0), periods=5, freq=pd.offsets.Hour()) 340 with pytest.raises(pytz.AmbiguousTimeError, match="Cannot infer dst time"): 341 dr.tz_localize(tz) 342 343 # With repeated hours, we can infer the transition 344 dr = date_range( 345 datetime(2011, 11, 6, 0), periods=5, freq=pd.offsets.Hour(), tz=tz 346 ) 347 times = [ 348 "11/06/2011 00:00", 349 "11/06/2011 01:00", 350 "11/06/2011 01:00", 351 "11/06/2011 02:00", 352 "11/06/2011 03:00", 353 ] 354 di = DatetimeIndex(times) 355 localized = di.tz_localize(tz, ambiguous="infer") 356 expected = dr._with_freq(None) 357 tm.assert_index_equal(expected, localized) 358 tm.assert_index_equal(expected, DatetimeIndex(times, tz=tz, ambiguous="infer")) 359 360 # When there is no dst transition, nothing special happens 361 dr = date_range(datetime(2011, 6, 1, 0), periods=10, freq=pd.offsets.Hour()) 362 localized = dr.tz_localize(tz) 363 localized_infer = dr.tz_localize(tz, ambiguous="infer") 364 tm.assert_index_equal(localized, localized_infer) 365 366 @pytest.mark.parametrize("tz", [pytz.timezone("US/Eastern"), gettz("US/Eastern")]) 367 def test_dti_tz_localize_ambiguous_times(self, tz): 368 # March 13, 2011, spring forward, skip from 2 AM to 3 AM 369 dr = date_range(datetime(2011, 3, 13, 1, 30), periods=3, freq=pd.offsets.Hour()) 370 with pytest.raises(pytz.NonExistentTimeError, match="2011-03-13 02:30:00"): 371 dr.tz_localize(tz) 372 373 # after dst transition, it works 374 dr = date_range( 375 datetime(2011, 3, 13, 3, 30), periods=3, freq=pd.offsets.Hour(), tz=tz 376 ) 377 378 # November 6, 2011, fall back, repeat 2 AM hour 379 dr = date_range(datetime(2011, 11, 6, 1, 30), periods=3, freq=pd.offsets.Hour()) 380 with pytest.raises(pytz.AmbiguousTimeError, match="Cannot infer dst time"): 381 dr.tz_localize(tz) 382 383 # UTC is OK 384 dr = date_range( 385 datetime(2011, 3, 13), periods=48, freq=pd.offsets.Minute(30), tz=pytz.utc 386 ) 387 388 @pytest.mark.parametrize("tzstr", ["US/Eastern", "dateutil/US/Eastern"]) 389 def test_dti_tz_localize_pass_dates_to_utc(self, tzstr): 390 strdates = ["1/1/2012", "3/1/2012", "4/1/2012"] 391 392 idx = DatetimeIndex(strdates) 393 conv = idx.tz_localize(tzstr) 394 395 fromdates = DatetimeIndex(strdates, tz=tzstr) 396 397 assert conv.tz == fromdates.tz 398 tm.assert_numpy_array_equal(conv.values, fromdates.values) 399 400 @pytest.mark.parametrize("prefix", ["", "dateutil/"]) 401 def test_dti_tz_localize(self, prefix): 402 tzstr = prefix + "US/Eastern" 403 dti = date_range(start="1/1/2005", end="1/1/2005 0:00:30.256", freq="L") 404 dti2 = dti.tz_localize(tzstr) 405 406 dti_utc = date_range( 407 start="1/1/2005 05:00", end="1/1/2005 5:00:30.256", freq="L", tz="utc" 408 ) 409 410 tm.assert_numpy_array_equal(dti2.values, dti_utc.values) 411 412 dti3 = dti2.tz_convert(prefix + "US/Pacific") 413 tm.assert_numpy_array_equal(dti3.values, dti_utc.values) 414 415 dti = date_range(start="11/6/2011 1:59", end="11/6/2011 2:00", freq="L") 416 with pytest.raises(pytz.AmbiguousTimeError, match="Cannot infer dst time"): 417 dti.tz_localize(tzstr) 418 419 dti = date_range(start="3/13/2011 1:59", end="3/13/2011 2:00", freq="L") 420 with pytest.raises(pytz.NonExistentTimeError, match="2011-03-13 02:00:00"): 421 dti.tz_localize(tzstr) 422 423 @pytest.mark.parametrize( 424 "tz", 425 [ 426 "US/Eastern", 427 "dateutil/US/Eastern", 428 pytz.timezone("US/Eastern"), 429 gettz("US/Eastern"), 430 ], 431 ) 432 def test_dti_tz_localize_utc_conversion(self, tz): 433 # Localizing to time zone should: 434 # 1) check for DST ambiguities 435 # 2) convert to UTC 436 437 rng = date_range("3/10/2012", "3/11/2012", freq="30T") 438 439 converted = rng.tz_localize(tz) 440 expected_naive = rng + pd.offsets.Hour(5) 441 tm.assert_numpy_array_equal(converted.asi8, expected_naive.asi8) 442 443 # DST ambiguity, this should fail 444 rng = date_range("3/11/2012", "3/12/2012", freq="30T") 445 # Is this really how it should fail?? 446 with pytest.raises(pytz.NonExistentTimeError, match="2012-03-11 02:00:00"): 447 rng.tz_localize(tz) 448 449 def test_dti_tz_localize_roundtrip(self, tz_aware_fixture): 450 # note: this tz tests that a tz-naive index can be localized 451 # and de-localized successfully, when there are no DST transitions 452 # in the range. 453 idx = date_range(start="2014-06-01", end="2014-08-30", freq="15T") 454 tz = tz_aware_fixture 455 localized = idx.tz_localize(tz) 456 # cant localize a tz-aware object 457 with pytest.raises( 458 TypeError, match="Already tz-aware, use tz_convert to convert" 459 ): 460 localized.tz_localize(tz) 461 reset = localized.tz_localize(None) 462 assert reset.tzinfo is None 463 expected = idx._with_freq(None) 464 tm.assert_index_equal(reset, expected) 465 466 def test_dti_tz_localize_naive(self): 467 rng = date_range("1/1/2011", periods=100, freq="H") 468 469 conv = rng.tz_localize("US/Pacific") 470 exp = date_range("1/1/2011", periods=100, freq="H", tz="US/Pacific") 471 472 tm.assert_index_equal(conv, exp._with_freq(None)) 473 474 def test_dti_tz_localize_tzlocal(self): 475 # GH#13583 476 offset = dateutil.tz.tzlocal().utcoffset(datetime(2011, 1, 1)) 477 offset = int(offset.total_seconds() * 1000000000) 478 479 dti = date_range(start="2001-01-01", end="2001-03-01") 480 dti2 = dti.tz_localize(dateutil.tz.tzlocal()) 481 tm.assert_numpy_array_equal(dti2.asi8 + offset, dti.asi8) 482 483 dti = date_range(start="2001-01-01", end="2001-03-01", tz=dateutil.tz.tzlocal()) 484 dti2 = dti.tz_localize(None) 485 tm.assert_numpy_array_equal(dti2.asi8 - offset, dti.asi8) 486 487 @pytest.mark.parametrize("tz", [pytz.timezone("US/Eastern"), gettz("US/Eastern")]) 488 def test_dti_tz_localize_ambiguous_nat(self, tz): 489 times = [ 490 "11/06/2011 00:00", 491 "11/06/2011 01:00", 492 "11/06/2011 01:00", 493 "11/06/2011 02:00", 494 "11/06/2011 03:00", 495 ] 496 di = DatetimeIndex(times) 497 localized = di.tz_localize(tz, ambiguous="NaT") 498 499 times = [ 500 "11/06/2011 00:00", 501 np.NaN, 502 np.NaN, 503 "11/06/2011 02:00", 504 "11/06/2011 03:00", 505 ] 506 di_test = DatetimeIndex(times, tz="US/Eastern") 507 508 # left dtype is datetime64[ns, US/Eastern] 509 # right is datetime64[ns, tzfile('/usr/share/zoneinfo/US/Eastern')] 510 tm.assert_numpy_array_equal(di_test.values, localized.values) 511 512 @pytest.mark.parametrize("tz", [pytz.timezone("US/Eastern"), gettz("US/Eastern")]) 513 def test_dti_tz_localize_ambiguous_flags(self, tz): 514 # November 6, 2011, fall back, repeat 2 AM hour 515 516 # Pass in flags to determine right dst transition 517 dr = date_range( 518 datetime(2011, 11, 6, 0), periods=5, freq=pd.offsets.Hour(), tz=tz 519 ) 520 times = [ 521 "11/06/2011 00:00", 522 "11/06/2011 01:00", 523 "11/06/2011 01:00", 524 "11/06/2011 02:00", 525 "11/06/2011 03:00", 526 ] 527 528 # Test tz_localize 529 di = DatetimeIndex(times) 530 is_dst = [1, 1, 0, 0, 0] 531 localized = di.tz_localize(tz, ambiguous=is_dst) 532 expected = dr._with_freq(None) 533 tm.assert_index_equal(expected, localized) 534 tm.assert_index_equal(expected, DatetimeIndex(times, tz=tz, ambiguous=is_dst)) 535 536 localized = di.tz_localize(tz, ambiguous=np.array(is_dst)) 537 tm.assert_index_equal(dr, localized) 538 539 localized = di.tz_localize(tz, ambiguous=np.array(is_dst).astype("bool")) 540 tm.assert_index_equal(dr, localized) 541 542 # Test constructor 543 localized = DatetimeIndex(times, tz=tz, ambiguous=is_dst) 544 tm.assert_index_equal(dr, localized) 545 546 # Test duplicate times where inferring the dst fails 547 times += times 548 di = DatetimeIndex(times) 549 550 # When the sizes are incompatible, make sure error is raised 551 msg = "Length of ambiguous bool-array must be the same size as vals" 552 with pytest.raises(Exception, match=msg): 553 di.tz_localize(tz, ambiguous=is_dst) 554 555 # When sizes are compatible and there are repeats ('infer' won't work) 556 is_dst = np.hstack((is_dst, is_dst)) 557 localized = di.tz_localize(tz, ambiguous=is_dst) 558 dr = dr.append(dr) 559 tm.assert_index_equal(dr, localized) 560 561 # When there is no dst transition, nothing special happens 562 dr = date_range(datetime(2011, 6, 1, 0), periods=10, freq=pd.offsets.Hour()) 563 is_dst = np.array([1] * 10) 564 localized = dr.tz_localize(tz) 565 localized_is_dst = dr.tz_localize(tz, ambiguous=is_dst) 566 tm.assert_index_equal(localized, localized_is_dst) 567 568 # TODO: belongs outside tz_localize tests? 569 @pytest.mark.parametrize("tz", ["Europe/London", "dateutil/Europe/London"]) 570 def test_dti_construction_ambiguous_endpoint(self, tz): 571 # construction with an ambiguous end-point 572 # GH#11626 573 574 with pytest.raises(pytz.AmbiguousTimeError, match="Cannot infer dst time"): 575 date_range( 576 "2013-10-26 23:00", "2013-10-27 01:00", tz="Europe/London", freq="H" 577 ) 578 579 times = date_range( 580 "2013-10-26 23:00", "2013-10-27 01:00", freq="H", tz=tz, ambiguous="infer" 581 ) 582 assert times[0] == Timestamp("2013-10-26 23:00", tz=tz, freq="H") 583 assert times[-1] == Timestamp("2013-10-27 01:00:00+0000", tz=tz, freq="H") 584 585 @pytest.mark.parametrize( 586 "tz, option, expected", 587 [ 588 ["US/Pacific", "shift_forward", "2019-03-10 03:00"], 589 ["dateutil/US/Pacific", "shift_forward", "2019-03-10 03:00"], 590 ["US/Pacific", "shift_backward", "2019-03-10 01:00"], 591 ["dateutil/US/Pacific", "shift_backward", "2019-03-10 01:00"], 592 ["US/Pacific", timedelta(hours=1), "2019-03-10 03:00"], 593 ], 594 ) 595 def test_dti_construction_nonexistent_endpoint(self, tz, option, expected): 596 # construction with an nonexistent end-point 597 598 with pytest.raises(pytz.NonExistentTimeError, match="2019-03-10 02:00:00"): 599 date_range( 600 "2019-03-10 00:00", "2019-03-10 02:00", tz="US/Pacific", freq="H" 601 ) 602 603 times = date_range( 604 "2019-03-10 00:00", "2019-03-10 02:00", freq="H", tz=tz, nonexistent=option 605 ) 606 assert times[-1] == Timestamp(expected, tz=tz, freq="H") 607 608 def test_dti_tz_localize_bdate_range(self): 609 dr = bdate_range("1/1/2009", "1/1/2010") 610 dr_utc = bdate_range("1/1/2009", "1/1/2010", tz=pytz.utc) 611 localized = dr.tz_localize(pytz.utc) 612 tm.assert_index_equal(dr_utc, localized) 613 614 @pytest.mark.parametrize("tz", ["Europe/Warsaw", "dateutil/Europe/Warsaw"]) 615 @pytest.mark.parametrize( 616 "method, exp", [["NaT", pd.NaT], ["raise", None], ["foo", "invalid"]] 617 ) 618 def test_dti_tz_localize_nonexistent(self, tz, method, exp): 619 # GH 8917 620 n = 60 621 dti = date_range(start="2015-03-29 02:00:00", periods=n, freq="min") 622 if method == "raise": 623 with pytest.raises(pytz.NonExistentTimeError, match="2015-03-29 02:00:00"): 624 dti.tz_localize(tz, nonexistent=method) 625 elif exp == "invalid": 626 msg = ( 627 "The nonexistent argument must be one of " 628 "'raise', 'NaT', 'shift_forward', 'shift_backward' " 629 "or a timedelta object" 630 ) 631 with pytest.raises(ValueError, match=msg): 632 dti.tz_localize(tz, nonexistent=method) 633 else: 634 result = dti.tz_localize(tz, nonexistent=method) 635 expected = DatetimeIndex([exp] * n, tz=tz) 636 tm.assert_index_equal(result, expected) 637 638 @pytest.mark.parametrize( 639 "start_ts, tz, end_ts, shift", 640 [ 641 ["2015-03-29 02:20:00", "Europe/Warsaw", "2015-03-29 03:00:00", "forward"], 642 [ 643 "2015-03-29 02:20:00", 644 "Europe/Warsaw", 645 "2015-03-29 01:59:59.999999999", 646 "backward", 647 ], 648 [ 649 "2015-03-29 02:20:00", 650 "Europe/Warsaw", 651 "2015-03-29 03:20:00", 652 timedelta(hours=1), 653 ], 654 [ 655 "2015-03-29 02:20:00", 656 "Europe/Warsaw", 657 "2015-03-29 01:20:00", 658 timedelta(hours=-1), 659 ], 660 ["2018-03-11 02:33:00", "US/Pacific", "2018-03-11 03:00:00", "forward"], 661 [ 662 "2018-03-11 02:33:00", 663 "US/Pacific", 664 "2018-03-11 01:59:59.999999999", 665 "backward", 666 ], 667 [ 668 "2018-03-11 02:33:00", 669 "US/Pacific", 670 "2018-03-11 03:33:00", 671 timedelta(hours=1), 672 ], 673 [ 674 "2018-03-11 02:33:00", 675 "US/Pacific", 676 "2018-03-11 01:33:00", 677 timedelta(hours=-1), 678 ], 679 ], 680 ) 681 @pytest.mark.parametrize("tz_type", ["", "dateutil/"]) 682 def test_dti_tz_localize_nonexistent_shift( 683 self, start_ts, tz, end_ts, shift, tz_type 684 ): 685 # GH 8917 686 tz = tz_type + tz 687 if isinstance(shift, str): 688 shift = "shift_" + shift 689 dti = DatetimeIndex([Timestamp(start_ts)]) 690 result = dti.tz_localize(tz, nonexistent=shift) 691 expected = DatetimeIndex([Timestamp(end_ts)]).tz_localize(tz) 692 tm.assert_index_equal(result, expected) 693 694 @pytest.mark.parametrize("offset", [-1, 1]) 695 @pytest.mark.parametrize("tz_type", ["", "dateutil/"]) 696 def test_dti_tz_localize_nonexistent_shift_invalid(self, offset, tz_type): 697 # GH 8917 698 tz = tz_type + "Europe/Warsaw" 699 dti = DatetimeIndex([Timestamp("2015-03-29 02:20:00")]) 700 msg = "The provided timedelta will relocalize on a nonexistent time" 701 with pytest.raises(ValueError, match=msg): 702 dti.tz_localize(tz, nonexistent=timedelta(seconds=offset)) 703 704 # ------------------------------------------------------------- 705 # DatetimeIndex.normalize 706 707 def test_normalize_tz(self): 708 rng = date_range("1/1/2000 9:30", periods=10, freq="D", tz="US/Eastern") 709 710 result = rng.normalize() # does not preserve freq 711 expected = date_range("1/1/2000", periods=10, freq="D", tz="US/Eastern") 712 tm.assert_index_equal(result, expected._with_freq(None)) 713 714 assert result.is_normalized 715 assert not rng.is_normalized 716 717 rng = date_range("1/1/2000 9:30", periods=10, freq="D", tz="UTC") 718 719 result = rng.normalize() 720 expected = date_range("1/1/2000", periods=10, freq="D", tz="UTC") 721 tm.assert_index_equal(result, expected) 722 723 assert result.is_normalized 724 assert not rng.is_normalized 725 726 rng = date_range("1/1/2000 9:30", periods=10, freq="D", tz=tzlocal()) 727 result = rng.normalize() # does not preserve freq 728 expected = date_range("1/1/2000", periods=10, freq="D", tz=tzlocal()) 729 tm.assert_index_equal(result, expected._with_freq(None)) 730 731 assert result.is_normalized 732 assert not rng.is_normalized 733 734 @td.skip_if_windows 735 @pytest.mark.parametrize( 736 "timezone", 737 [ 738 "US/Pacific", 739 "US/Eastern", 740 "UTC", 741 "Asia/Kolkata", 742 "Asia/Shanghai", 743 "Australia/Canberra", 744 ], 745 ) 746 def test_normalize_tz_local(self, timezone): 747 # GH#13459 748 with tm.set_timezone(timezone): 749 rng = date_range("1/1/2000 9:30", periods=10, freq="D", tz=tzlocal()) 750 751 result = rng.normalize() 752 expected = date_range("1/1/2000", periods=10, freq="D", tz=tzlocal()) 753 expected = expected._with_freq(None) 754 tm.assert_index_equal(result, expected) 755 756 assert result.is_normalized 757 assert not rng.is_normalized 758 759 # ------------------------------------------------------------ 760 # DatetimeIndex.__new__ 761 762 @pytest.mark.parametrize("prefix", ["", "dateutil/"]) 763 def test_dti_constructor_static_tzinfo(self, prefix): 764 # it works! 765 index = DatetimeIndex([datetime(2012, 1, 1)], tz=prefix + "EST") 766 index.hour 767 index[0] 768 769 def test_dti_constructor_with_fixed_tz(self): 770 off = FixedOffset(420, "+07:00") 771 start = datetime(2012, 3, 11, 5, 0, 0, tzinfo=off) 772 end = datetime(2012, 6, 11, 5, 0, 0, tzinfo=off) 773 rng = date_range(start=start, end=end) 774 assert off == rng.tz 775 776 rng2 = date_range(start, periods=len(rng), tz=off) 777 tm.assert_index_equal(rng, rng2) 778 779 rng3 = date_range("3/11/2012 05:00:00+07:00", "6/11/2012 05:00:00+07:00") 780 assert (rng.values == rng3.values).all() 781 782 @pytest.mark.parametrize("tzstr", ["US/Eastern", "dateutil/US/Eastern"]) 783 def test_dti_convert_datetime_list(self, tzstr): 784 dr = date_range("2012-06-02", periods=10, tz=tzstr, name="foo") 785 dr2 = DatetimeIndex(list(dr), name="foo", freq="D") 786 tm.assert_index_equal(dr, dr2) 787 788 def test_dti_construction_univalent(self): 789 rng = date_range("03/12/2012 00:00", periods=10, freq="W-FRI", tz="US/Eastern") 790 rng2 = DatetimeIndex(data=rng, tz="US/Eastern") 791 tm.assert_index_equal(rng, rng2) 792 793 @pytest.mark.parametrize("tz", [pytz.timezone("US/Eastern"), gettz("US/Eastern")]) 794 def test_dti_from_tzaware_datetime(self, tz): 795 d = [datetime(2012, 8, 19, tzinfo=tz)] 796 797 index = DatetimeIndex(d) 798 assert timezones.tz_compare(index.tz, tz) 799 800 @pytest.mark.parametrize("tzstr", ["US/Eastern", "dateutil/US/Eastern"]) 801 def test_dti_tz_constructors(self, tzstr): 802 """Test different DatetimeIndex constructions with timezone 803 Follow-up of GH#4229 804 """ 805 arr = ["11/10/2005 08:00:00", "11/10/2005 09:00:00"] 806 807 idx1 = to_datetime(arr).tz_localize(tzstr) 808 idx2 = date_range(start="2005-11-10 08:00:00", freq="H", periods=2, tz=tzstr) 809 idx2 = idx2._with_freq(None) # the others all have freq=None 810 idx3 = DatetimeIndex(arr, tz=tzstr) 811 idx4 = DatetimeIndex(np.array(arr), tz=tzstr) 812 813 for other in [idx2, idx3, idx4]: 814 tm.assert_index_equal(idx1, other) 815 816 # ------------------------------------------------------------- 817 # Unsorted 818 819 @pytest.mark.parametrize( 820 "dtype", 821 [None, "datetime64[ns, CET]", "datetime64[ns, EST]", "datetime64[ns, UTC]"], 822 ) 823 def test_date_accessor(self, dtype): 824 # Regression test for GH#21230 825 expected = np.array([date(2018, 6, 4), pd.NaT]) 826 827 index = DatetimeIndex(["2018-06-04 10:00:00", pd.NaT], dtype=dtype) 828 result = index.date 829 830 tm.assert_numpy_array_equal(result, expected) 831 832 @pytest.mark.parametrize( 833 "dtype", 834 [None, "datetime64[ns, CET]", "datetime64[ns, EST]", "datetime64[ns, UTC]"], 835 ) 836 def test_time_accessor(self, dtype): 837 # Regression test for GH#21267 838 expected = np.array([time(10, 20, 30), pd.NaT]) 839 840 index = DatetimeIndex(["2018-06-04 10:20:30", pd.NaT], dtype=dtype) 841 result = index.time 842 843 tm.assert_numpy_array_equal(result, expected) 844 845 def test_timetz_accessor(self, tz_naive_fixture): 846 # GH21358 847 tz = timezones.maybe_get_tz(tz_naive_fixture) 848 849 expected = np.array([time(10, 20, 30, tzinfo=tz), pd.NaT]) 850 851 index = DatetimeIndex(["2018-06-04 10:20:30", pd.NaT], tz=tz) 852 result = index.timetz 853 854 tm.assert_numpy_array_equal(result, expected) 855 856 def test_dti_drop_dont_lose_tz(self): 857 # GH#2621 858 ind = date_range("2012-12-01", periods=10, tz="utc") 859 ind = ind.drop(ind[-1]) 860 861 assert ind.tz is not None 862 863 def test_dti_tz_conversion_freq(self, tz_naive_fixture): 864 # GH25241 865 t3 = DatetimeIndex(["2019-01-01 10:00"], freq="H") 866 assert t3.tz_localize(tz=tz_naive_fixture).freq == t3.freq 867 t4 = DatetimeIndex(["2019-01-02 12:00"], tz="UTC", freq="T") 868 assert t4.tz_convert(tz="UTC").freq == t4.freq 869 870 def test_drop_dst_boundary(self): 871 # see gh-18031 872 tz = "Europe/Brussels" 873 freq = "15min" 874 875 start = Timestamp("201710290100", tz=tz) 876 end = Timestamp("201710290300", tz=tz) 877 index = date_range(start=start, end=end, freq=freq) 878 879 expected = DatetimeIndex( 880 [ 881 "201710290115", 882 "201710290130", 883 "201710290145", 884 "201710290200", 885 "201710290215", 886 "201710290230", 887 "201710290245", 888 "201710290200", 889 "201710290215", 890 "201710290230", 891 "201710290245", 892 "201710290300", 893 ], 894 tz=tz, 895 freq=freq, 896 ambiguous=[ 897 True, 898 True, 899 True, 900 True, 901 True, 902 True, 903 True, 904 False, 905 False, 906 False, 907 False, 908 False, 909 ], 910 ) 911 result = index.drop(index[0]) 912 tm.assert_index_equal(result, expected) 913 914 def test_date_range_localize(self): 915 rng = date_range("3/11/2012 03:00", periods=15, freq="H", tz="US/Eastern") 916 rng2 = DatetimeIndex(["3/11/2012 03:00", "3/11/2012 04:00"], tz="US/Eastern") 917 rng3 = date_range("3/11/2012 03:00", periods=15, freq="H") 918 rng3 = rng3.tz_localize("US/Eastern") 919 920 tm.assert_index_equal(rng._with_freq(None), rng3) 921 922 # DST transition time 923 val = rng[0] 924 exp = Timestamp("3/11/2012 03:00", tz="US/Eastern") 925 926 assert val.hour == 3 927 assert exp.hour == 3 928 assert val == exp # same UTC value 929 tm.assert_index_equal(rng[:2], rng2) 930 931 # Right before the DST transition 932 rng = date_range("3/11/2012 00:00", periods=2, freq="H", tz="US/Eastern") 933 rng2 = DatetimeIndex( 934 ["3/11/2012 00:00", "3/11/2012 01:00"], tz="US/Eastern", freq="H" 935 ) 936 tm.assert_index_equal(rng, rng2) 937 exp = Timestamp("3/11/2012 00:00", tz="US/Eastern") 938 assert exp.hour == 0 939 assert rng[0] == exp 940 exp = Timestamp("3/11/2012 01:00", tz="US/Eastern") 941 assert exp.hour == 1 942 assert rng[1] == exp 943 944 rng = date_range("3/11/2012 00:00", periods=10, freq="H", tz="US/Eastern") 945 assert rng[2].hour == 3 946 947 def test_timestamp_equality_different_timezones(self): 948 utc_range = date_range("1/1/2000", periods=20, tz="UTC") 949 eastern_range = utc_range.tz_convert("US/Eastern") 950 berlin_range = utc_range.tz_convert("Europe/Berlin") 951 952 for a, b, c in zip(utc_range, eastern_range, berlin_range): 953 assert a == b 954 assert b == c 955 assert a == c 956 957 assert (utc_range == eastern_range).all() 958 assert (utc_range == berlin_range).all() 959 assert (berlin_range == eastern_range).all() 960 961 def test_dti_intersection(self): 962 rng = date_range("1/1/2011", periods=100, freq="H", tz="utc") 963 964 left = rng[10:90][::-1] 965 right = rng[20:80][::-1] 966 967 assert left.tz == rng.tz 968 result = left.intersection(right) 969 assert result.tz == left.tz 970 971 def test_dti_equals_with_tz(self): 972 left = date_range("1/1/2011", periods=100, freq="H", tz="utc") 973 right = date_range("1/1/2011", periods=100, freq="H", tz="US/Eastern") 974 975 assert not left.equals(right) 976 977 @pytest.mark.parametrize("tzstr", ["US/Eastern", "dateutil/US/Eastern"]) 978 def test_dti_tz_nat(self, tzstr): 979 idx = DatetimeIndex([Timestamp("2013-1-1", tz=tzstr), pd.NaT]) 980 981 assert isna(idx[1]) 982 assert idx[0].tzinfo is not None 983 984 @pytest.mark.parametrize("tzstr", ["US/Eastern", "dateutil/US/Eastern"]) 985 def test_dti_astype_asobject_tzinfos(self, tzstr): 986 # GH#1345 987 988 # dates around a dst transition 989 rng = date_range("2/13/2010", "5/6/2010", tz=tzstr) 990 991 objs = rng.astype(object) 992 for i, x in enumerate(objs): 993 exval = rng[i] 994 assert x == exval 995 assert x.tzinfo == exval.tzinfo 996 997 objs = rng.astype(object) 998 for i, x in enumerate(objs): 999 exval = rng[i] 1000 assert x == exval 1001 assert x.tzinfo == exval.tzinfo 1002 1003 @pytest.mark.parametrize("tzstr", ["US/Eastern", "dateutil/US/Eastern"]) 1004 def test_dti_with_timezone_repr(self, tzstr): 1005 rng = date_range("4/13/2010", "5/6/2010") 1006 1007 rng_eastern = rng.tz_localize(tzstr) 1008 1009 rng_repr = repr(rng_eastern) 1010 assert "2010-04-13 00:00:00" in rng_repr 1011 1012 @pytest.mark.parametrize("tzstr", ["US/Eastern", "dateutil/US/Eastern"]) 1013 def test_dti_take_dont_lose_meta(self, tzstr): 1014 rng = date_range("1/1/2000", periods=20, tz=tzstr) 1015 1016 result = rng.take(range(5)) 1017 assert result.tz == rng.tz 1018 assert result.freq == rng.freq 1019 1020 @pytest.mark.parametrize("tzstr", ["US/Eastern", "dateutil/US/Eastern"]) 1021 def test_utc_box_timestamp_and_localize(self, tzstr): 1022 tz = timezones.maybe_get_tz(tzstr) 1023 1024 rng = date_range("3/11/2012", "3/12/2012", freq="H", tz="utc") 1025 rng_eastern = rng.tz_convert(tzstr) 1026 1027 expected = rng[-1].astimezone(tz) 1028 1029 stamp = rng_eastern[-1] 1030 assert stamp == expected 1031 assert stamp.tzinfo == expected.tzinfo 1032 1033 # right tzinfo 1034 rng = date_range("3/13/2012", "3/14/2012", freq="H", tz="utc") 1035 rng_eastern = rng.tz_convert(tzstr) 1036 # test not valid for dateutil timezones. 1037 # assert 'EDT' in repr(rng_eastern[0].tzinfo) 1038 assert "EDT" in repr(rng_eastern[0].tzinfo) or "tzfile" in repr( 1039 rng_eastern[0].tzinfo 1040 ) 1041 1042 def test_dti_to_pydatetime(self): 1043 dt = dateutil.parser.parse("2012-06-13T01:39:00Z") 1044 dt = dt.replace(tzinfo=tzlocal()) 1045 1046 arr = np.array([dt], dtype=object) 1047 1048 result = to_datetime(arr, utc=True) 1049 assert result.tz is pytz.utc 1050 1051 rng = date_range("2012-11-03 03:00", "2012-11-05 03:00", tz=tzlocal()) 1052 arr = rng.to_pydatetime() 1053 result = to_datetime(arr, utc=True) 1054 assert result.tz is pytz.utc 1055 1056 def test_dti_to_pydatetime_fizedtz(self): 1057 dates = np.array( 1058 [ 1059 datetime(2000, 1, 1, tzinfo=fixed_off), 1060 datetime(2000, 1, 2, tzinfo=fixed_off), 1061 datetime(2000, 1, 3, tzinfo=fixed_off), 1062 ] 1063 ) 1064 dti = DatetimeIndex(dates) 1065 1066 result = dti.to_pydatetime() 1067 tm.assert_numpy_array_equal(dates, result) 1068 1069 result = dti._mpl_repr() 1070 tm.assert_numpy_array_equal(dates, result) 1071 1072 @pytest.mark.parametrize("tz", [pytz.timezone("US/Central"), gettz("US/Central")]) 1073 def test_with_tz(self, tz): 1074 # just want it to work 1075 start = datetime(2011, 3, 12, tzinfo=pytz.utc) 1076 dr = bdate_range(start, periods=50, freq=pd.offsets.Hour()) 1077 assert dr.tz is pytz.utc 1078 1079 # DateRange with naive datetimes 1080 dr = bdate_range("1/1/2005", "1/1/2009", tz=pytz.utc) 1081 dr = bdate_range("1/1/2005", "1/1/2009", tz=tz) 1082 1083 # normalized 1084 central = dr.tz_convert(tz) 1085 assert central.tz is tz 1086 naive = central[0].to_pydatetime().replace(tzinfo=None) 1087 comp = conversion.localize_pydatetime(naive, tz).tzinfo 1088 assert central[0].tz is comp 1089 1090 # compare vs a localized tz 1091 naive = dr[0].to_pydatetime().replace(tzinfo=None) 1092 comp = conversion.localize_pydatetime(naive, tz).tzinfo 1093 assert central[0].tz is comp 1094 1095 # datetimes with tzinfo set 1096 dr = bdate_range( 1097 datetime(2005, 1, 1, tzinfo=pytz.utc), datetime(2009, 1, 1, tzinfo=pytz.utc) 1098 ) 1099 msg = "Start and end cannot both be tz-aware with different timezones" 1100 with pytest.raises(Exception, match=msg): 1101 bdate_range(datetime(2005, 1, 1, tzinfo=pytz.utc), "1/1/2009", tz=tz) 1102 1103 @pytest.mark.parametrize("prefix", ["", "dateutil/"]) 1104 def test_field_access_localize(self, prefix): 1105 strdates = ["1/1/2012", "3/1/2012", "4/1/2012"] 1106 rng = DatetimeIndex(strdates, tz=prefix + "US/Eastern") 1107 assert (rng.hour == 0).all() 1108 1109 # a more unusual time zone, #1946 1110 dr = date_range( 1111 "2011-10-02 00:00", freq="h", periods=10, tz=prefix + "America/Atikokan" 1112 ) 1113 1114 expected = Index(np.arange(10, dtype=np.int64)) 1115 tm.assert_index_equal(dr.hour, expected) 1116 1117 @pytest.mark.parametrize("tz", [pytz.timezone("US/Eastern"), gettz("US/Eastern")]) 1118 def test_dti_convert_tz_aware_datetime_datetime(self, tz): 1119 # GH#1581 1120 dates = [datetime(2000, 1, 1), datetime(2000, 1, 2), datetime(2000, 1, 3)] 1121 1122 dates_aware = [conversion.localize_pydatetime(x, tz) for x in dates] 1123 result = DatetimeIndex(dates_aware) 1124 assert timezones.tz_compare(result.tz, tz) 1125 1126 converted = to_datetime(dates_aware, utc=True) 1127 ex_vals = np.array([Timestamp(x).value for x in dates_aware]) 1128 tm.assert_numpy_array_equal(converted.asi8, ex_vals) 1129 assert converted.tz is pytz.utc 1130 1131 def test_dti_union_aware(self): 1132 # non-overlapping 1133 rng = date_range("2012-11-15 00:00:00", periods=6, freq="H", tz="US/Central") 1134 1135 rng2 = date_range("2012-11-15 12:00:00", periods=6, freq="H", tz="US/Eastern") 1136 1137 result = rng.union(rng2) 1138 expected = rng.astype("O").union(rng2.astype("O")) 1139 tm.assert_index_equal(result, expected) 1140 assert result[0].tz.zone == "US/Central" 1141 assert result[-1].tz.zone == "US/Eastern" 1142 1143 def test_dti_union_mixed(self): 1144 # GH 21671 1145 rng = DatetimeIndex([Timestamp("2011-01-01"), pd.NaT]) 1146 rng2 = DatetimeIndex(["2012-01-01", "2012-01-02"], tz="Asia/Tokyo") 1147 result = rng.union(rng2) 1148 expected = Index( 1149 [ 1150 Timestamp("2011-01-01"), 1151 pd.NaT, 1152 Timestamp("2012-01-01", tz="Asia/Tokyo"), 1153 Timestamp("2012-01-02", tz="Asia/Tokyo"), 1154 ], 1155 dtype=object, 1156 ) 1157 tm.assert_index_equal(result, expected) 1158 1159 @pytest.mark.parametrize( 1160 "tz", [None, "UTC", "US/Central", dateutil.tz.tzoffset(None, -28800)] 1161 ) 1162 @pytest.mark.usefixtures("datetime_tz_utc") 1163 def test_iteration_preserves_nanoseconds(self, tz): 1164 # GH 19603 1165 index = DatetimeIndex( 1166 ["2018-02-08 15:00:00.168456358", "2018-02-08 15:00:00.168456359"], tz=tz 1167 ) 1168 for i, ts in enumerate(index): 1169 assert ts == index[i] 1170 1171 1172def test_tz_localize_invalidates_freq(): 1173 # we only preserve freq in unambiguous cases 1174 1175 # if localized to US/Eastern, this crosses a DST transition 1176 dti = date_range("2014-03-08 23:00", "2014-03-09 09:00", freq="H") 1177 assert dti.freq == "H" 1178 1179 result = dti.tz_localize(None) # no-op 1180 assert result.freq == "H" 1181 1182 result = dti.tz_localize("UTC") # unambiguous freq preservation 1183 assert result.freq == "H" 1184 1185 result = dti.tz_localize("US/Eastern", nonexistent="shift_forward") 1186 assert result.freq is None 1187 assert result.inferred_freq is None # i.e. we are not _too_ strict here 1188 1189 # Case where we _can_ keep freq because we're length==1 1190 dti2 = dti[:1] 1191 result = dti2.tz_localize("US/Eastern") 1192 assert result.freq == "H" 1193