test_constructors.py 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. import numpy as np
  2. import pytest
  3. from pandas.core.dtypes.dtypes import DatetimeTZDtype
  4. import pandas as pd
  5. import pandas._testing as tm
  6. from pandas.core.arrays import DatetimeArray
  7. from pandas.core.arrays.datetimes import _sequence_to_dt64ns
  8. class TestDatetimeArrayConstructor:
  9. def test_from_sequence_invalid_type(self):
  10. mi = pd.MultiIndex.from_product([np.arange(5), np.arange(5)])
  11. with pytest.raises(TypeError, match="Cannot create a DatetimeArray"):
  12. DatetimeArray._from_sequence(mi)
  13. def test_only_1dim_accepted(self):
  14. arr = np.array([0, 1, 2, 3], dtype="M8[h]").astype("M8[ns]")
  15. with pytest.raises(ValueError, match="Only 1-dimensional"):
  16. # 3-dim, we allow 2D to sneak in for ops purposes GH#29853
  17. DatetimeArray(arr.reshape(2, 2, 1))
  18. with pytest.raises(ValueError, match="Only 1-dimensional"):
  19. # 0-dim
  20. DatetimeArray(arr[[0]].squeeze())
  21. def test_freq_validation(self):
  22. # GH#24623 check that invalid instances cannot be created with the
  23. # public constructor
  24. arr = np.arange(5, dtype=np.int64) * 3600 * 10**9
  25. msg = (
  26. "Inferred frequency H from passed values does not "
  27. "conform to passed frequency W-SUN"
  28. )
  29. with pytest.raises(ValueError, match=msg):
  30. DatetimeArray(arr, freq="W")
  31. @pytest.mark.parametrize(
  32. "meth",
  33. [
  34. DatetimeArray._from_sequence,
  35. _sequence_to_dt64ns,
  36. pd.to_datetime,
  37. pd.DatetimeIndex,
  38. ],
  39. )
  40. def test_mixing_naive_tzaware_raises(self, meth):
  41. # GH#24569
  42. arr = np.array([pd.Timestamp("2000"), pd.Timestamp("2000", tz="CET")])
  43. msg = (
  44. "Cannot mix tz-aware with tz-naive values|"
  45. "Tz-aware datetime.datetime cannot be converted "
  46. "to datetime64 unless utc=True"
  47. )
  48. for obj in [arr, arr[::-1]]:
  49. # check that we raise regardless of whether naive is found
  50. # before aware or vice-versa
  51. with pytest.raises(ValueError, match=msg):
  52. meth(obj)
  53. def test_from_pandas_array(self):
  54. arr = pd.array(np.arange(5, dtype=np.int64)) * 3600 * 10**9
  55. result = DatetimeArray._from_sequence(arr)._with_freq("infer")
  56. expected = pd.date_range("1970-01-01", periods=5, freq="H")._data
  57. tm.assert_datetime_array_equal(result, expected)
  58. def test_mismatched_timezone_raises(self):
  59. arr = DatetimeArray(
  60. np.array(["2000-01-01T06:00:00"], dtype="M8[ns]"),
  61. dtype=DatetimeTZDtype(tz="US/Central"),
  62. )
  63. dtype = DatetimeTZDtype(tz="US/Eastern")
  64. msg = r"dtype=datetime64\[ns.*\] does not match data dtype datetime64\[ns.*\]"
  65. with pytest.raises(TypeError, match=msg):
  66. DatetimeArray(arr, dtype=dtype)
  67. # also with mismatched tzawareness
  68. with pytest.raises(TypeError, match=msg):
  69. DatetimeArray(arr, dtype=np.dtype("M8[ns]"))
  70. with pytest.raises(TypeError, match=msg):
  71. DatetimeArray(arr.tz_localize(None), dtype=arr.dtype)
  72. def test_non_array_raises(self):
  73. with pytest.raises(ValueError, match="list"):
  74. DatetimeArray([1, 2, 3])
  75. def test_bool_dtype_raises(self):
  76. arr = np.array([1, 2, 3], dtype="bool")
  77. msg = "Unexpected value for 'dtype': 'bool'. Must be"
  78. with pytest.raises(ValueError, match=msg):
  79. DatetimeArray(arr)
  80. msg = r"dtype bool cannot be converted to datetime64\[ns\]"
  81. with pytest.raises(TypeError, match=msg):
  82. DatetimeArray._from_sequence(arr)
  83. with pytest.raises(TypeError, match=msg):
  84. _sequence_to_dt64ns(arr)
  85. with pytest.raises(TypeError, match=msg):
  86. pd.DatetimeIndex(arr)
  87. with pytest.raises(TypeError, match=msg):
  88. pd.to_datetime(arr)
  89. def test_incorrect_dtype_raises(self):
  90. with pytest.raises(ValueError, match="Unexpected value for 'dtype'."):
  91. DatetimeArray(np.array([1, 2, 3], dtype="i8"), dtype="category")
  92. def test_freq_infer_raises(self):
  93. with pytest.raises(ValueError, match="Frequency inference"):
  94. DatetimeArray(np.array([1, 2, 3], dtype="i8"), freq="infer")
  95. def test_copy(self):
  96. data = np.array([1, 2, 3], dtype="M8[ns]")
  97. arr = DatetimeArray(data, copy=False)
  98. assert arr._ndarray is data
  99. arr = DatetimeArray(data, copy=True)
  100. assert arr._ndarray is not data
  101. @pytest.mark.parametrize("unit", ["s", "ms", "us", "ns"])
  102. def test_numpy_datetime_unit(self, unit):
  103. data = np.array([1, 2, 3], dtype=f"M8[{unit}]")
  104. arr = DatetimeArray(data)
  105. assert arr.unit == unit
  106. assert arr[0].unit == unit
  107. class TestSequenceToDT64NS:
  108. def test_tz_dtype_mismatch_raises(self):
  109. arr = DatetimeArray._from_sequence(
  110. ["2000"], dtype=DatetimeTZDtype(tz="US/Central")
  111. )
  112. with pytest.raises(TypeError, match="data is already tz-aware"):
  113. DatetimeArray._from_sequence_not_strict(
  114. arr, dtype=DatetimeTZDtype(tz="UTC")
  115. )
  116. def test_tz_dtype_matches(self):
  117. dtype = DatetimeTZDtype(tz="US/Central")
  118. arr = DatetimeArray._from_sequence(["2000"], dtype=dtype)
  119. result = DatetimeArray._from_sequence_not_strict(arr, dtype=dtype)
  120. tm.assert_equal(arr, result)
  121. @pytest.mark.parametrize("order", ["F", "C"])
  122. def test_2d(self, order):
  123. dti = pd.date_range("2016-01-01", periods=6, tz="US/Pacific")
  124. arr = np.array(dti, dtype=object).reshape(3, 2)
  125. if order == "F":
  126. arr = arr.T
  127. res = _sequence_to_dt64ns(arr)
  128. expected = _sequence_to_dt64ns(arr.ravel())
  129. tm.assert_numpy_array_equal(res[0].ravel(), expected[0])
  130. assert res[1] == expected[1]
  131. assert res[2] == expected[2]
  132. res = DatetimeArray._from_sequence(arr)
  133. expected = DatetimeArray._from_sequence(arr.ravel()).reshape(arr.shape)
  134. tm.assert_datetime_array_equal(res, expected)