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