Skip to content

REF: collect Timestamp tests by method #55674

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Oct 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file.
86 changes: 86 additions & 0 deletions pandas/tests/scalar/timestamp/methods/test_as_unit.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import pytest

from pandas._libs.tslibs.dtypes import NpyDatetimeUnit
from pandas.errors import OutOfBoundsDatetime

from pandas import Timestamp


class TestTimestampAsUnit:
def test_as_unit(self):
ts = Timestamp("1970-01-01").as_unit("ns")
assert ts.unit == "ns"

assert ts.as_unit("ns") is ts

res = ts.as_unit("us")
assert res._value == ts._value // 1000
assert res._creso == NpyDatetimeUnit.NPY_FR_us.value

rt = res.as_unit("ns")
assert rt._value == ts._value
assert rt._creso == ts._creso

res = ts.as_unit("ms")
assert res._value == ts._value // 1_000_000
assert res._creso == NpyDatetimeUnit.NPY_FR_ms.value

rt = res.as_unit("ns")
assert rt._value == ts._value
assert rt._creso == ts._creso

res = ts.as_unit("s")
assert res._value == ts._value // 1_000_000_000
assert res._creso == NpyDatetimeUnit.NPY_FR_s.value

rt = res.as_unit("ns")
assert rt._value == ts._value
assert rt._creso == ts._creso

def test_as_unit_overflows(self):
# microsecond that would be just out of bounds for nano
us = 9223372800000000
ts = Timestamp._from_value_and_reso(us, NpyDatetimeUnit.NPY_FR_us.value, None)

msg = "Cannot cast 2262-04-12 00:00:00 to unit='ns' without overflow"
with pytest.raises(OutOfBoundsDatetime, match=msg):
ts.as_unit("ns")

res = ts.as_unit("ms")
assert res._value == us // 1000
assert res._creso == NpyDatetimeUnit.NPY_FR_ms.value

def test_as_unit_rounding(self):
ts = Timestamp(1_500_000) # i.e. 1500 microseconds
res = ts.as_unit("ms")

expected = Timestamp(1_000_000) # i.e. 1 millisecond
assert res == expected

assert res._creso == NpyDatetimeUnit.NPY_FR_ms.value
assert res._value == 1

with pytest.raises(ValueError, match="Cannot losslessly convert units"):
ts.as_unit("ms", round_ok=False)

def test_as_unit_non_nano(self):
# case where we are going neither to nor from nano
ts = Timestamp("1970-01-02").as_unit("ms")
assert ts.year == 1970
assert ts.month == 1
assert ts.day == 2
assert ts.hour == ts.minute == ts.second == ts.microsecond == ts.nanosecond == 0

res = ts.as_unit("s")
assert res._value == 24 * 3600
assert res.year == 1970
assert res.month == 1
assert res.day == 2
assert (
res.hour
== res.minute
== res.second
== res.microsecond
== res.nanosecond
== 0
)
22 changes: 22 additions & 0 deletions pandas/tests/scalar/timestamp/methods/test_normalize.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import pytest

from pandas._libs.tslibs import Timestamp
from pandas._libs.tslibs.dtypes import NpyDatetimeUnit


class TestTimestampNormalize:
@pytest.mark.parametrize("arg", ["2013-11-30", "2013-11-30 12:00:00"])
@pytest.mark.parametrize("unit", ["ns", "us", "ms", "s"])
def test_normalize(self, tz_naive_fixture, arg, unit):
tz = tz_naive_fixture
ts = Timestamp(arg, tz=tz).as_unit(unit)
result = ts.normalize()
expected = Timestamp("2013-11-30", tz=tz)
assert result == expected
assert result._creso == getattr(NpyDatetimeUnit, f"NPY_FR_{unit}").value

def test_normalize_pre_epoch_dates(self):
# GH: 36294
result = Timestamp("1969-01-01 09:00:00").normalize()
expected = Timestamp("1969-01-01 00:00:00")
assert result == expected
193 changes: 193 additions & 0 deletions pandas/tests/scalar/timestamp/methods/test_replace.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
from datetime import datetime

from dateutil.tz import gettz
import numpy as np
import pytest
import pytz

from pandas._libs.tslibs import (
OutOfBoundsDatetime,
Timestamp,
conversion,
)
from pandas._libs.tslibs.dtypes import NpyDatetimeUnit
import pandas.util._test_decorators as td

import pandas._testing as tm


class TestTimestampReplace:
def test_replace_out_of_pydatetime_bounds(self):
# GH#50348
ts = Timestamp("2016-01-01").as_unit("ns")

msg = "Out of bounds nanosecond timestamp: 99999-01-01 00:00:00"
with pytest.raises(OutOfBoundsDatetime, match=msg):
ts.replace(year=99_999)

ts = ts.as_unit("ms")
result = ts.replace(year=99_999)
assert result.year == 99_999
assert result._value == Timestamp(np.datetime64("99999-01-01", "ms"))._value

def test_replace_non_nano(self):
ts = Timestamp._from_value_and_reso(
91514880000000000, NpyDatetimeUnit.NPY_FR_us.value, None
)
assert ts.to_pydatetime() == datetime(4869, 12, 28)

result = ts.replace(year=4900)
assert result._creso == ts._creso
assert result.to_pydatetime() == datetime(4900, 12, 28)

def test_replace_naive(self):
# GH#14621, GH#7825
ts = Timestamp("2016-01-01 09:00:00")
result = ts.replace(hour=0)
expected = Timestamp("2016-01-01 00:00:00")
assert result == expected

def test_replace_aware(self, tz_aware_fixture):
tz = tz_aware_fixture
# GH#14621, GH#7825
# replacing datetime components with and w/o presence of a timezone
ts = Timestamp("2016-01-01 09:00:00", tz=tz)
result = ts.replace(hour=0)
expected = Timestamp("2016-01-01 00:00:00", tz=tz)
assert result == expected

def test_replace_preserves_nanos(self, tz_aware_fixture):
tz = tz_aware_fixture
# GH#14621, GH#7825
ts = Timestamp("2016-01-01 09:00:00.000000123", tz=tz)
result = ts.replace(hour=0)
expected = Timestamp("2016-01-01 00:00:00.000000123", tz=tz)
assert result == expected

def test_replace_multiple(self, tz_aware_fixture):
tz = tz_aware_fixture
# GH#14621, GH#7825
# replacing datetime components with and w/o presence of a timezone
# test all
ts = Timestamp("2016-01-01 09:00:00.000000123", tz=tz)
result = ts.replace(
year=2015,
month=2,
day=2,
hour=0,
minute=5,
second=5,
microsecond=5,
nanosecond=5,
)
expected = Timestamp("2015-02-02 00:05:05.000005005", tz=tz)
assert result == expected

def test_replace_invalid_kwarg(self, tz_aware_fixture):
tz = tz_aware_fixture
# GH#14621, GH#7825
ts = Timestamp("2016-01-01 09:00:00.000000123", tz=tz)
msg = r"replace\(\) got an unexpected keyword argument"
with pytest.raises(TypeError, match=msg):
ts.replace(foo=5)

def test_replace_integer_args(self, tz_aware_fixture):
tz = tz_aware_fixture
# GH#14621, GH#7825
ts = Timestamp("2016-01-01 09:00:00.000000123", tz=tz)
msg = "value must be an integer, received <class 'float'> for hour"
with pytest.raises(ValueError, match=msg):
ts.replace(hour=0.1)

def test_replace_tzinfo_equiv_tz_localize_none(self):
# GH#14621, GH#7825
# assert conversion to naive is the same as replacing tzinfo with None
ts = Timestamp("2013-11-03 01:59:59.999999-0400", tz="US/Eastern")
assert ts.tz_localize(None) == ts.replace(tzinfo=None)

@td.skip_if_windows
def test_replace_tzinfo(self):
# GH#15683
dt = datetime(2016, 3, 27, 1)
tzinfo = pytz.timezone("CET").localize(dt, is_dst=False).tzinfo

result_dt = dt.replace(tzinfo=tzinfo)
result_pd = Timestamp(dt).replace(tzinfo=tzinfo)

# datetime.timestamp() converts in the local timezone
with tm.set_timezone("UTC"):
assert result_dt.timestamp() == result_pd.timestamp()

assert result_dt == result_pd
assert result_dt == result_pd.to_pydatetime()

result_dt = dt.replace(tzinfo=tzinfo).replace(tzinfo=None)
result_pd = Timestamp(dt).replace(tzinfo=tzinfo).replace(tzinfo=None)

# datetime.timestamp() converts in the local timezone
with tm.set_timezone("UTC"):
assert result_dt.timestamp() == result_pd.timestamp()

assert result_dt == result_pd
assert result_dt == result_pd.to_pydatetime()

@pytest.mark.parametrize(
"tz, normalize",
[
(pytz.timezone("US/Eastern"), lambda x: x.tzinfo.normalize(x)),
(gettz("US/Eastern"), lambda x: x),
],
)
def test_replace_across_dst(self, tz, normalize):
# GH#18319 check that 1) timezone is correctly normalized and
# 2) that hour is not incorrectly changed by this normalization
ts_naive = Timestamp("2017-12-03 16:03:30")
ts_aware = conversion.localize_pydatetime(ts_naive, tz)

# Preliminary sanity-check
assert ts_aware == normalize(ts_aware)

# Replace across DST boundary
ts2 = ts_aware.replace(month=6)

# Check that `replace` preserves hour literal
assert (ts2.hour, ts2.minute) == (ts_aware.hour, ts_aware.minute)

# Check that post-replace object is appropriately normalized
ts2b = normalize(ts2)
assert ts2 == ts2b

@pytest.mark.parametrize("unit", ["ns", "us", "ms", "s"])
def test_replace_dst_border(self, unit):
# Gh 7825
t = Timestamp("2013-11-3", tz="America/Chicago").as_unit(unit)
result = t.replace(hour=3)
expected = Timestamp("2013-11-3 03:00:00", tz="America/Chicago")
assert result == expected
assert result._creso == getattr(NpyDatetimeUnit, f"NPY_FR_{unit}").value

@pytest.mark.parametrize("fold", [0, 1])
@pytest.mark.parametrize("tz", ["dateutil/Europe/London", "Europe/London"])
@pytest.mark.parametrize("unit", ["ns", "us", "ms", "s"])
def test_replace_dst_fold(self, fold, tz, unit):
# GH 25017
d = datetime(2019, 10, 27, 2, 30)
ts = Timestamp(d, tz=tz).as_unit(unit)
result = ts.replace(hour=1, fold=fold)
expected = Timestamp(datetime(2019, 10, 27, 1, 30)).tz_localize(
tz, ambiguous=not fold
)
assert result == expected
assert result._creso == getattr(NpyDatetimeUnit, f"NPY_FR_{unit}").value

@pytest.mark.parametrize("fold", [0, 1])
def test_replace_preserves_fold(self, fold):
# GH#37610. Check that replace preserves Timestamp fold property
tz = gettz("Europe/Moscow")

ts = Timestamp(
year=2009, month=10, day=25, hour=2, minute=30, fold=fold, tzinfo=tz
)
ts_replaced = ts.replace(second=1)

assert ts_replaced.fold == fold
Loading