test_timedelta.py 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. from datetime import timedelta
  2. import numpy as np
  3. import pytest
  4. import pandas as pd
  5. from pandas import (
  6. Index,
  7. NaT,
  8. Series,
  9. Timedelta,
  10. TimedeltaIndex,
  11. timedelta_range,
  12. )
  13. import pandas._testing as tm
  14. from pandas.core.arrays import TimedeltaArray
  15. from pandas.tests.indexes.datetimelike import DatetimeLike
  16. randn = np.random.randn
  17. class TestTimedeltaIndex(DatetimeLike):
  18. _index_cls = TimedeltaIndex
  19. @pytest.fixture
  20. def simple_index(self) -> TimedeltaIndex:
  21. index = pd.to_timedelta(range(5), unit="d")._with_freq("infer")
  22. assert index.freq == "D"
  23. ret = index + pd.offsets.Hour(1)
  24. assert ret.freq == "D"
  25. return ret
  26. @pytest.fixture
  27. def index(self):
  28. return tm.makeTimedeltaIndex(10)
  29. def test_numeric_compat(self):
  30. # Dummy method to override super's version; this test is now done
  31. # in test_arithmetic.py
  32. pass
  33. def test_shift(self):
  34. pass # this is handled in test_arithmetic.py
  35. def test_misc_coverage(self):
  36. rng = timedelta_range("1 day", periods=5)
  37. result = rng.groupby(rng.days)
  38. assert isinstance(list(result.values())[0][0], Timedelta)
  39. def test_map(self):
  40. # test_map_dictlike generally tests
  41. rng = timedelta_range("1 day", periods=10)
  42. f = lambda x: x.days
  43. result = rng.map(f)
  44. exp = Index([f(x) for x in rng], dtype=np.int64)
  45. tm.assert_index_equal(result, exp)
  46. def test_pass_TimedeltaIndex_to_index(self):
  47. rng = timedelta_range("1 days", "10 days")
  48. idx = Index(rng, dtype=object)
  49. expected = Index(rng.to_pytimedelta(), dtype=object)
  50. tm.assert_numpy_array_equal(idx.values, expected.values)
  51. def test_fields(self):
  52. rng = timedelta_range("1 days, 10:11:12.100123456", periods=2, freq="s")
  53. tm.assert_index_equal(rng.days, Index([1, 1], dtype=np.int64))
  54. tm.assert_index_equal(
  55. rng.seconds,
  56. Index([10 * 3600 + 11 * 60 + 12, 10 * 3600 + 11 * 60 + 13], dtype=np.int32),
  57. )
  58. tm.assert_index_equal(
  59. rng.microseconds,
  60. Index([100 * 1000 + 123, 100 * 1000 + 123], dtype=np.int32),
  61. )
  62. tm.assert_index_equal(rng.nanoseconds, Index([456, 456], dtype=np.int32))
  63. msg = "'TimedeltaIndex' object has no attribute '{}'"
  64. with pytest.raises(AttributeError, match=msg.format("hours")):
  65. rng.hours
  66. with pytest.raises(AttributeError, match=msg.format("minutes")):
  67. rng.minutes
  68. with pytest.raises(AttributeError, match=msg.format("milliseconds")):
  69. rng.milliseconds
  70. # with nat
  71. s = Series(rng)
  72. s[1] = np.nan
  73. tm.assert_series_equal(s.dt.days, Series([1, np.nan], index=[0, 1]))
  74. tm.assert_series_equal(
  75. s.dt.seconds, Series([10 * 3600 + 11 * 60 + 12, np.nan], index=[0, 1])
  76. )
  77. # preserve name (GH15589)
  78. rng.name = "name"
  79. assert rng.days.name == "name"
  80. def test_freq_conversion_always_floating(self):
  81. # pre-2.0 td64 astype converted to float64. now for supported units
  82. # (s, ms, us, ns) this converts to the requested dtype.
  83. # This matches TDA and Series
  84. tdi = timedelta_range("1 Day", periods=30)
  85. res = tdi.astype("m8[s]")
  86. exp_values = np.asarray(tdi).astype("m8[s]")
  87. exp_tda = TimedeltaArray._simple_new(
  88. exp_values, dtype=exp_values.dtype, freq=tdi.freq
  89. )
  90. expected = Index(exp_tda)
  91. assert expected.dtype == "m8[s]"
  92. tm.assert_index_equal(res, expected)
  93. # check this matches Series and TimedeltaArray
  94. res = tdi._data.astype("m8[s]")
  95. tm.assert_equal(res, expected._values)
  96. res = tdi.to_series().astype("m8[s]")
  97. tm.assert_equal(res._values, expected._values._with_freq(None))
  98. def test_freq_conversion(self, index_or_series):
  99. # doc example
  100. scalar = Timedelta(days=31)
  101. td = index_or_series(
  102. [scalar, scalar, scalar + timedelta(minutes=5, seconds=3), NaT],
  103. dtype="m8[ns]",
  104. )
  105. result = td / np.timedelta64(1, "D")
  106. expected = index_or_series(
  107. [31, 31, (31 * 86400 + 5 * 60 + 3) / 86400.0, np.nan]
  108. )
  109. tm.assert_equal(result, expected)
  110. # We don't support "D" reso, so we use the pre-2.0 behavior
  111. # casting to float64
  112. msg = (
  113. r"Cannot convert from timedelta64\[ns\] to timedelta64\[D\]. "
  114. "Supported resolutions are 's', 'ms', 'us', 'ns'"
  115. )
  116. with pytest.raises(ValueError, match=msg):
  117. td.astype("timedelta64[D]")
  118. result = td / np.timedelta64(1, "s")
  119. expected = index_or_series(
  120. [31 * 86400, 31 * 86400, 31 * 86400 + 5 * 60 + 3, np.nan]
  121. )
  122. tm.assert_equal(result, expected)
  123. exp_values = np.asarray(td).astype("m8[s]")
  124. exp_tda = TimedeltaArray._simple_new(exp_values, dtype=exp_values.dtype)
  125. expected = index_or_series(exp_tda)
  126. assert expected.dtype == "m8[s]"
  127. result = td.astype("timedelta64[s]")
  128. tm.assert_equal(result, expected)