test_ticks.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  1. """
  2. Tests for offsets.Tick and subclasses
  3. """
  4. from datetime import (
  5. datetime,
  6. timedelta,
  7. )
  8. from hypothesis import (
  9. assume,
  10. example,
  11. given,
  12. )
  13. import numpy as np
  14. import pytest
  15. from pandas._libs.tslibs.offsets import delta_to_tick
  16. from pandas import (
  17. Timedelta,
  18. Timestamp,
  19. )
  20. import pandas._testing as tm
  21. from pandas._testing._hypothesis import INT_NEG_999_TO_POS_999
  22. from pandas.tests.tseries.offsets.common import assert_offset_equal
  23. from pandas.tseries import offsets
  24. from pandas.tseries.offsets import (
  25. Hour,
  26. Micro,
  27. Milli,
  28. Minute,
  29. Nano,
  30. Second,
  31. )
  32. # ---------------------------------------------------------------------
  33. # Test Helpers
  34. tick_classes = [Hour, Minute, Second, Milli, Micro, Nano]
  35. # ---------------------------------------------------------------------
  36. def test_apply_ticks():
  37. result = offsets.Hour(3) + offsets.Hour(4)
  38. exp = offsets.Hour(7)
  39. assert result == exp
  40. def test_delta_to_tick():
  41. delta = timedelta(3)
  42. tick = delta_to_tick(delta)
  43. assert tick == offsets.Day(3)
  44. td = Timedelta(nanoseconds=5)
  45. tick = delta_to_tick(td)
  46. assert tick == Nano(5)
  47. @pytest.mark.parametrize("cls", tick_classes)
  48. @example(n=2, m=3)
  49. @example(n=800, m=300)
  50. @example(n=1000, m=5)
  51. @given(n=INT_NEG_999_TO_POS_999, m=INT_NEG_999_TO_POS_999)
  52. def test_tick_add_sub(cls, n, m):
  53. # For all Tick subclasses and all integers n, m, we should have
  54. # tick(n) + tick(m) == tick(n+m)
  55. # tick(n) - tick(m) == tick(n-m)
  56. left = cls(n)
  57. right = cls(m)
  58. expected = cls(n + m)
  59. assert left + right == expected
  60. expected = cls(n - m)
  61. assert left - right == expected
  62. @pytest.mark.arm_slow
  63. @pytest.mark.parametrize("cls", tick_classes)
  64. @example(n=2, m=3)
  65. @given(n=INT_NEG_999_TO_POS_999, m=INT_NEG_999_TO_POS_999)
  66. def test_tick_equality(cls, n, m):
  67. assume(m != n)
  68. # tick == tock iff tick.n == tock.n
  69. left = cls(n)
  70. right = cls(m)
  71. assert left != right
  72. right = cls(n)
  73. assert left == right
  74. assert not left != right
  75. if n != 0:
  76. assert cls(n) != cls(-n)
  77. # ---------------------------------------------------------------------
  78. def test_Hour():
  79. assert_offset_equal(Hour(), datetime(2010, 1, 1), datetime(2010, 1, 1, 1))
  80. assert_offset_equal(Hour(-1), datetime(2010, 1, 1, 1), datetime(2010, 1, 1))
  81. assert_offset_equal(2 * Hour(), datetime(2010, 1, 1), datetime(2010, 1, 1, 2))
  82. assert_offset_equal(-1 * Hour(), datetime(2010, 1, 1, 1), datetime(2010, 1, 1))
  83. assert Hour(3) + Hour(2) == Hour(5)
  84. assert Hour(3) - Hour(2) == Hour()
  85. assert Hour(4) != Hour(1)
  86. def test_Minute():
  87. assert_offset_equal(Minute(), datetime(2010, 1, 1), datetime(2010, 1, 1, 0, 1))
  88. assert_offset_equal(Minute(-1), datetime(2010, 1, 1, 0, 1), datetime(2010, 1, 1))
  89. assert_offset_equal(2 * Minute(), datetime(2010, 1, 1), datetime(2010, 1, 1, 0, 2))
  90. assert_offset_equal(-1 * Minute(), datetime(2010, 1, 1, 0, 1), datetime(2010, 1, 1))
  91. assert Minute(3) + Minute(2) == Minute(5)
  92. assert Minute(3) - Minute(2) == Minute()
  93. assert Minute(5) != Minute()
  94. def test_Second():
  95. assert_offset_equal(Second(), datetime(2010, 1, 1), datetime(2010, 1, 1, 0, 0, 1))
  96. assert_offset_equal(Second(-1), datetime(2010, 1, 1, 0, 0, 1), datetime(2010, 1, 1))
  97. assert_offset_equal(
  98. 2 * Second(), datetime(2010, 1, 1), datetime(2010, 1, 1, 0, 0, 2)
  99. )
  100. assert_offset_equal(
  101. -1 * Second(), datetime(2010, 1, 1, 0, 0, 1), datetime(2010, 1, 1)
  102. )
  103. assert Second(3) + Second(2) == Second(5)
  104. assert Second(3) - Second(2) == Second()
  105. def test_Millisecond():
  106. assert_offset_equal(
  107. Milli(), datetime(2010, 1, 1), datetime(2010, 1, 1, 0, 0, 0, 1000)
  108. )
  109. assert_offset_equal(
  110. Milli(-1), datetime(2010, 1, 1, 0, 0, 0, 1000), datetime(2010, 1, 1)
  111. )
  112. assert_offset_equal(
  113. Milli(2), datetime(2010, 1, 1), datetime(2010, 1, 1, 0, 0, 0, 2000)
  114. )
  115. assert_offset_equal(
  116. 2 * Milli(), datetime(2010, 1, 1), datetime(2010, 1, 1, 0, 0, 0, 2000)
  117. )
  118. assert_offset_equal(
  119. -1 * Milli(), datetime(2010, 1, 1, 0, 0, 0, 1000), datetime(2010, 1, 1)
  120. )
  121. assert Milli(3) + Milli(2) == Milli(5)
  122. assert Milli(3) - Milli(2) == Milli()
  123. def test_MillisecondTimestampArithmetic():
  124. assert_offset_equal(
  125. Milli(), Timestamp("2010-01-01"), Timestamp("2010-01-01 00:00:00.001")
  126. )
  127. assert_offset_equal(
  128. Milli(-1), Timestamp("2010-01-01 00:00:00.001"), Timestamp("2010-01-01")
  129. )
  130. def test_Microsecond():
  131. assert_offset_equal(Micro(), datetime(2010, 1, 1), datetime(2010, 1, 1, 0, 0, 0, 1))
  132. assert_offset_equal(
  133. Micro(-1), datetime(2010, 1, 1, 0, 0, 0, 1), datetime(2010, 1, 1)
  134. )
  135. assert_offset_equal(
  136. 2 * Micro(), datetime(2010, 1, 1), datetime(2010, 1, 1, 0, 0, 0, 2)
  137. )
  138. assert_offset_equal(
  139. -1 * Micro(), datetime(2010, 1, 1, 0, 0, 0, 1), datetime(2010, 1, 1)
  140. )
  141. assert Micro(3) + Micro(2) == Micro(5)
  142. assert Micro(3) - Micro(2) == Micro()
  143. def test_NanosecondGeneric():
  144. timestamp = Timestamp(datetime(2010, 1, 1))
  145. assert timestamp.nanosecond == 0
  146. result = timestamp + Nano(10)
  147. assert result.nanosecond == 10
  148. reverse_result = Nano(10) + timestamp
  149. assert reverse_result.nanosecond == 10
  150. def test_Nanosecond():
  151. timestamp = Timestamp(datetime(2010, 1, 1))
  152. assert_offset_equal(Nano(), timestamp, timestamp + np.timedelta64(1, "ns"))
  153. assert_offset_equal(Nano(-1), timestamp + np.timedelta64(1, "ns"), timestamp)
  154. assert_offset_equal(2 * Nano(), timestamp, timestamp + np.timedelta64(2, "ns"))
  155. assert_offset_equal(-1 * Nano(), timestamp + np.timedelta64(1, "ns"), timestamp)
  156. assert Nano(3) + Nano(2) == Nano(5)
  157. assert Nano(3) - Nano(2) == Nano()
  158. # GH9284
  159. assert Nano(1) + Nano(10) == Nano(11)
  160. assert Nano(5) + Micro(1) == Nano(1005)
  161. assert Micro(5) + Nano(1) == Nano(5001)
  162. @pytest.mark.parametrize(
  163. "kls, expected",
  164. [
  165. (Hour, Timedelta(hours=5)),
  166. (Minute, Timedelta(hours=2, minutes=3)),
  167. (Second, Timedelta(hours=2, seconds=3)),
  168. (Milli, Timedelta(hours=2, milliseconds=3)),
  169. (Micro, Timedelta(hours=2, microseconds=3)),
  170. (Nano, Timedelta(hours=2, nanoseconds=3)),
  171. ],
  172. )
  173. def test_tick_addition(kls, expected):
  174. offset = kls(3)
  175. td = Timedelta(hours=2)
  176. for other in [td, td.to_pytimedelta(), td.to_timedelta64()]:
  177. result = offset + other
  178. assert isinstance(result, Timedelta)
  179. assert result == expected
  180. result = other + offset
  181. assert isinstance(result, Timedelta)
  182. assert result == expected
  183. @pytest.mark.parametrize("cls", tick_classes)
  184. def test_tick_division(cls):
  185. off = cls(10)
  186. assert off / cls(5) == 2
  187. assert off / 2 == cls(5)
  188. assert off / 2.0 == cls(5)
  189. assert off / off.delta == 1
  190. assert off / off.delta.to_timedelta64() == 1
  191. assert off / Nano(1) == off.delta / Nano(1).delta
  192. if cls is not Nano:
  193. # A case where we end up with a smaller class
  194. result = off / 1000
  195. assert isinstance(result, offsets.Tick)
  196. assert not isinstance(result, cls)
  197. assert result.delta == off.delta / 1000
  198. if cls._nanos_inc < Timedelta(seconds=1)._value:
  199. # Case where we end up with a bigger class
  200. result = off / 0.001
  201. assert isinstance(result, offsets.Tick)
  202. assert not isinstance(result, cls)
  203. assert result.delta == off.delta / 0.001
  204. def test_tick_mul_float():
  205. off = Micro(2)
  206. # Case where we retain type
  207. result = off * 1.5
  208. expected = Micro(3)
  209. assert result == expected
  210. assert isinstance(result, Micro)
  211. # Case where we bump up to the next type
  212. result = off * 1.25
  213. expected = Nano(2500)
  214. assert result == expected
  215. assert isinstance(result, Nano)
  216. @pytest.mark.parametrize("cls", tick_classes)
  217. def test_tick_rdiv(cls):
  218. off = cls(10)
  219. delta = off.delta
  220. td64 = delta.to_timedelta64()
  221. instance__type = ".".join([cls.__module__, cls.__name__])
  222. msg = (
  223. "unsupported operand type\\(s\\) for \\/: 'int'|'float' and "
  224. f"'{instance__type}'"
  225. )
  226. with pytest.raises(TypeError, match=msg):
  227. 2 / off
  228. with pytest.raises(TypeError, match=msg):
  229. 2.0 / off
  230. assert (td64 * 2.5) / off == 2.5
  231. if cls is not Nano:
  232. # skip pytimedelta for Nano since it gets dropped
  233. assert (delta.to_pytimedelta() * 2) / off == 2
  234. result = np.array([2 * td64, td64]) / off
  235. expected = np.array([2.0, 1.0])
  236. tm.assert_numpy_array_equal(result, expected)
  237. @pytest.mark.parametrize("cls1", tick_classes)
  238. @pytest.mark.parametrize("cls2", tick_classes)
  239. def test_tick_zero(cls1, cls2):
  240. assert cls1(0) == cls2(0)
  241. assert cls1(0) + cls2(0) == cls1(0)
  242. if cls1 is not Nano:
  243. assert cls1(2) + cls2(0) == cls1(2)
  244. if cls1 is Nano:
  245. assert cls1(2) + Nano(0) == cls1(2)
  246. @pytest.mark.parametrize("cls", tick_classes)
  247. def test_tick_equalities(cls):
  248. assert cls() == cls(1)
  249. @pytest.mark.parametrize("cls", tick_classes)
  250. def test_tick_offset(cls):
  251. assert not cls().is_anchored()
  252. @pytest.mark.parametrize("cls", tick_classes)
  253. def test_compare_ticks(cls):
  254. three = cls(3)
  255. four = cls(4)
  256. assert three < cls(4)
  257. assert cls(3) < four
  258. assert four > cls(3)
  259. assert cls(4) > three
  260. assert cls(3) == cls(3)
  261. assert cls(3) != cls(4)
  262. @pytest.mark.parametrize("cls", tick_classes)
  263. def test_compare_ticks_to_strs(cls):
  264. # GH#23524
  265. off = cls(19)
  266. # These tests should work with any strings, but we particularly are
  267. # interested in "infer" as that comparison is convenient to make in
  268. # Datetime/Timedelta Array/Index constructors
  269. assert not off == "infer"
  270. assert not "foo" == off
  271. instance_type = ".".join([cls.__module__, cls.__name__])
  272. msg = (
  273. "'<'|'<='|'>'|'>=' not supported between instances of "
  274. f"'str' and '{instance_type}'|'{instance_type}' and 'str'"
  275. )
  276. for left, right in [("infer", off), (off, "infer")]:
  277. with pytest.raises(TypeError, match=msg):
  278. left < right
  279. with pytest.raises(TypeError, match=msg):
  280. left <= right
  281. with pytest.raises(TypeError, match=msg):
  282. left > right
  283. with pytest.raises(TypeError, match=msg):
  284. left >= right
  285. @pytest.mark.parametrize("cls", tick_classes)
  286. def test_compare_ticks_to_timedeltalike(cls):
  287. off = cls(19)
  288. td = off.delta
  289. others = [td, td.to_timedelta64()]
  290. if cls is not Nano:
  291. others.append(td.to_pytimedelta())
  292. for other in others:
  293. assert off == other
  294. assert not off != other
  295. assert not off < other
  296. assert not off > other
  297. assert off <= other
  298. assert off >= other