Updated script that can be controled by Nodejs web app
This commit is contained in:
65
lib/python3.13/site-packages/pandas/tests/tslibs/test_api.py
Normal file
65
lib/python3.13/site-packages/pandas/tests/tslibs/test_api.py
Normal file
@ -0,0 +1,65 @@
|
||||
"""Tests that the tslibs API is locked down"""
|
||||
|
||||
from pandas._libs import tslibs
|
||||
|
||||
|
||||
def test_namespace():
|
||||
submodules = [
|
||||
"base",
|
||||
"ccalendar",
|
||||
"conversion",
|
||||
"dtypes",
|
||||
"fields",
|
||||
"nattype",
|
||||
"np_datetime",
|
||||
"offsets",
|
||||
"parsing",
|
||||
"period",
|
||||
"strptime",
|
||||
"vectorized",
|
||||
"timedeltas",
|
||||
"timestamps",
|
||||
"timezones",
|
||||
"tzconversion",
|
||||
]
|
||||
|
||||
api = [
|
||||
"BaseOffset",
|
||||
"NaT",
|
||||
"NaTType",
|
||||
"iNaT",
|
||||
"nat_strings",
|
||||
"OutOfBoundsDatetime",
|
||||
"OutOfBoundsTimedelta",
|
||||
"Period",
|
||||
"IncompatibleFrequency",
|
||||
"Resolution",
|
||||
"Tick",
|
||||
"Timedelta",
|
||||
"dt64arr_to_periodarr",
|
||||
"Timestamp",
|
||||
"is_date_array_normalized",
|
||||
"ints_to_pydatetime",
|
||||
"normalize_i8_timestamps",
|
||||
"get_resolution",
|
||||
"delta_to_nanoseconds",
|
||||
"ints_to_pytimedelta",
|
||||
"localize_pydatetime",
|
||||
"tz_convert_from_utc",
|
||||
"tz_convert_from_utc_single",
|
||||
"to_offset",
|
||||
"tz_compare",
|
||||
"is_unitless",
|
||||
"astype_overflowsafe",
|
||||
"get_unit_from_dtype",
|
||||
"periods_per_day",
|
||||
"periods_per_second",
|
||||
"guess_datetime_format",
|
||||
"add_overflowsafe",
|
||||
"get_supported_dtype",
|
||||
"is_supported_dtype",
|
||||
]
|
||||
|
||||
expected = set(submodules + api)
|
||||
names = [x for x in dir(tslibs) if not x.startswith("__")]
|
||||
assert set(names) == expected
|
@ -0,0 +1,337 @@
|
||||
from datetime import (
|
||||
date,
|
||||
datetime,
|
||||
timedelta,
|
||||
timezone,
|
||||
)
|
||||
|
||||
from dateutil.tz.tz import tzoffset
|
||||
import numpy as np
|
||||
import pytest
|
||||
|
||||
from pandas._libs import (
|
||||
NaT,
|
||||
iNaT,
|
||||
tslib,
|
||||
)
|
||||
from pandas._libs.tslibs.dtypes import NpyDatetimeUnit
|
||||
from pandas._libs.tslibs.np_datetime import OutOfBoundsDatetime
|
||||
|
||||
from pandas import Timestamp
|
||||
import pandas._testing as tm
|
||||
|
||||
creso_infer = NpyDatetimeUnit.NPY_FR_GENERIC.value
|
||||
|
||||
|
||||
class TestArrayToDatetimeResolutionInference:
|
||||
# TODO: tests that include tzs, ints
|
||||
|
||||
def test_infer_all_nat(self):
|
||||
arr = np.array([NaT, np.nan], dtype=object)
|
||||
result, tz = tslib.array_to_datetime(arr, creso=creso_infer)
|
||||
assert tz is None
|
||||
assert result.dtype == "M8[s]"
|
||||
|
||||
def test_infer_homogeoneous_datetimes(self):
|
||||
dt = datetime(2023, 10, 27, 18, 3, 5, 678000)
|
||||
arr = np.array([dt, dt, dt], dtype=object)
|
||||
result, tz = tslib.array_to_datetime(arr, creso=creso_infer)
|
||||
assert tz is None
|
||||
expected = np.array([dt, dt, dt], dtype="M8[us]")
|
||||
tm.assert_numpy_array_equal(result, expected)
|
||||
|
||||
def test_infer_homogeoneous_date_objects(self):
|
||||
dt = datetime(2023, 10, 27, 18, 3, 5, 678000)
|
||||
dt2 = dt.date()
|
||||
arr = np.array([None, dt2, dt2, dt2], dtype=object)
|
||||
result, tz = tslib.array_to_datetime(arr, creso=creso_infer)
|
||||
assert tz is None
|
||||
expected = np.array([np.datetime64("NaT"), dt2, dt2, dt2], dtype="M8[s]")
|
||||
tm.assert_numpy_array_equal(result, expected)
|
||||
|
||||
def test_infer_homogeoneous_dt64(self):
|
||||
dt = datetime(2023, 10, 27, 18, 3, 5, 678000)
|
||||
dt64 = np.datetime64(dt, "ms")
|
||||
arr = np.array([None, dt64, dt64, dt64], dtype=object)
|
||||
result, tz = tslib.array_to_datetime(arr, creso=creso_infer)
|
||||
assert tz is None
|
||||
expected = np.array([np.datetime64("NaT"), dt64, dt64, dt64], dtype="M8[ms]")
|
||||
tm.assert_numpy_array_equal(result, expected)
|
||||
|
||||
def test_infer_homogeoneous_timestamps(self):
|
||||
dt = datetime(2023, 10, 27, 18, 3, 5, 678000)
|
||||
ts = Timestamp(dt).as_unit("ns")
|
||||
arr = np.array([None, ts, ts, ts], dtype=object)
|
||||
result, tz = tslib.array_to_datetime(arr, creso=creso_infer)
|
||||
assert tz is None
|
||||
expected = np.array([np.datetime64("NaT")] + [ts.asm8] * 3, dtype="M8[ns]")
|
||||
tm.assert_numpy_array_equal(result, expected)
|
||||
|
||||
def test_infer_homogeoneous_datetimes_strings(self):
|
||||
item = "2023-10-27 18:03:05.678000"
|
||||
arr = np.array([None, item, item, item], dtype=object)
|
||||
result, tz = tslib.array_to_datetime(arr, creso=creso_infer)
|
||||
assert tz is None
|
||||
expected = np.array([np.datetime64("NaT"), item, item, item], dtype="M8[us]")
|
||||
tm.assert_numpy_array_equal(result, expected)
|
||||
|
||||
def test_infer_heterogeneous(self):
|
||||
dtstr = "2023-10-27 18:03:05.678000"
|
||||
|
||||
arr = np.array([dtstr, dtstr[:-3], dtstr[:-7], None], dtype=object)
|
||||
result, tz = tslib.array_to_datetime(arr, creso=creso_infer)
|
||||
assert tz is None
|
||||
expected = np.array(arr, dtype="M8[us]")
|
||||
tm.assert_numpy_array_equal(result, expected)
|
||||
|
||||
result, tz = tslib.array_to_datetime(arr[::-1], creso=creso_infer)
|
||||
assert tz is None
|
||||
tm.assert_numpy_array_equal(result, expected[::-1])
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"item", [float("nan"), NaT.value, float(NaT.value), "NaT", ""]
|
||||
)
|
||||
def test_infer_with_nat_int_float_str(self, item):
|
||||
# floats/ints get inferred to nanos *unless* they are NaN/iNaT,
|
||||
# similar NaT string gets treated like NaT scalar (ignored for resolution)
|
||||
dt = datetime(2023, 11, 15, 15, 5, 6)
|
||||
|
||||
arr = np.array([dt, item], dtype=object)
|
||||
result, tz = tslib.array_to_datetime(arr, creso=creso_infer)
|
||||
assert tz is None
|
||||
expected = np.array([dt, np.datetime64("NaT")], dtype="M8[us]")
|
||||
tm.assert_numpy_array_equal(result, expected)
|
||||
|
||||
result2, tz2 = tslib.array_to_datetime(arr[::-1], creso=creso_infer)
|
||||
assert tz2 is None
|
||||
tm.assert_numpy_array_equal(result2, expected[::-1])
|
||||
|
||||
|
||||
class TestArrayToDatetimeWithTZResolutionInference:
|
||||
def test_array_to_datetime_with_tz_resolution(self):
|
||||
tz = tzoffset("custom", 3600)
|
||||
vals = np.array(["2016-01-01 02:03:04.567", NaT], dtype=object)
|
||||
res = tslib.array_to_datetime_with_tz(vals, tz, False, False, creso_infer)
|
||||
assert res.dtype == "M8[ms]"
|
||||
|
||||
vals2 = np.array([datetime(2016, 1, 1, 2, 3, 4), NaT], dtype=object)
|
||||
res2 = tslib.array_to_datetime_with_tz(vals2, tz, False, False, creso_infer)
|
||||
assert res2.dtype == "M8[us]"
|
||||
|
||||
vals3 = np.array([NaT, np.datetime64(12345, "s")], dtype=object)
|
||||
res3 = tslib.array_to_datetime_with_tz(vals3, tz, False, False, creso_infer)
|
||||
assert res3.dtype == "M8[s]"
|
||||
|
||||
def test_array_to_datetime_with_tz_resolution_all_nat(self):
|
||||
tz = tzoffset("custom", 3600)
|
||||
vals = np.array(["NaT"], dtype=object)
|
||||
res = tslib.array_to_datetime_with_tz(vals, tz, False, False, creso_infer)
|
||||
assert res.dtype == "M8[s]"
|
||||
|
||||
vals2 = np.array([NaT, NaT], dtype=object)
|
||||
res2 = tslib.array_to_datetime_with_tz(vals2, tz, False, False, creso_infer)
|
||||
assert res2.dtype == "M8[s]"
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"data,expected",
|
||||
[
|
||||
(
|
||||
["01-01-2013", "01-02-2013"],
|
||||
[
|
||||
"2013-01-01T00:00:00.000000000",
|
||||
"2013-01-02T00:00:00.000000000",
|
||||
],
|
||||
),
|
||||
(
|
||||
["Mon Sep 16 2013", "Tue Sep 17 2013"],
|
||||
[
|
||||
"2013-09-16T00:00:00.000000000",
|
||||
"2013-09-17T00:00:00.000000000",
|
||||
],
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_parsing_valid_dates(data, expected):
|
||||
arr = np.array(data, dtype=object)
|
||||
result, _ = tslib.array_to_datetime(arr)
|
||||
|
||||
expected = np.array(expected, dtype="M8[ns]")
|
||||
tm.assert_numpy_array_equal(result, expected)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"dt_string, expected_tz",
|
||||
[
|
||||
["01-01-2013 08:00:00+08:00", 480],
|
||||
["2013-01-01T08:00:00.000000000+0800", 480],
|
||||
["2012-12-31T16:00:00.000000000-0800", -480],
|
||||
["12-31-2012 23:00:00-01:00", -60],
|
||||
],
|
||||
)
|
||||
def test_parsing_timezone_offsets(dt_string, expected_tz):
|
||||
# All of these datetime strings with offsets are equivalent
|
||||
# to the same datetime after the timezone offset is added.
|
||||
arr = np.array(["01-01-2013 00:00:00"], dtype=object)
|
||||
expected, _ = tslib.array_to_datetime(arr)
|
||||
|
||||
arr = np.array([dt_string], dtype=object)
|
||||
result, result_tz = tslib.array_to_datetime(arr)
|
||||
|
||||
tm.assert_numpy_array_equal(result, expected)
|
||||
assert result_tz == timezone(timedelta(minutes=expected_tz))
|
||||
|
||||
|
||||
def test_parsing_non_iso_timezone_offset():
|
||||
dt_string = "01-01-2013T00:00:00.000000000+0000"
|
||||
arr = np.array([dt_string], dtype=object)
|
||||
|
||||
with tm.assert_produces_warning(None):
|
||||
# GH#50949 should not get tzlocal-deprecation warning here
|
||||
result, result_tz = tslib.array_to_datetime(arr)
|
||||
expected = np.array([np.datetime64("2013-01-01 00:00:00.000000000")])
|
||||
|
||||
tm.assert_numpy_array_equal(result, expected)
|
||||
assert result_tz is timezone.utc
|
||||
|
||||
|
||||
def test_parsing_different_timezone_offsets():
|
||||
# see gh-17697
|
||||
data = ["2015-11-18 15:30:00+05:30", "2015-11-18 15:30:00+06:30"]
|
||||
data = np.array(data, dtype=object)
|
||||
|
||||
msg = "parsing datetimes with mixed time zones will raise an error"
|
||||
with tm.assert_produces_warning(FutureWarning, match=msg):
|
||||
result, result_tz = tslib.array_to_datetime(data)
|
||||
expected = np.array(
|
||||
[
|
||||
datetime(2015, 11, 18, 15, 30, tzinfo=tzoffset(None, 19800)),
|
||||
datetime(2015, 11, 18, 15, 30, tzinfo=tzoffset(None, 23400)),
|
||||
],
|
||||
dtype=object,
|
||||
)
|
||||
|
||||
tm.assert_numpy_array_equal(result, expected)
|
||||
assert result_tz is None
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"data", [["-352.737091", "183.575577"], ["1", "2", "3", "4", "5"]]
|
||||
)
|
||||
def test_number_looking_strings_not_into_datetime(data):
|
||||
# see gh-4601
|
||||
#
|
||||
# These strings don't look like datetimes, so
|
||||
# they shouldn't be attempted to be converted.
|
||||
arr = np.array(data, dtype=object)
|
||||
result, _ = tslib.array_to_datetime(arr, errors="ignore")
|
||||
|
||||
tm.assert_numpy_array_equal(result, arr)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"invalid_date",
|
||||
[
|
||||
date(1000, 1, 1),
|
||||
datetime(1000, 1, 1),
|
||||
"1000-01-01",
|
||||
"Jan 1, 1000",
|
||||
np.datetime64("1000-01-01"),
|
||||
],
|
||||
)
|
||||
@pytest.mark.parametrize("errors", ["coerce", "raise"])
|
||||
def test_coerce_outside_ns_bounds(invalid_date, errors):
|
||||
arr = np.array([invalid_date], dtype="object")
|
||||
kwargs = {"values": arr, "errors": errors}
|
||||
|
||||
if errors == "raise":
|
||||
msg = "^Out of bounds nanosecond timestamp: .*, at position 0$"
|
||||
|
||||
with pytest.raises(OutOfBoundsDatetime, match=msg):
|
||||
tslib.array_to_datetime(**kwargs)
|
||||
else: # coerce.
|
||||
result, _ = tslib.array_to_datetime(**kwargs)
|
||||
expected = np.array([iNaT], dtype="M8[ns]")
|
||||
|
||||
tm.assert_numpy_array_equal(result, expected)
|
||||
|
||||
|
||||
def test_coerce_outside_ns_bounds_one_valid():
|
||||
arr = np.array(["1/1/1000", "1/1/2000"], dtype=object)
|
||||
result, _ = tslib.array_to_datetime(arr, errors="coerce")
|
||||
|
||||
expected = [iNaT, "2000-01-01T00:00:00.000000000"]
|
||||
expected = np.array(expected, dtype="M8[ns]")
|
||||
|
||||
tm.assert_numpy_array_equal(result, expected)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("errors", ["ignore", "coerce"])
|
||||
def test_coerce_of_invalid_datetimes(errors):
|
||||
arr = np.array(["01-01-2013", "not_a_date", "1"], dtype=object)
|
||||
kwargs = {"values": arr, "errors": errors}
|
||||
|
||||
if errors == "ignore":
|
||||
# Without coercing, the presence of any invalid
|
||||
# dates prevents any values from being converted.
|
||||
result, _ = tslib.array_to_datetime(**kwargs)
|
||||
tm.assert_numpy_array_equal(result, arr)
|
||||
else: # coerce.
|
||||
# With coercing, the invalid dates becomes iNaT
|
||||
result, _ = tslib.array_to_datetime(arr, errors="coerce")
|
||||
expected = ["2013-01-01T00:00:00.000000000", iNaT, iNaT]
|
||||
|
||||
tm.assert_numpy_array_equal(result, np.array(expected, dtype="M8[ns]"))
|
||||
|
||||
|
||||
def test_to_datetime_barely_out_of_bounds():
|
||||
# see gh-19382, gh-19529
|
||||
#
|
||||
# Close enough to bounds that dropping nanos
|
||||
# would result in an in-bounds datetime.
|
||||
arr = np.array(["2262-04-11 23:47:16.854775808"], dtype=object)
|
||||
msg = "^Out of bounds nanosecond timestamp: 2262-04-11 23:47:16, at position 0$"
|
||||
|
||||
with pytest.raises(tslib.OutOfBoundsDatetime, match=msg):
|
||||
tslib.array_to_datetime(arr)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"timestamp",
|
||||
[
|
||||
# Close enough to bounds that scaling micros to nanos overflows
|
||||
# but adding nanos would result in an in-bounds datetime.
|
||||
"1677-09-21T00:12:43.145224193",
|
||||
"1677-09-21T00:12:43.145224999",
|
||||
# this always worked
|
||||
"1677-09-21T00:12:43.145225000",
|
||||
],
|
||||
)
|
||||
def test_to_datetime_barely_inside_bounds(timestamp):
|
||||
# see gh-57150
|
||||
result, _ = tslib.array_to_datetime(np.array([timestamp], dtype=object))
|
||||
tm.assert_numpy_array_equal(result, np.array([timestamp], dtype="M8[ns]"))
|
||||
|
||||
|
||||
class SubDatetime(datetime):
|
||||
pass
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"data,expected",
|
||||
[
|
||||
([SubDatetime(2000, 1, 1)], ["2000-01-01T00:00:00.000000000"]),
|
||||
([datetime(2000, 1, 1)], ["2000-01-01T00:00:00.000000000"]),
|
||||
([Timestamp(2000, 1, 1)], ["2000-01-01T00:00:00.000000000"]),
|
||||
],
|
||||
)
|
||||
def test_datetime_subclass(data, expected):
|
||||
# GH 25851
|
||||
# ensure that subclassed datetime works with
|
||||
# array_to_datetime
|
||||
|
||||
arr = np.array(data, dtype=object)
|
||||
result, _ = tslib.array_to_datetime(arr)
|
||||
|
||||
expected = np.array(expected, dtype="M8[ns]")
|
||||
tm.assert_numpy_array_equal(result, expected)
|
@ -0,0 +1,63 @@
|
||||
from datetime import (
|
||||
date,
|
||||
datetime,
|
||||
)
|
||||
|
||||
from hypothesis import given
|
||||
import numpy as np
|
||||
import pytest
|
||||
|
||||
from pandas._libs.tslibs import ccalendar
|
||||
|
||||
from pandas._testing._hypothesis import DATETIME_IN_PD_TIMESTAMP_RANGE_NO_TZ
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"date_tuple,expected",
|
||||
[
|
||||
((2001, 3, 1), 60),
|
||||
((2004, 3, 1), 61),
|
||||
((1907, 12, 31), 365), # End-of-year, non-leap year.
|
||||
((2004, 12, 31), 366), # End-of-year, leap year.
|
||||
],
|
||||
)
|
||||
def test_get_day_of_year_numeric(date_tuple, expected):
|
||||
assert ccalendar.get_day_of_year(*date_tuple) == expected
|
||||
|
||||
|
||||
def test_get_day_of_year_dt():
|
||||
dt = datetime.fromordinal(1 + np.random.default_rng(2).integers(365 * 4000))
|
||||
result = ccalendar.get_day_of_year(dt.year, dt.month, dt.day)
|
||||
|
||||
expected = (dt - dt.replace(month=1, day=1)).days + 1
|
||||
assert result == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"input_date_tuple, expected_iso_tuple",
|
||||
[
|
||||
[(2020, 1, 1), (2020, 1, 3)],
|
||||
[(2019, 12, 31), (2020, 1, 2)],
|
||||
[(2019, 12, 30), (2020, 1, 1)],
|
||||
[(2009, 12, 31), (2009, 53, 4)],
|
||||
[(2010, 1, 1), (2009, 53, 5)],
|
||||
[(2010, 1, 3), (2009, 53, 7)],
|
||||
[(2010, 1, 4), (2010, 1, 1)],
|
||||
[(2006, 1, 1), (2005, 52, 7)],
|
||||
[(2005, 12, 31), (2005, 52, 6)],
|
||||
[(2008, 12, 28), (2008, 52, 7)],
|
||||
[(2008, 12, 29), (2009, 1, 1)],
|
||||
],
|
||||
)
|
||||
def test_dt_correct_iso_8601_year_week_and_day(input_date_tuple, expected_iso_tuple):
|
||||
result = ccalendar.get_iso_calendar(*input_date_tuple)
|
||||
expected_from_date_isocalendar = date(*input_date_tuple).isocalendar()
|
||||
assert result == expected_from_date_isocalendar
|
||||
assert result == expected_iso_tuple
|
||||
|
||||
|
||||
@given(DATETIME_IN_PD_TIMESTAMP_RANGE_NO_TZ)
|
||||
def test_isocalendar(dt):
|
||||
expected = dt.isocalendar()
|
||||
result = ccalendar.get_iso_calendar(dt.year, dt.month, dt.day)
|
||||
assert result == expected
|
@ -0,0 +1,160 @@
|
||||
from datetime import datetime
|
||||
|
||||
import numpy as np
|
||||
import pytest
|
||||
from pytz import UTC
|
||||
|
||||
from pandas._libs.tslibs import (
|
||||
OutOfBoundsTimedelta,
|
||||
astype_overflowsafe,
|
||||
conversion,
|
||||
iNaT,
|
||||
timezones,
|
||||
tz_convert_from_utc,
|
||||
tzconversion,
|
||||
)
|
||||
|
||||
from pandas import (
|
||||
Timestamp,
|
||||
date_range,
|
||||
)
|
||||
import pandas._testing as tm
|
||||
|
||||
|
||||
def _compare_utc_to_local(tz_didx):
|
||||
def f(x):
|
||||
return tzconversion.tz_convert_from_utc_single(x, tz_didx.tz)
|
||||
|
||||
result = tz_convert_from_utc(tz_didx.asi8, tz_didx.tz)
|
||||
expected = np.vectorize(f)(tz_didx.asi8)
|
||||
|
||||
tm.assert_numpy_array_equal(result, expected)
|
||||
|
||||
|
||||
def _compare_local_to_utc(tz_didx, naive_didx):
|
||||
# Check that tz_localize behaves the same vectorized and pointwise.
|
||||
err1 = err2 = None
|
||||
try:
|
||||
result = tzconversion.tz_localize_to_utc(naive_didx.asi8, tz_didx.tz)
|
||||
err1 = None
|
||||
except Exception as err:
|
||||
err1 = err
|
||||
|
||||
try:
|
||||
expected = naive_didx.map(lambda x: x.tz_localize(tz_didx.tz)).asi8
|
||||
except Exception as err:
|
||||
err2 = err
|
||||
|
||||
if err1 is not None:
|
||||
assert type(err1) == type(err2)
|
||||
else:
|
||||
assert err2 is None
|
||||
tm.assert_numpy_array_equal(result, expected)
|
||||
|
||||
|
||||
def test_tz_localize_to_utc_copies():
|
||||
# GH#46460
|
||||
arr = np.arange(5, dtype="i8")
|
||||
result = tz_convert_from_utc(arr, tz=UTC)
|
||||
tm.assert_numpy_array_equal(result, arr)
|
||||
assert not np.shares_memory(arr, result)
|
||||
|
||||
result = tz_convert_from_utc(arr, tz=None)
|
||||
tm.assert_numpy_array_equal(result, arr)
|
||||
assert not np.shares_memory(arr, result)
|
||||
|
||||
|
||||
def test_tz_convert_single_matches_tz_convert_hourly(tz_aware_fixture):
|
||||
tz = tz_aware_fixture
|
||||
tz_didx = date_range("2014-03-01", "2015-01-10", freq="h", tz=tz)
|
||||
naive_didx = date_range("2014-03-01", "2015-01-10", freq="h")
|
||||
|
||||
_compare_utc_to_local(tz_didx)
|
||||
_compare_local_to_utc(tz_didx, naive_didx)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("freq", ["D", "YE"])
|
||||
def test_tz_convert_single_matches_tz_convert(tz_aware_fixture, freq):
|
||||
tz = tz_aware_fixture
|
||||
tz_didx = date_range("2018-01-01", "2020-01-01", freq=freq, tz=tz)
|
||||
naive_didx = date_range("2018-01-01", "2020-01-01", freq=freq)
|
||||
|
||||
_compare_utc_to_local(tz_didx)
|
||||
_compare_local_to_utc(tz_didx, naive_didx)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"arr",
|
||||
[
|
||||
pytest.param(np.array([], dtype=np.int64), id="empty"),
|
||||
pytest.param(np.array([iNaT], dtype=np.int64), id="all_nat"),
|
||||
],
|
||||
)
|
||||
def test_tz_convert_corner(arr):
|
||||
result = tz_convert_from_utc(arr, timezones.maybe_get_tz("Asia/Tokyo"))
|
||||
tm.assert_numpy_array_equal(result, arr)
|
||||
|
||||
|
||||
def test_tz_convert_readonly():
|
||||
# GH#35530
|
||||
arr = np.array([0], dtype=np.int64)
|
||||
arr.setflags(write=False)
|
||||
result = tz_convert_from_utc(arr, UTC)
|
||||
tm.assert_numpy_array_equal(result, arr)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("copy", [True, False])
|
||||
@pytest.mark.parametrize("dtype", ["M8[ns]", "M8[s]"])
|
||||
def test_length_zero_copy(dtype, copy):
|
||||
arr = np.array([], dtype=dtype)
|
||||
result = astype_overflowsafe(arr, copy=copy, dtype=np.dtype("M8[ns]"))
|
||||
if copy:
|
||||
assert not np.shares_memory(result, arr)
|
||||
elif arr.dtype == result.dtype:
|
||||
assert result is arr
|
||||
else:
|
||||
assert not np.shares_memory(result, arr)
|
||||
|
||||
|
||||
def test_ensure_datetime64ns_bigendian():
|
||||
# GH#29684
|
||||
arr = np.array([np.datetime64(1, "ms")], dtype=">M8[ms]")
|
||||
result = astype_overflowsafe(arr, dtype=np.dtype("M8[ns]"))
|
||||
|
||||
expected = np.array([np.datetime64(1, "ms")], dtype="M8[ns]")
|
||||
tm.assert_numpy_array_equal(result, expected)
|
||||
|
||||
|
||||
def test_ensure_timedelta64ns_overflows():
|
||||
arr = np.arange(10).astype("m8[Y]") * 100
|
||||
msg = r"Cannot convert 300 years to timedelta64\[ns\] without overflow"
|
||||
with pytest.raises(OutOfBoundsTimedelta, match=msg):
|
||||
astype_overflowsafe(arr, dtype=np.dtype("m8[ns]"))
|
||||
|
||||
|
||||
class SubDatetime(datetime):
|
||||
pass
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"dt, expected",
|
||||
[
|
||||
pytest.param(
|
||||
Timestamp("2000-01-01"), Timestamp("2000-01-01", tz=UTC), id="timestamp"
|
||||
),
|
||||
pytest.param(
|
||||
datetime(2000, 1, 1), datetime(2000, 1, 1, tzinfo=UTC), id="datetime"
|
||||
),
|
||||
pytest.param(
|
||||
SubDatetime(2000, 1, 1),
|
||||
SubDatetime(2000, 1, 1, tzinfo=UTC),
|
||||
id="subclassed_datetime",
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_localize_pydatetime_dt_types(dt, expected):
|
||||
# GH 25851
|
||||
# ensure that subclassed datetime works with
|
||||
# localize_pydatetime
|
||||
result = conversion.localize_pydatetime(dt, UTC)
|
||||
assert result == expected
|
@ -0,0 +1,40 @@
|
||||
import numpy as np
|
||||
import pytest
|
||||
|
||||
from pandas._libs.tslibs import fields
|
||||
|
||||
import pandas._testing as tm
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def dtindex():
|
||||
dtindex = np.arange(5, dtype=np.int64) * 10**9 * 3600 * 24 * 32
|
||||
dtindex.flags.writeable = False
|
||||
return dtindex
|
||||
|
||||
|
||||
def test_get_date_name_field_readonly(dtindex):
|
||||
# https://github.com/vaexio/vaex/issues/357
|
||||
# fields functions shouldn't raise when we pass read-only data
|
||||
result = fields.get_date_name_field(dtindex, "month_name")
|
||||
expected = np.array(["January", "February", "March", "April", "May"], dtype=object)
|
||||
tm.assert_numpy_array_equal(result, expected)
|
||||
|
||||
|
||||
def test_get_date_field_readonly(dtindex):
|
||||
result = fields.get_date_field(dtindex, "Y")
|
||||
expected = np.array([1970, 1970, 1970, 1970, 1970], dtype=np.int32)
|
||||
tm.assert_numpy_array_equal(result, expected)
|
||||
|
||||
|
||||
def test_get_start_end_field_readonly(dtindex):
|
||||
result = fields.get_start_end_field(dtindex, "is_month_start", None)
|
||||
expected = np.array([True, False, False, False, False], dtype=np.bool_)
|
||||
tm.assert_numpy_array_equal(result, expected)
|
||||
|
||||
|
||||
def test_get_timedelta_field_readonly(dtindex):
|
||||
# treat dtindex as timedeltas for this next one
|
||||
result = fields.get_timedelta_field(dtindex, "seconds")
|
||||
expected = np.array([0] * 5, dtype=np.int32)
|
||||
tm.assert_numpy_array_equal(result, expected)
|
@ -0,0 +1,27 @@
|
||||
import pytest
|
||||
|
||||
from pandas._libs.tslibs.parsing import get_rule_month
|
||||
|
||||
from pandas.tseries import offsets
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"obj,expected",
|
||||
[
|
||||
("W", "DEC"),
|
||||
(offsets.Week().freqstr, "DEC"),
|
||||
("D", "DEC"),
|
||||
(offsets.Day().freqstr, "DEC"),
|
||||
("Q", "DEC"),
|
||||
(offsets.QuarterEnd(startingMonth=12).freqstr, "DEC"),
|
||||
("Q-JAN", "JAN"),
|
||||
(offsets.QuarterEnd(startingMonth=1).freqstr, "JAN"),
|
||||
("Y-DEC", "DEC"),
|
||||
(offsets.YearEnd().freqstr, "DEC"),
|
||||
("Y-MAY", "MAY"),
|
||||
(offsets.YearEnd(month=5).freqstr, "MAY"),
|
||||
],
|
||||
)
|
||||
def test_get_rule_month(obj, expected):
|
||||
result = get_rule_month(obj)
|
||||
assert result == expected
|
@ -0,0 +1,173 @@
|
||||
"""
|
||||
Tests for helper functions in the cython tslibs.offsets
|
||||
"""
|
||||
from datetime import datetime
|
||||
|
||||
import pytest
|
||||
|
||||
from pandas._libs.tslibs.ccalendar import (
|
||||
get_firstbday,
|
||||
get_lastbday,
|
||||
)
|
||||
import pandas._libs.tslibs.offsets as liboffsets
|
||||
from pandas._libs.tslibs.offsets import roll_qtrday
|
||||
|
||||
from pandas import Timestamp
|
||||
|
||||
|
||||
@pytest.fixture(params=["start", "end", "business_start", "business_end"])
|
||||
def day_opt(request):
|
||||
return request.param
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"dt,exp_week_day,exp_last_day",
|
||||
[
|
||||
(datetime(2017, 11, 30), 3, 30), # Business day.
|
||||
(datetime(1993, 10, 31), 6, 29), # Non-business day.
|
||||
],
|
||||
)
|
||||
def test_get_last_bday(dt, exp_week_day, exp_last_day):
|
||||
assert dt.weekday() == exp_week_day
|
||||
assert get_lastbday(dt.year, dt.month) == exp_last_day
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"dt,exp_week_day,exp_first_day",
|
||||
[
|
||||
(datetime(2017, 4, 1), 5, 3), # Non-weekday.
|
||||
(datetime(1993, 10, 1), 4, 1), # Business day.
|
||||
],
|
||||
)
|
||||
def test_get_first_bday(dt, exp_week_day, exp_first_day):
|
||||
assert dt.weekday() == exp_week_day
|
||||
assert get_firstbday(dt.year, dt.month) == exp_first_day
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"months,day_opt,expected",
|
||||
[
|
||||
(0, 15, datetime(2017, 11, 15)),
|
||||
(0, None, datetime(2017, 11, 30)),
|
||||
(1, "start", datetime(2017, 12, 1)),
|
||||
(-145, "end", datetime(2005, 10, 31)),
|
||||
(0, "business_end", datetime(2017, 11, 30)),
|
||||
(0, "business_start", datetime(2017, 11, 1)),
|
||||
],
|
||||
)
|
||||
def test_shift_month_dt(months, day_opt, expected):
|
||||
dt = datetime(2017, 11, 30)
|
||||
assert liboffsets.shift_month(dt, months, day_opt=day_opt) == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"months,day_opt,expected",
|
||||
[
|
||||
(1, "start", Timestamp("1929-06-01")),
|
||||
(-3, "end", Timestamp("1929-02-28")),
|
||||
(25, None, Timestamp("1931-06-5")),
|
||||
(-1, 31, Timestamp("1929-04-30")),
|
||||
],
|
||||
)
|
||||
def test_shift_month_ts(months, day_opt, expected):
|
||||
ts = Timestamp("1929-05-05")
|
||||
assert liboffsets.shift_month(ts, months, day_opt=day_opt) == expected
|
||||
|
||||
|
||||
def test_shift_month_error():
|
||||
dt = datetime(2017, 11, 15)
|
||||
day_opt = "this should raise"
|
||||
|
||||
with pytest.raises(ValueError, match=day_opt):
|
||||
liboffsets.shift_month(dt, 3, day_opt=day_opt)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"other,expected",
|
||||
[
|
||||
# Before March 1.
|
||||
(datetime(2017, 2, 10), {2: 1, -7: -7, 0: 0}),
|
||||
# After March 1.
|
||||
(Timestamp("2014-03-15", tz="US/Eastern"), {2: 2, -7: -6, 0: 1}),
|
||||
],
|
||||
)
|
||||
@pytest.mark.parametrize("n", [2, -7, 0])
|
||||
def test_roll_qtrday_year(other, expected, n):
|
||||
month = 3
|
||||
day_opt = "start" # `other` will be compared to March 1.
|
||||
|
||||
assert roll_qtrday(other, n, month, day_opt, modby=12) == expected[n]
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"other,expected",
|
||||
[
|
||||
# Before June 30.
|
||||
(datetime(1999, 6, 29), {5: 4, -7: -7, 0: 0}),
|
||||
# After June 30.
|
||||
(Timestamp(2072, 8, 24, 6, 17, 18), {5: 5, -7: -6, 0: 1}),
|
||||
],
|
||||
)
|
||||
@pytest.mark.parametrize("n", [5, -7, 0])
|
||||
def test_roll_qtrday_year2(other, expected, n):
|
||||
month = 6
|
||||
day_opt = "end" # `other` will be compared to June 30.
|
||||
|
||||
assert roll_qtrday(other, n, month, day_opt, modby=12) == expected[n]
|
||||
|
||||
|
||||
def test_get_day_of_month_error():
|
||||
# get_day_of_month is not directly exposed.
|
||||
# We test it via roll_qtrday.
|
||||
dt = datetime(2017, 11, 15)
|
||||
day_opt = "foo"
|
||||
|
||||
with pytest.raises(ValueError, match=day_opt):
|
||||
# To hit the raising case we need month == dt.month and n > 0.
|
||||
roll_qtrday(dt, n=3, month=11, day_opt=day_opt, modby=12)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"month",
|
||||
[3, 5], # (other.month % 3) < (month % 3) # (other.month % 3) > (month % 3)
|
||||
)
|
||||
@pytest.mark.parametrize("n", [4, -3])
|
||||
def test_roll_qtr_day_not_mod_unequal(day_opt, month, n):
|
||||
expected = {3: {-3: -2, 4: 4}, 5: {-3: -3, 4: 3}}
|
||||
|
||||
other = Timestamp(2072, 10, 1, 6, 17, 18) # Saturday.
|
||||
assert roll_qtrday(other, n, month, day_opt, modby=3) == expected[month][n]
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"other,month,exp_dict",
|
||||
[
|
||||
# Monday.
|
||||
(datetime(1999, 5, 31), 2, {-1: {"start": 0, "business_start": 0}}),
|
||||
# Saturday.
|
||||
(
|
||||
Timestamp(2072, 10, 1, 6, 17, 18),
|
||||
4,
|
||||
{2: {"end": 1, "business_end": 1, "business_start": 1}},
|
||||
),
|
||||
# First business day.
|
||||
(
|
||||
Timestamp(2072, 10, 3, 6, 17, 18),
|
||||
4,
|
||||
{2: {"end": 1, "business_end": 1}, -1: {"start": 0}},
|
||||
),
|
||||
],
|
||||
)
|
||||
@pytest.mark.parametrize("n", [2, -1])
|
||||
def test_roll_qtr_day_mod_equal(other, month, exp_dict, n, day_opt):
|
||||
# All cases have (other.month % 3) == (month % 3).
|
||||
expected = exp_dict.get(n, {}).get(day_opt, n)
|
||||
assert roll_qtrday(other, n, month, day_opt, modby=3) == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"n,expected", [(42, {29: 42, 1: 42, 31: 41}), (-4, {29: -4, 1: -3, 31: -4})]
|
||||
)
|
||||
@pytest.mark.parametrize("compare", [29, 1, 31])
|
||||
def test_roll_convention(n, expected, compare):
|
||||
assert liboffsets.roll_convention(29, n, compare) == expected[compare]
|
@ -0,0 +1,222 @@
|
||||
import numpy as np
|
||||
import pytest
|
||||
|
||||
from pandas._libs.tslibs.dtypes import NpyDatetimeUnit
|
||||
from pandas._libs.tslibs.np_datetime import (
|
||||
OutOfBoundsDatetime,
|
||||
OutOfBoundsTimedelta,
|
||||
astype_overflowsafe,
|
||||
is_unitless,
|
||||
py_get_unit_from_dtype,
|
||||
py_td64_to_tdstruct,
|
||||
)
|
||||
|
||||
import pandas._testing as tm
|
||||
|
||||
|
||||
def test_is_unitless():
|
||||
dtype = np.dtype("M8[ns]")
|
||||
assert not is_unitless(dtype)
|
||||
|
||||
dtype = np.dtype("datetime64")
|
||||
assert is_unitless(dtype)
|
||||
|
||||
dtype = np.dtype("m8[ns]")
|
||||
assert not is_unitless(dtype)
|
||||
|
||||
dtype = np.dtype("timedelta64")
|
||||
assert is_unitless(dtype)
|
||||
|
||||
msg = "dtype must be datetime64 or timedelta64"
|
||||
with pytest.raises(ValueError, match=msg):
|
||||
is_unitless(np.dtype(np.int64))
|
||||
|
||||
msg = "Argument 'dtype' has incorrect type"
|
||||
with pytest.raises(TypeError, match=msg):
|
||||
is_unitless("foo")
|
||||
|
||||
|
||||
def test_get_unit_from_dtype():
|
||||
# datetime64
|
||||
assert py_get_unit_from_dtype(np.dtype("M8[Y]")) == NpyDatetimeUnit.NPY_FR_Y.value
|
||||
assert py_get_unit_from_dtype(np.dtype("M8[M]")) == NpyDatetimeUnit.NPY_FR_M.value
|
||||
assert py_get_unit_from_dtype(np.dtype("M8[W]")) == NpyDatetimeUnit.NPY_FR_W.value
|
||||
# B has been deprecated and removed -> no 3
|
||||
assert py_get_unit_from_dtype(np.dtype("M8[D]")) == NpyDatetimeUnit.NPY_FR_D.value
|
||||
assert py_get_unit_from_dtype(np.dtype("M8[h]")) == NpyDatetimeUnit.NPY_FR_h.value
|
||||
assert py_get_unit_from_dtype(np.dtype("M8[m]")) == NpyDatetimeUnit.NPY_FR_m.value
|
||||
assert py_get_unit_from_dtype(np.dtype("M8[s]")) == NpyDatetimeUnit.NPY_FR_s.value
|
||||
assert py_get_unit_from_dtype(np.dtype("M8[ms]")) == NpyDatetimeUnit.NPY_FR_ms.value
|
||||
assert py_get_unit_from_dtype(np.dtype("M8[us]")) == NpyDatetimeUnit.NPY_FR_us.value
|
||||
assert py_get_unit_from_dtype(np.dtype("M8[ns]")) == NpyDatetimeUnit.NPY_FR_ns.value
|
||||
assert py_get_unit_from_dtype(np.dtype("M8[ps]")) == NpyDatetimeUnit.NPY_FR_ps.value
|
||||
assert py_get_unit_from_dtype(np.dtype("M8[fs]")) == NpyDatetimeUnit.NPY_FR_fs.value
|
||||
assert py_get_unit_from_dtype(np.dtype("M8[as]")) == NpyDatetimeUnit.NPY_FR_as.value
|
||||
|
||||
# timedelta64
|
||||
assert py_get_unit_from_dtype(np.dtype("m8[Y]")) == NpyDatetimeUnit.NPY_FR_Y.value
|
||||
assert py_get_unit_from_dtype(np.dtype("m8[M]")) == NpyDatetimeUnit.NPY_FR_M.value
|
||||
assert py_get_unit_from_dtype(np.dtype("m8[W]")) == NpyDatetimeUnit.NPY_FR_W.value
|
||||
# B has been deprecated and removed -> no 3
|
||||
assert py_get_unit_from_dtype(np.dtype("m8[D]")) == NpyDatetimeUnit.NPY_FR_D.value
|
||||
assert py_get_unit_from_dtype(np.dtype("m8[h]")) == NpyDatetimeUnit.NPY_FR_h.value
|
||||
assert py_get_unit_from_dtype(np.dtype("m8[m]")) == NpyDatetimeUnit.NPY_FR_m.value
|
||||
assert py_get_unit_from_dtype(np.dtype("m8[s]")) == NpyDatetimeUnit.NPY_FR_s.value
|
||||
assert py_get_unit_from_dtype(np.dtype("m8[ms]")) == NpyDatetimeUnit.NPY_FR_ms.value
|
||||
assert py_get_unit_from_dtype(np.dtype("m8[us]")) == NpyDatetimeUnit.NPY_FR_us.value
|
||||
assert py_get_unit_from_dtype(np.dtype("m8[ns]")) == NpyDatetimeUnit.NPY_FR_ns.value
|
||||
assert py_get_unit_from_dtype(np.dtype("m8[ps]")) == NpyDatetimeUnit.NPY_FR_ps.value
|
||||
assert py_get_unit_from_dtype(np.dtype("m8[fs]")) == NpyDatetimeUnit.NPY_FR_fs.value
|
||||
assert py_get_unit_from_dtype(np.dtype("m8[as]")) == NpyDatetimeUnit.NPY_FR_as.value
|
||||
|
||||
|
||||
def test_td64_to_tdstruct():
|
||||
val = 12454636234 # arbitrary value
|
||||
|
||||
res1 = py_td64_to_tdstruct(val, NpyDatetimeUnit.NPY_FR_ns.value)
|
||||
exp1 = {
|
||||
"days": 0,
|
||||
"hrs": 0,
|
||||
"min": 0,
|
||||
"sec": 12,
|
||||
"ms": 454,
|
||||
"us": 636,
|
||||
"ns": 234,
|
||||
"seconds": 12,
|
||||
"microseconds": 454636,
|
||||
"nanoseconds": 234,
|
||||
}
|
||||
assert res1 == exp1
|
||||
|
||||
res2 = py_td64_to_tdstruct(val, NpyDatetimeUnit.NPY_FR_us.value)
|
||||
exp2 = {
|
||||
"days": 0,
|
||||
"hrs": 3,
|
||||
"min": 27,
|
||||
"sec": 34,
|
||||
"ms": 636,
|
||||
"us": 234,
|
||||
"ns": 0,
|
||||
"seconds": 12454,
|
||||
"microseconds": 636234,
|
||||
"nanoseconds": 0,
|
||||
}
|
||||
assert res2 == exp2
|
||||
|
||||
res3 = py_td64_to_tdstruct(val, NpyDatetimeUnit.NPY_FR_ms.value)
|
||||
exp3 = {
|
||||
"days": 144,
|
||||
"hrs": 3,
|
||||
"min": 37,
|
||||
"sec": 16,
|
||||
"ms": 234,
|
||||
"us": 0,
|
||||
"ns": 0,
|
||||
"seconds": 13036,
|
||||
"microseconds": 234000,
|
||||
"nanoseconds": 0,
|
||||
}
|
||||
assert res3 == exp3
|
||||
|
||||
# Note this out of bounds for nanosecond Timedelta
|
||||
res4 = py_td64_to_tdstruct(val, NpyDatetimeUnit.NPY_FR_s.value)
|
||||
exp4 = {
|
||||
"days": 144150,
|
||||
"hrs": 21,
|
||||
"min": 10,
|
||||
"sec": 34,
|
||||
"ms": 0,
|
||||
"us": 0,
|
||||
"ns": 0,
|
||||
"seconds": 76234,
|
||||
"microseconds": 0,
|
||||
"nanoseconds": 0,
|
||||
}
|
||||
assert res4 == exp4
|
||||
|
||||
|
||||
class TestAstypeOverflowSafe:
|
||||
def test_pass_non_dt64_array(self):
|
||||
# check that we raise, not segfault
|
||||
arr = np.arange(5)
|
||||
dtype = np.dtype("M8[ns]")
|
||||
|
||||
msg = (
|
||||
"astype_overflowsafe values.dtype and dtype must be either "
|
||||
"both-datetime64 or both-timedelta64"
|
||||
)
|
||||
with pytest.raises(TypeError, match=msg):
|
||||
astype_overflowsafe(arr, dtype, copy=True)
|
||||
|
||||
with pytest.raises(TypeError, match=msg):
|
||||
astype_overflowsafe(arr, dtype, copy=False)
|
||||
|
||||
def test_pass_non_dt64_dtype(self):
|
||||
# check that we raise, not segfault
|
||||
arr = np.arange(5, dtype="i8").view("M8[D]")
|
||||
dtype = np.dtype("m8[ns]")
|
||||
|
||||
msg = (
|
||||
"astype_overflowsafe values.dtype and dtype must be either "
|
||||
"both-datetime64 or both-timedelta64"
|
||||
)
|
||||
with pytest.raises(TypeError, match=msg):
|
||||
astype_overflowsafe(arr, dtype, copy=True)
|
||||
|
||||
with pytest.raises(TypeError, match=msg):
|
||||
astype_overflowsafe(arr, dtype, copy=False)
|
||||
|
||||
def test_astype_overflowsafe_dt64(self):
|
||||
dtype = np.dtype("M8[ns]")
|
||||
|
||||
dt = np.datetime64("2262-04-05", "D")
|
||||
arr = dt + np.arange(10, dtype="m8[D]")
|
||||
|
||||
# arr.astype silently overflows, so this
|
||||
wrong = arr.astype(dtype)
|
||||
roundtrip = wrong.astype(arr.dtype)
|
||||
assert not (wrong == roundtrip).all()
|
||||
|
||||
msg = "Out of bounds nanosecond timestamp"
|
||||
with pytest.raises(OutOfBoundsDatetime, match=msg):
|
||||
astype_overflowsafe(arr, dtype)
|
||||
|
||||
# But converting to microseconds is fine, and we match numpy's results.
|
||||
dtype2 = np.dtype("M8[us]")
|
||||
result = astype_overflowsafe(arr, dtype2)
|
||||
expected = arr.astype(dtype2)
|
||||
tm.assert_numpy_array_equal(result, expected)
|
||||
|
||||
def test_astype_overflowsafe_td64(self):
|
||||
dtype = np.dtype("m8[ns]")
|
||||
|
||||
dt = np.datetime64("2262-04-05", "D")
|
||||
arr = dt + np.arange(10, dtype="m8[D]")
|
||||
arr = arr.view("m8[D]")
|
||||
|
||||
# arr.astype silently overflows, so this
|
||||
wrong = arr.astype(dtype)
|
||||
roundtrip = wrong.astype(arr.dtype)
|
||||
assert not (wrong == roundtrip).all()
|
||||
|
||||
msg = r"Cannot convert 106752 days to timedelta64\[ns\] without overflow"
|
||||
with pytest.raises(OutOfBoundsTimedelta, match=msg):
|
||||
astype_overflowsafe(arr, dtype)
|
||||
|
||||
# But converting to microseconds is fine, and we match numpy's results.
|
||||
dtype2 = np.dtype("m8[us]")
|
||||
result = astype_overflowsafe(arr, dtype2)
|
||||
expected = arr.astype(dtype2)
|
||||
tm.assert_numpy_array_equal(result, expected)
|
||||
|
||||
def test_astype_overflowsafe_disallow_rounding(self):
|
||||
arr = np.array([-1500, 1500], dtype="M8[ns]")
|
||||
dtype = np.dtype("M8[us]")
|
||||
|
||||
msg = "Cannot losslessly cast '-1500 ns' to us"
|
||||
with pytest.raises(ValueError, match=msg):
|
||||
astype_overflowsafe(arr, dtype, round_ok=False)
|
||||
|
||||
result = astype_overflowsafe(arr, dtype, round_ok=True)
|
||||
expected = arr.astype(dtype)
|
||||
tm.assert_numpy_array_equal(result, expected)
|
@ -0,0 +1,27 @@
|
||||
import numpy as np
|
||||
|
||||
from pandas._libs.tslibs.dtypes import abbrev_to_npy_unit
|
||||
from pandas._libs.tslibs.vectorized import is_date_array_normalized
|
||||
|
||||
# a datetime64 ndarray which *is* normalized
|
||||
day_arr = np.arange(10, dtype="i8").view("M8[D]")
|
||||
|
||||
|
||||
class TestIsDateArrayNormalized:
|
||||
def test_is_date_array_normalized_day(self):
|
||||
arr = day_arr
|
||||
abbrev = "D"
|
||||
unit = abbrev_to_npy_unit(abbrev)
|
||||
result = is_date_array_normalized(arr.view("i8"), None, unit)
|
||||
assert result is True
|
||||
|
||||
def test_is_date_array_normalized_seconds(self):
|
||||
abbrev = "s"
|
||||
arr = day_arr.astype(f"M8[{abbrev}]")
|
||||
unit = abbrev_to_npy_unit(abbrev)
|
||||
result = is_date_array_normalized(arr.view("i8"), None, unit)
|
||||
assert result is True
|
||||
|
||||
arr[0] += np.timedelta64(1, abbrev)
|
||||
result2 = is_date_array_normalized(arr.view("i8"), None, unit)
|
||||
assert result2 is False
|
@ -0,0 +1,119 @@
|
||||
from datetime import datetime
|
||||
|
||||
import pytest
|
||||
|
||||
from pandas._libs import tslib
|
||||
|
||||
from pandas import Timestamp
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"date_str, exp",
|
||||
[
|
||||
("2011-01-02", datetime(2011, 1, 2)),
|
||||
("2011-1-2", datetime(2011, 1, 2)),
|
||||
("2011-01", datetime(2011, 1, 1)),
|
||||
("2011-1", datetime(2011, 1, 1)),
|
||||
("2011 01 02", datetime(2011, 1, 2)),
|
||||
("2011.01.02", datetime(2011, 1, 2)),
|
||||
("2011/01/02", datetime(2011, 1, 2)),
|
||||
("2011\\01\\02", datetime(2011, 1, 2)),
|
||||
("2013-01-01 05:30:00", datetime(2013, 1, 1, 5, 30)),
|
||||
("2013-1-1 5:30:00", datetime(2013, 1, 1, 5, 30)),
|
||||
("2013-1-1 5:30:00+01:00", Timestamp(2013, 1, 1, 5, 30, tz="UTC+01:00")),
|
||||
],
|
||||
)
|
||||
def test_parsers_iso8601(date_str, exp):
|
||||
# see gh-12060
|
||||
#
|
||||
# Test only the ISO parser - flexibility to
|
||||
# different separators and leading zero's.
|
||||
actual = tslib._test_parse_iso8601(date_str)
|
||||
assert actual == exp
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"date_str",
|
||||
[
|
||||
"2011-01/02",
|
||||
"2011=11=11",
|
||||
"201401",
|
||||
"201111",
|
||||
"200101",
|
||||
# Mixed separated and unseparated.
|
||||
"2005-0101",
|
||||
"200501-01",
|
||||
"20010101 12:3456",
|
||||
"20010101 1234:56",
|
||||
# HHMMSS must have two digits in
|
||||
# each component if unseparated.
|
||||
"20010101 1",
|
||||
"20010101 123",
|
||||
"20010101 12345",
|
||||
"20010101 12345Z",
|
||||
],
|
||||
)
|
||||
def test_parsers_iso8601_invalid(date_str):
|
||||
msg = f'Error parsing datetime string "{date_str}"'
|
||||
|
||||
with pytest.raises(ValueError, match=msg):
|
||||
tslib._test_parse_iso8601(date_str)
|
||||
|
||||
|
||||
def test_parsers_iso8601_invalid_offset_invalid():
|
||||
date_str = "2001-01-01 12-34-56"
|
||||
msg = f'Timezone hours offset out of range in datetime string "{date_str}"'
|
||||
|
||||
with pytest.raises(ValueError, match=msg):
|
||||
tslib._test_parse_iso8601(date_str)
|
||||
|
||||
|
||||
def test_parsers_iso8601_leading_space():
|
||||
# GH#25895 make sure isoparser doesn't overflow with long input
|
||||
date_str, expected = ("2013-1-1 5:30:00", datetime(2013, 1, 1, 5, 30))
|
||||
actual = tslib._test_parse_iso8601(" " * 200 + date_str)
|
||||
assert actual == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"date_str, timespec, exp",
|
||||
[
|
||||
("2023-01-01 00:00:00", "auto", "2023-01-01T00:00:00"),
|
||||
("2023-01-01 00:00:00", "seconds", "2023-01-01T00:00:00"),
|
||||
("2023-01-01 00:00:00", "milliseconds", "2023-01-01T00:00:00.000"),
|
||||
("2023-01-01 00:00:00", "microseconds", "2023-01-01T00:00:00.000000"),
|
||||
("2023-01-01 00:00:00", "nanoseconds", "2023-01-01T00:00:00.000000000"),
|
||||
("2023-01-01 00:00:00.001", "auto", "2023-01-01T00:00:00.001000"),
|
||||
("2023-01-01 00:00:00.001", "seconds", "2023-01-01T00:00:00"),
|
||||
("2023-01-01 00:00:00.001", "milliseconds", "2023-01-01T00:00:00.001"),
|
||||
("2023-01-01 00:00:00.001", "microseconds", "2023-01-01T00:00:00.001000"),
|
||||
("2023-01-01 00:00:00.001", "nanoseconds", "2023-01-01T00:00:00.001000000"),
|
||||
("2023-01-01 00:00:00.000001", "auto", "2023-01-01T00:00:00.000001"),
|
||||
("2023-01-01 00:00:00.000001", "seconds", "2023-01-01T00:00:00"),
|
||||
("2023-01-01 00:00:00.000001", "milliseconds", "2023-01-01T00:00:00.000"),
|
||||
("2023-01-01 00:00:00.000001", "microseconds", "2023-01-01T00:00:00.000001"),
|
||||
("2023-01-01 00:00:00.000001", "nanoseconds", "2023-01-01T00:00:00.000001000"),
|
||||
("2023-01-01 00:00:00.000000001", "auto", "2023-01-01T00:00:00.000000001"),
|
||||
("2023-01-01 00:00:00.000000001", "seconds", "2023-01-01T00:00:00"),
|
||||
("2023-01-01 00:00:00.000000001", "milliseconds", "2023-01-01T00:00:00.000"),
|
||||
("2023-01-01 00:00:00.000000001", "microseconds", "2023-01-01T00:00:00.000000"),
|
||||
(
|
||||
"2023-01-01 00:00:00.000000001",
|
||||
"nanoseconds",
|
||||
"2023-01-01T00:00:00.000000001",
|
||||
),
|
||||
("2023-01-01 00:00:00.000001001", "auto", "2023-01-01T00:00:00.000001001"),
|
||||
("2023-01-01 00:00:00.000001001", "seconds", "2023-01-01T00:00:00"),
|
||||
("2023-01-01 00:00:00.000001001", "milliseconds", "2023-01-01T00:00:00.000"),
|
||||
("2023-01-01 00:00:00.000001001", "microseconds", "2023-01-01T00:00:00.000001"),
|
||||
(
|
||||
"2023-01-01 00:00:00.000001001",
|
||||
"nanoseconds",
|
||||
"2023-01-01T00:00:00.000001001",
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_iso8601_formatter(date_str: str, timespec: str, exp: str):
|
||||
# GH#53020
|
||||
ts = Timestamp(date_str)
|
||||
assert ts.isoformat(timespec=timespec) == exp
|
414
lib/python3.13/site-packages/pandas/tests/tslibs/test_parsing.py
Normal file
414
lib/python3.13/site-packages/pandas/tests/tslibs/test_parsing.py
Normal file
@ -0,0 +1,414 @@
|
||||
"""
|
||||
Tests for Timestamp parsing, aimed at pandas/_libs/tslibs/parsing.pyx
|
||||
"""
|
||||
from datetime import datetime
|
||||
import re
|
||||
|
||||
from dateutil.parser import parse as du_parse
|
||||
from dateutil.tz import tzlocal
|
||||
from hypothesis import given
|
||||
import numpy as np
|
||||
import pytest
|
||||
|
||||
from pandas._libs.tslibs import (
|
||||
parsing,
|
||||
strptime,
|
||||
)
|
||||
from pandas._libs.tslibs.parsing import parse_datetime_string_with_reso
|
||||
from pandas.compat import (
|
||||
ISMUSL,
|
||||
is_platform_windows,
|
||||
)
|
||||
import pandas.util._test_decorators as td
|
||||
|
||||
import pandas._testing as tm
|
||||
from pandas._testing._hypothesis import DATETIME_NO_TZ
|
||||
|
||||
|
||||
@pytest.mark.skipif(
|
||||
is_platform_windows() or ISMUSL,
|
||||
reason="TZ setting incorrect on Windows and MUSL Linux",
|
||||
)
|
||||
def test_parsing_tzlocal_deprecated():
|
||||
# GH#50791
|
||||
msg = (
|
||||
"Parsing 'EST' as tzlocal.*"
|
||||
"Pass the 'tz' keyword or call tz_localize after construction instead"
|
||||
)
|
||||
dtstr = "Jan 15 2004 03:00 EST"
|
||||
|
||||
with tm.set_timezone("US/Eastern"):
|
||||
with tm.assert_produces_warning(FutureWarning, match=msg):
|
||||
res, _ = parse_datetime_string_with_reso(dtstr)
|
||||
|
||||
assert isinstance(res.tzinfo, tzlocal)
|
||||
|
||||
with tm.assert_produces_warning(FutureWarning, match=msg):
|
||||
res = parsing.py_parse_datetime_string(dtstr)
|
||||
assert isinstance(res.tzinfo, tzlocal)
|
||||
|
||||
|
||||
def test_parse_datetime_string_with_reso():
|
||||
(parsed, reso) = parse_datetime_string_with_reso("4Q1984")
|
||||
(parsed_lower, reso_lower) = parse_datetime_string_with_reso("4q1984")
|
||||
|
||||
assert reso == reso_lower
|
||||
assert parsed == parsed_lower
|
||||
|
||||
|
||||
def test_parse_datetime_string_with_reso_nanosecond_reso():
|
||||
# GH#46811
|
||||
parsed, reso = parse_datetime_string_with_reso("2022-04-20 09:19:19.123456789")
|
||||
assert reso == "nanosecond"
|
||||
|
||||
|
||||
def test_parse_datetime_string_with_reso_invalid_type():
|
||||
# Raise on invalid input, don't just return it
|
||||
msg = "Argument 'date_string' has incorrect type (expected str, got tuple)"
|
||||
with pytest.raises(TypeError, match=re.escape(msg)):
|
||||
parse_datetime_string_with_reso((4, 5))
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"dashed,normal", [("1988-Q2", "1988Q2"), ("2Q-1988", "2Q1988")]
|
||||
)
|
||||
def test_parse_time_quarter_with_dash(dashed, normal):
|
||||
# see gh-9688
|
||||
(parsed_dash, reso_dash) = parse_datetime_string_with_reso(dashed)
|
||||
(parsed, reso) = parse_datetime_string_with_reso(normal)
|
||||
|
||||
assert parsed_dash == parsed
|
||||
assert reso_dash == reso
|
||||
|
||||
|
||||
@pytest.mark.parametrize("dashed", ["-2Q1992", "2-Q1992", "4-4Q1992"])
|
||||
def test_parse_time_quarter_with_dash_error(dashed):
|
||||
msg = f"Unknown datetime string format, unable to parse: {dashed}"
|
||||
|
||||
with pytest.raises(parsing.DateParseError, match=msg):
|
||||
parse_datetime_string_with_reso(dashed)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"date_string,expected",
|
||||
[
|
||||
("123.1234", False),
|
||||
("-50000", False),
|
||||
("999", False),
|
||||
("m", False),
|
||||
("T", False),
|
||||
("Mon Sep 16, 2013", True),
|
||||
("2012-01-01", True),
|
||||
("01/01/2012", True),
|
||||
("01012012", True),
|
||||
("0101", True),
|
||||
("1-1", True),
|
||||
],
|
||||
)
|
||||
def test_does_not_convert_mixed_integer(date_string, expected):
|
||||
assert parsing._does_string_look_like_datetime(date_string) is expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"date_str,kwargs,msg",
|
||||
[
|
||||
(
|
||||
"2013Q5",
|
||||
{},
|
||||
(
|
||||
"Incorrect quarterly string is given, "
|
||||
"quarter must be between 1 and 4: 2013Q5"
|
||||
),
|
||||
),
|
||||
# see gh-5418
|
||||
(
|
||||
"2013Q1",
|
||||
{"freq": "INVLD-L-DEC-SAT"},
|
||||
(
|
||||
"Unable to retrieve month information "
|
||||
"from given freq: INVLD-L-DEC-SAT"
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_parsers_quarterly_with_freq_error(date_str, kwargs, msg):
|
||||
with pytest.raises(parsing.DateParseError, match=msg):
|
||||
parsing.parse_datetime_string_with_reso(date_str, **kwargs)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"date_str,freq,expected",
|
||||
[
|
||||
("2013Q2", None, datetime(2013, 4, 1)),
|
||||
("2013Q2", "Y-APR", datetime(2012, 8, 1)),
|
||||
("2013-Q2", "Y-DEC", datetime(2013, 4, 1)),
|
||||
],
|
||||
)
|
||||
def test_parsers_quarterly_with_freq(date_str, freq, expected):
|
||||
result, _ = parsing.parse_datetime_string_with_reso(date_str, freq=freq)
|
||||
assert result == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"date_str", ["2Q 2005", "2Q-200Y", "2Q-200", "22Q2005", "2Q200.", "6Q-20"]
|
||||
)
|
||||
def test_parsers_quarter_invalid(date_str):
|
||||
if date_str == "6Q-20":
|
||||
msg = (
|
||||
"Incorrect quarterly string is given, quarter "
|
||||
f"must be between 1 and 4: {date_str}"
|
||||
)
|
||||
else:
|
||||
msg = f"Unknown datetime string format, unable to parse: {date_str}"
|
||||
|
||||
with pytest.raises(ValueError, match=msg):
|
||||
parsing.parse_datetime_string_with_reso(date_str)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"date_str,expected",
|
||||
[("201101", datetime(2011, 1, 1, 0, 0)), ("200005", datetime(2000, 5, 1, 0, 0))],
|
||||
)
|
||||
def test_parsers_month_freq(date_str, expected):
|
||||
result, _ = parsing.parse_datetime_string_with_reso(date_str, freq="ME")
|
||||
assert result == expected
|
||||
|
||||
|
||||
@td.skip_if_not_us_locale
|
||||
@pytest.mark.parametrize(
|
||||
"string,fmt",
|
||||
[
|
||||
("20111230", "%Y%m%d"),
|
||||
("201112300000", "%Y%m%d%H%M"),
|
||||
("20111230000000", "%Y%m%d%H%M%S"),
|
||||
("20111230T00", "%Y%m%dT%H"),
|
||||
("20111230T0000", "%Y%m%dT%H%M"),
|
||||
("20111230T000000", "%Y%m%dT%H%M%S"),
|
||||
("2011-12-30", "%Y-%m-%d"),
|
||||
("2011", "%Y"),
|
||||
("2011-01", "%Y-%m"),
|
||||
("30-12-2011", "%d-%m-%Y"),
|
||||
("2011-12-30 00:00:00", "%Y-%m-%d %H:%M:%S"),
|
||||
("2011-12-30T00:00:00", "%Y-%m-%dT%H:%M:%S"),
|
||||
("2011-12-30T00:00:00UTC", "%Y-%m-%dT%H:%M:%S%Z"),
|
||||
("2011-12-30T00:00:00Z", "%Y-%m-%dT%H:%M:%S%z"),
|
||||
("2011-12-30T00:00:00+9", "%Y-%m-%dT%H:%M:%S%z"),
|
||||
("2011-12-30T00:00:00+09", "%Y-%m-%dT%H:%M:%S%z"),
|
||||
("2011-12-30T00:00:00+090", None),
|
||||
("2011-12-30T00:00:00+0900", "%Y-%m-%dT%H:%M:%S%z"),
|
||||
("2011-12-30T00:00:00-0900", "%Y-%m-%dT%H:%M:%S%z"),
|
||||
("2011-12-30T00:00:00+09:00", "%Y-%m-%dT%H:%M:%S%z"),
|
||||
("2011-12-30T00:00:00+09:000", None),
|
||||
("2011-12-30T00:00:00+9:0", "%Y-%m-%dT%H:%M:%S%z"),
|
||||
("2011-12-30T00:00:00+09:", None),
|
||||
("2011-12-30T00:00:00.000000UTC", "%Y-%m-%dT%H:%M:%S.%f%Z"),
|
||||
("2011-12-30T00:00:00.000000Z", "%Y-%m-%dT%H:%M:%S.%f%z"),
|
||||
("2011-12-30T00:00:00.000000+9", "%Y-%m-%dT%H:%M:%S.%f%z"),
|
||||
("2011-12-30T00:00:00.000000+09", "%Y-%m-%dT%H:%M:%S.%f%z"),
|
||||
("2011-12-30T00:00:00.000000+090", None),
|
||||
("2011-12-30T00:00:00.000000+0900", "%Y-%m-%dT%H:%M:%S.%f%z"),
|
||||
("2011-12-30T00:00:00.000000-0900", "%Y-%m-%dT%H:%M:%S.%f%z"),
|
||||
("2011-12-30T00:00:00.000000+09:00", "%Y-%m-%dT%H:%M:%S.%f%z"),
|
||||
("2011-12-30T00:00:00.000000+09:000", None),
|
||||
("2011-12-30T00:00:00.000000+9:0", "%Y-%m-%dT%H:%M:%S.%f%z"),
|
||||
("2011-12-30T00:00:00.000000+09:", None),
|
||||
("2011-12-30 00:00:00.000000", "%Y-%m-%d %H:%M:%S.%f"),
|
||||
("Tue 24 Aug 2021 01:30:48", "%a %d %b %Y %H:%M:%S"),
|
||||
("Tuesday 24 Aug 2021 01:30:48", "%A %d %b %Y %H:%M:%S"),
|
||||
("Tue 24 Aug 2021 01:30:48 AM", "%a %d %b %Y %I:%M:%S %p"),
|
||||
("Tuesday 24 Aug 2021 01:30:48 AM", "%A %d %b %Y %I:%M:%S %p"),
|
||||
("27.03.2003 14:55:00.000", "%d.%m.%Y %H:%M:%S.%f"), # GH50317
|
||||
],
|
||||
)
|
||||
def test_guess_datetime_format_with_parseable_formats(string, fmt):
|
||||
with tm.maybe_produces_warning(
|
||||
UserWarning, fmt is not None and re.search(r"%d.*%m", fmt)
|
||||
):
|
||||
result = parsing.guess_datetime_format(string)
|
||||
assert result == fmt
|
||||
|
||||
|
||||
@pytest.mark.parametrize("dayfirst,expected", [(True, "%d/%m/%Y"), (False, "%m/%d/%Y")])
|
||||
def test_guess_datetime_format_with_dayfirst(dayfirst, expected):
|
||||
ambiguous_string = "01/01/2011"
|
||||
result = parsing.guess_datetime_format(ambiguous_string, dayfirst=dayfirst)
|
||||
assert result == expected
|
||||
|
||||
|
||||
@td.skip_if_not_us_locale
|
||||
@pytest.mark.parametrize(
|
||||
"string,fmt",
|
||||
[
|
||||
("30/Dec/2011", "%d/%b/%Y"),
|
||||
("30/December/2011", "%d/%B/%Y"),
|
||||
("30/Dec/2011 00:00:00", "%d/%b/%Y %H:%M:%S"),
|
||||
],
|
||||
)
|
||||
def test_guess_datetime_format_with_locale_specific_formats(string, fmt):
|
||||
result = parsing.guess_datetime_format(string)
|
||||
assert result == fmt
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"invalid_dt",
|
||||
[
|
||||
"01/2013",
|
||||
"12:00:00",
|
||||
"1/1/1/1",
|
||||
"this_is_not_a_datetime",
|
||||
"51a",
|
||||
"13/2019",
|
||||
"202001", # YYYYMM isn't ISO8601
|
||||
"2020/01", # YYYY/MM isn't ISO8601 either
|
||||
"87156549591102612381000001219H5",
|
||||
],
|
||||
)
|
||||
def test_guess_datetime_format_invalid_inputs(invalid_dt):
|
||||
# A datetime string must include a year, month and a day for it to be
|
||||
# guessable, in addition to being a string that looks like a datetime.
|
||||
assert parsing.guess_datetime_format(invalid_dt) is None
|
||||
|
||||
|
||||
@pytest.mark.parametrize("invalid_type_dt", [9, datetime(2011, 1, 1)])
|
||||
def test_guess_datetime_format_wrong_type_inputs(invalid_type_dt):
|
||||
# A datetime string must include a year, month and a day for it to be
|
||||
# guessable, in addition to being a string that looks like a datetime.
|
||||
with pytest.raises(
|
||||
TypeError,
|
||||
match=r"^Argument 'dt_str' has incorrect type \(expected str, got .*\)$",
|
||||
):
|
||||
parsing.guess_datetime_format(invalid_type_dt)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"string,fmt,dayfirst,warning",
|
||||
[
|
||||
("2011-1-1", "%Y-%m-%d", False, None),
|
||||
("2011-1-1", "%Y-%d-%m", True, None),
|
||||
("1/1/2011", "%m/%d/%Y", False, None),
|
||||
("1/1/2011", "%d/%m/%Y", True, None),
|
||||
("30-1-2011", "%d-%m-%Y", False, UserWarning),
|
||||
("30-1-2011", "%d-%m-%Y", True, None),
|
||||
("2011-1-1 0:0:0", "%Y-%m-%d %H:%M:%S", False, None),
|
||||
("2011-1-1 0:0:0", "%Y-%d-%m %H:%M:%S", True, None),
|
||||
("2011-1-3T00:00:0", "%Y-%m-%dT%H:%M:%S", False, None),
|
||||
("2011-1-3T00:00:0", "%Y-%d-%mT%H:%M:%S", True, None),
|
||||
("2011-1-1 00:00:00", "%Y-%m-%d %H:%M:%S", False, None),
|
||||
("2011-1-1 00:00:00", "%Y-%d-%m %H:%M:%S", True, None),
|
||||
],
|
||||
)
|
||||
def test_guess_datetime_format_no_padding(string, fmt, dayfirst, warning):
|
||||
# see gh-11142
|
||||
msg = (
|
||||
rf"Parsing dates in {fmt} format when dayfirst=False \(the default\) "
|
||||
"was specified. "
|
||||
"Pass `dayfirst=True` or specify a format to silence this warning."
|
||||
)
|
||||
with tm.assert_produces_warning(warning, match=msg):
|
||||
result = parsing.guess_datetime_format(string, dayfirst=dayfirst)
|
||||
assert result == fmt
|
||||
|
||||
|
||||
def test_try_parse_dates():
|
||||
arr = np.array(["5/1/2000", "6/1/2000", "7/1/2000"], dtype=object)
|
||||
result = parsing.try_parse_dates(arr, parser=lambda x: du_parse(x, dayfirst=True))
|
||||
|
||||
expected = np.array([du_parse(d, dayfirst=True) for d in arr])
|
||||
tm.assert_numpy_array_equal(result, expected)
|
||||
|
||||
|
||||
def test_parse_datetime_string_with_reso_check_instance_type_raise_exception():
|
||||
# issue 20684
|
||||
msg = "Argument 'date_string' has incorrect type (expected str, got tuple)"
|
||||
with pytest.raises(TypeError, match=re.escape(msg)):
|
||||
parse_datetime_string_with_reso((1, 2, 3))
|
||||
|
||||
result = parse_datetime_string_with_reso("2019")
|
||||
expected = (datetime(2019, 1, 1), "year")
|
||||
assert result == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"fmt,expected",
|
||||
[
|
||||
("%Y %m %d %H:%M:%S", True),
|
||||
("%Y/%m/%d %H:%M:%S", True),
|
||||
(r"%Y\%m\%d %H:%M:%S", True),
|
||||
("%Y-%m-%d %H:%M:%S", True),
|
||||
("%Y.%m.%d %H:%M:%S", True),
|
||||
("%Y%m%d %H:%M:%S", True),
|
||||
("%Y-%m-%dT%H:%M:%S", True),
|
||||
("%Y-%m-%dT%H:%M:%S%z", True),
|
||||
("%Y-%m-%dT%H:%M:%S%Z", False),
|
||||
("%Y-%m-%dT%H:%M:%S.%f", True),
|
||||
("%Y-%m-%dT%H:%M:%S.%f%z", True),
|
||||
("%Y-%m-%dT%H:%M:%S.%f%Z", False),
|
||||
("%Y%m%d", True),
|
||||
("%Y%m", False),
|
||||
("%Y", True),
|
||||
("%Y-%m-%d", True),
|
||||
("%Y-%m", True),
|
||||
],
|
||||
)
|
||||
def test_is_iso_format(fmt, expected):
|
||||
# see gh-41047
|
||||
result = strptime._test_format_is_iso(fmt)
|
||||
assert result == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"input",
|
||||
[
|
||||
"2018-01-01T00:00:00.123456789",
|
||||
"2018-01-01T00:00:00.123456",
|
||||
"2018-01-01T00:00:00.123",
|
||||
],
|
||||
)
|
||||
def test_guess_datetime_format_f(input):
|
||||
# https://github.com/pandas-dev/pandas/issues/49043
|
||||
result = parsing.guess_datetime_format(input)
|
||||
expected = "%Y-%m-%dT%H:%M:%S.%f"
|
||||
assert result == expected
|
||||
|
||||
|
||||
def _helper_hypothesis_delimited_date(call, date_string, **kwargs):
|
||||
msg, result = None, None
|
||||
try:
|
||||
result = call(date_string, **kwargs)
|
||||
except ValueError as err:
|
||||
msg = str(err)
|
||||
return msg, result
|
||||
|
||||
|
||||
@given(DATETIME_NO_TZ)
|
||||
@pytest.mark.parametrize("delimiter", list(" -./"))
|
||||
@pytest.mark.parametrize("dayfirst", [True, False])
|
||||
@pytest.mark.parametrize(
|
||||
"date_format",
|
||||
["%d %m %Y", "%m %d %Y", "%m %Y", "%Y %m %d", "%y %m %d", "%Y%m%d", "%y%m%d"],
|
||||
)
|
||||
def test_hypothesis_delimited_date(
|
||||
request, date_format, dayfirst, delimiter, test_datetime
|
||||
):
|
||||
if date_format == "%m %Y" and delimiter == ".":
|
||||
request.applymarker(
|
||||
pytest.mark.xfail(
|
||||
reason="parse_datetime_string cannot reliably tell whether "
|
||||
"e.g. %m.%Y is a float or a date"
|
||||
)
|
||||
)
|
||||
date_string = test_datetime.strftime(date_format.replace(" ", delimiter))
|
||||
|
||||
except_out_dateutil, result = _helper_hypothesis_delimited_date(
|
||||
parsing.py_parse_datetime_string, date_string, dayfirst=dayfirst
|
||||
)
|
||||
except_in_dateutil, expected = _helper_hypothesis_delimited_date(
|
||||
du_parse,
|
||||
date_string,
|
||||
default=datetime(1, 1, 1),
|
||||
dayfirst=dayfirst,
|
||||
yearfirst=False,
|
||||
)
|
||||
|
||||
assert except_out_dateutil == except_in_dateutil
|
||||
assert result == expected
|
123
lib/python3.13/site-packages/pandas/tests/tslibs/test_period.py
Normal file
123
lib/python3.13/site-packages/pandas/tests/tslibs/test_period.py
Normal file
@ -0,0 +1,123 @@
|
||||
import numpy as np
|
||||
import pytest
|
||||
|
||||
from pandas._libs.tslibs import (
|
||||
iNaT,
|
||||
to_offset,
|
||||
)
|
||||
from pandas._libs.tslibs.period import (
|
||||
extract_ordinals,
|
||||
get_period_field_arr,
|
||||
period_asfreq,
|
||||
period_ordinal,
|
||||
)
|
||||
|
||||
import pandas._testing as tm
|
||||
|
||||
|
||||
def get_freq_code(freqstr: str) -> int:
|
||||
off = to_offset(freqstr, is_period=True)
|
||||
# error: "BaseOffset" has no attribute "_period_dtype_code"
|
||||
code = off._period_dtype_code # type: ignore[attr-defined]
|
||||
return code
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"freq1,freq2,expected",
|
||||
[
|
||||
("D", "h", 24),
|
||||
("D", "min", 1440),
|
||||
("D", "s", 86400),
|
||||
("D", "ms", 86400000),
|
||||
("D", "us", 86400000000),
|
||||
("D", "ns", 86400000000000),
|
||||
("h", "min", 60),
|
||||
("h", "s", 3600),
|
||||
("h", "ms", 3600000),
|
||||
("h", "us", 3600000000),
|
||||
("h", "ns", 3600000000000),
|
||||
("min", "s", 60),
|
||||
("min", "ms", 60000),
|
||||
("min", "us", 60000000),
|
||||
("min", "ns", 60000000000),
|
||||
("s", "ms", 1000),
|
||||
("s", "us", 1000000),
|
||||
("s", "ns", 1000000000),
|
||||
("ms", "us", 1000),
|
||||
("ms", "ns", 1000000),
|
||||
("us", "ns", 1000),
|
||||
],
|
||||
)
|
||||
def test_intra_day_conversion_factors(freq1, freq2, expected):
|
||||
assert (
|
||||
period_asfreq(1, get_freq_code(freq1), get_freq_code(freq2), False) == expected
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"freq,expected", [("Y", 0), ("M", 0), ("W", 1), ("D", 0), ("B", 0)]
|
||||
)
|
||||
def test_period_ordinal_start_values(freq, expected):
|
||||
# information for Jan. 1, 1970.
|
||||
assert period_ordinal(1970, 1, 1, 0, 0, 0, 0, 0, get_freq_code(freq)) == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"dt,expected",
|
||||
[
|
||||
((1970, 1, 4, 0, 0, 0, 0, 0), 1),
|
||||
((1970, 1, 5, 0, 0, 0, 0, 0), 2),
|
||||
((2013, 10, 6, 0, 0, 0, 0, 0), 2284),
|
||||
((2013, 10, 7, 0, 0, 0, 0, 0), 2285),
|
||||
],
|
||||
)
|
||||
def test_period_ordinal_week(dt, expected):
|
||||
args = dt + (get_freq_code("W"),)
|
||||
assert period_ordinal(*args) == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"day,expected",
|
||||
[
|
||||
# Thursday (Oct. 3, 2013).
|
||||
(3, 11415),
|
||||
# Friday (Oct. 4, 2013).
|
||||
(4, 11416),
|
||||
# Saturday (Oct. 5, 2013).
|
||||
(5, 11417),
|
||||
# Sunday (Oct. 6, 2013).
|
||||
(6, 11417),
|
||||
# Monday (Oct. 7, 2013).
|
||||
(7, 11417),
|
||||
# Tuesday (Oct. 8, 2013).
|
||||
(8, 11418),
|
||||
],
|
||||
)
|
||||
def test_period_ordinal_business_day(day, expected):
|
||||
# 5000 is PeriodDtypeCode for BusinessDay
|
||||
args = (2013, 10, day, 0, 0, 0, 0, 0, 5000)
|
||||
assert period_ordinal(*args) == expected
|
||||
|
||||
|
||||
class TestExtractOrdinals:
|
||||
def test_extract_ordinals_raises(self):
|
||||
# with non-object, make sure we raise TypeError, not segfault
|
||||
arr = np.arange(5)
|
||||
freq = to_offset("D")
|
||||
with pytest.raises(TypeError, match="values must be object-dtype"):
|
||||
extract_ordinals(arr, freq)
|
||||
|
||||
def test_extract_ordinals_2d(self):
|
||||
freq = to_offset("D")
|
||||
arr = np.empty(10, dtype=object)
|
||||
arr[:] = iNaT
|
||||
|
||||
res = extract_ordinals(arr, freq)
|
||||
res2 = extract_ordinals(arr.reshape(5, 2), freq)
|
||||
tm.assert_numpy_array_equal(res, res2.reshape(-1))
|
||||
|
||||
|
||||
def test_get_period_field_array_raises_on_out_of_range():
|
||||
msg = "Buffer dtype mismatch, expected 'const int64_t' but got 'double'"
|
||||
with pytest.raises(ValueError, match=msg):
|
||||
get_period_field_arr(-1, np.empty(1), 0)
|
@ -0,0 +1,57 @@
|
||||
import numpy as np
|
||||
import pytest
|
||||
import pytz
|
||||
|
||||
from pandas._libs.tslibs import (
|
||||
Resolution,
|
||||
get_resolution,
|
||||
)
|
||||
from pandas._libs.tslibs.dtypes import NpyDatetimeUnit
|
||||
|
||||
import pandas._testing as tm
|
||||
|
||||
|
||||
def test_get_resolution_nano():
|
||||
# don't return the fallback RESO_DAY
|
||||
arr = np.array([1], dtype=np.int64)
|
||||
res = get_resolution(arr)
|
||||
assert res == Resolution.RESO_NS
|
||||
|
||||
|
||||
def test_get_resolution_non_nano_data():
|
||||
arr = np.array([1], dtype=np.int64)
|
||||
res = get_resolution(arr, None, NpyDatetimeUnit.NPY_FR_us.value)
|
||||
assert res == Resolution.RESO_US
|
||||
|
||||
res = get_resolution(arr, pytz.UTC, NpyDatetimeUnit.NPY_FR_us.value)
|
||||
assert res == Resolution.RESO_US
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"freqstr,expected",
|
||||
[
|
||||
("Y", "year"),
|
||||
("Q", "quarter"),
|
||||
("M", "month"),
|
||||
("D", "day"),
|
||||
("h", "hour"),
|
||||
("min", "minute"),
|
||||
("s", "second"),
|
||||
("ms", "millisecond"),
|
||||
("us", "microsecond"),
|
||||
("ns", "nanosecond"),
|
||||
],
|
||||
)
|
||||
def test_get_attrname_from_abbrev(freqstr, expected):
|
||||
reso = Resolution.get_reso_from_freqstr(freqstr)
|
||||
assert reso.attr_abbrev == freqstr
|
||||
assert reso.attrname == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize("freq", ["A", "H", "T", "S", "L", "U", "N"])
|
||||
def test_units_A_H_T_S_L_U_N_deprecated_from_attrname_to_abbrevs(freq):
|
||||
# GH#52536
|
||||
msg = f"'{freq}' is deprecated and will be removed in a future version."
|
||||
|
||||
with tm.assert_produces_warning(FutureWarning, match=msg):
|
||||
Resolution.get_reso_from_freqstr(freq)
|
@ -0,0 +1,110 @@
|
||||
from datetime import (
|
||||
datetime,
|
||||
timezone,
|
||||
)
|
||||
|
||||
import numpy as np
|
||||
import pytest
|
||||
|
||||
from pandas._libs.tslibs.dtypes import NpyDatetimeUnit
|
||||
from pandas._libs.tslibs.strptime import array_strptime
|
||||
|
||||
from pandas import (
|
||||
NaT,
|
||||
Timestamp,
|
||||
)
|
||||
import pandas._testing as tm
|
||||
|
||||
creso_infer = NpyDatetimeUnit.NPY_FR_GENERIC.value
|
||||
|
||||
|
||||
class TestArrayStrptimeResolutionInference:
|
||||
def test_array_strptime_resolution_all_nat(self):
|
||||
arr = np.array([NaT, np.nan], dtype=object)
|
||||
|
||||
fmt = "%Y-%m-%d %H:%M:%S"
|
||||
res, _ = array_strptime(arr, fmt=fmt, utc=False, creso=creso_infer)
|
||||
assert res.dtype == "M8[s]"
|
||||
|
||||
res, _ = array_strptime(arr, fmt=fmt, utc=True, creso=creso_infer)
|
||||
assert res.dtype == "M8[s]"
|
||||
|
||||
@pytest.mark.parametrize("tz", [None, timezone.utc])
|
||||
def test_array_strptime_resolution_inference_homogeneous_strings(self, tz):
|
||||
dt = datetime(2016, 1, 2, 3, 4, 5, 678900, tzinfo=tz)
|
||||
|
||||
fmt = "%Y-%m-%d %H:%M:%S"
|
||||
dtstr = dt.strftime(fmt)
|
||||
arr = np.array([dtstr] * 3, dtype=object)
|
||||
expected = np.array([dt.replace(tzinfo=None)] * 3, dtype="M8[s]")
|
||||
|
||||
res, _ = array_strptime(arr, fmt=fmt, utc=False, creso=creso_infer)
|
||||
tm.assert_numpy_array_equal(res, expected)
|
||||
|
||||
fmt = "%Y-%m-%d %H:%M:%S.%f"
|
||||
dtstr = dt.strftime(fmt)
|
||||
arr = np.array([dtstr] * 3, dtype=object)
|
||||
expected = np.array([dt.replace(tzinfo=None)] * 3, dtype="M8[us]")
|
||||
|
||||
res, _ = array_strptime(arr, fmt=fmt, utc=False, creso=creso_infer)
|
||||
tm.assert_numpy_array_equal(res, expected)
|
||||
|
||||
fmt = "ISO8601"
|
||||
res, _ = array_strptime(arr, fmt=fmt, utc=False, creso=creso_infer)
|
||||
tm.assert_numpy_array_equal(res, expected)
|
||||
|
||||
@pytest.mark.parametrize("tz", [None, timezone.utc])
|
||||
def test_array_strptime_resolution_mixed(self, tz):
|
||||
dt = datetime(2016, 1, 2, 3, 4, 5, 678900, tzinfo=tz)
|
||||
|
||||
ts = Timestamp(dt).as_unit("ns")
|
||||
|
||||
arr = np.array([dt, ts], dtype=object)
|
||||
expected = np.array(
|
||||
[Timestamp(dt).as_unit("ns").asm8, ts.asm8],
|
||||
dtype="M8[ns]",
|
||||
)
|
||||
|
||||
fmt = "%Y-%m-%d %H:%M:%S"
|
||||
res, _ = array_strptime(arr, fmt=fmt, utc=False, creso=creso_infer)
|
||||
tm.assert_numpy_array_equal(res, expected)
|
||||
|
||||
fmt = "ISO8601"
|
||||
res, _ = array_strptime(arr, fmt=fmt, utc=False, creso=creso_infer)
|
||||
tm.assert_numpy_array_equal(res, expected)
|
||||
|
||||
def test_array_strptime_resolution_todaynow(self):
|
||||
# specifically case where today/now is the *first* item
|
||||
vals = np.array(["today", np.datetime64("2017-01-01", "us")], dtype=object)
|
||||
|
||||
now = Timestamp("now").asm8
|
||||
res, _ = array_strptime(vals, fmt="%Y-%m-%d", utc=False, creso=creso_infer)
|
||||
res2, _ = array_strptime(
|
||||
vals[::-1], fmt="%Y-%m-%d", utc=False, creso=creso_infer
|
||||
)
|
||||
|
||||
# 1s is an arbitrary cutoff for call overhead; in local testing the
|
||||
# actual difference is about 250us
|
||||
tolerance = np.timedelta64(1, "s")
|
||||
|
||||
assert res.dtype == "M8[us]"
|
||||
assert abs(res[0] - now) < tolerance
|
||||
assert res[1] == vals[1]
|
||||
|
||||
assert res2.dtype == "M8[us]"
|
||||
assert abs(res2[1] - now) < tolerance * 2
|
||||
assert res2[0] == vals[1]
|
||||
|
||||
def test_array_strptime_str_outside_nano_range(self):
|
||||
vals = np.array(["2401-09-15"], dtype=object)
|
||||
expected = np.array(["2401-09-15"], dtype="M8[s]")
|
||||
fmt = "ISO8601"
|
||||
res, _ = array_strptime(vals, fmt=fmt, creso=creso_infer)
|
||||
tm.assert_numpy_array_equal(res, expected)
|
||||
|
||||
# non-iso -> different path
|
||||
vals2 = np.array(["Sep 15, 2401"], dtype=object)
|
||||
expected2 = np.array(["2401-09-15"], dtype="M8[s]")
|
||||
fmt2 = "%b %d, %Y"
|
||||
res2, _ = array_strptime(vals2, fmt=fmt2, creso=creso_infer)
|
||||
tm.assert_numpy_array_equal(res2, expected2)
|
@ -0,0 +1,149 @@
|
||||
import re
|
||||
|
||||
import numpy as np
|
||||
import pytest
|
||||
|
||||
from pandas._libs.tslibs.timedeltas import (
|
||||
array_to_timedelta64,
|
||||
delta_to_nanoseconds,
|
||||
ints_to_pytimedelta,
|
||||
)
|
||||
|
||||
from pandas import (
|
||||
Timedelta,
|
||||
offsets,
|
||||
)
|
||||
import pandas._testing as tm
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"obj,expected",
|
||||
[
|
||||
(np.timedelta64(14, "D"), 14 * 24 * 3600 * 1e9),
|
||||
(Timedelta(minutes=-7), -7 * 60 * 1e9),
|
||||
(Timedelta(minutes=-7).to_pytimedelta(), -7 * 60 * 1e9),
|
||||
(Timedelta(seconds=1234e-9), 1234), # GH43764, GH40946
|
||||
(
|
||||
Timedelta(seconds=1e-9, milliseconds=1e-5, microseconds=1e-1),
|
||||
111,
|
||||
), # GH43764
|
||||
(
|
||||
Timedelta(days=1, seconds=1e-9, milliseconds=1e-5, microseconds=1e-1),
|
||||
24 * 3600e9 + 111,
|
||||
), # GH43764
|
||||
(offsets.Nano(125), 125),
|
||||
],
|
||||
)
|
||||
def test_delta_to_nanoseconds(obj, expected):
|
||||
result = delta_to_nanoseconds(obj)
|
||||
assert result == expected
|
||||
|
||||
|
||||
def test_delta_to_nanoseconds_error():
|
||||
obj = np.array([123456789], dtype="m8[ns]")
|
||||
|
||||
with pytest.raises(TypeError, match="<class 'numpy.ndarray'>"):
|
||||
delta_to_nanoseconds(obj)
|
||||
|
||||
with pytest.raises(TypeError, match="float"):
|
||||
delta_to_nanoseconds(1.5)
|
||||
with pytest.raises(TypeError, match="int"):
|
||||
delta_to_nanoseconds(1)
|
||||
with pytest.raises(TypeError, match="int"):
|
||||
delta_to_nanoseconds(np.int64(2))
|
||||
with pytest.raises(TypeError, match="int"):
|
||||
delta_to_nanoseconds(np.int32(3))
|
||||
|
||||
|
||||
def test_delta_to_nanoseconds_td64_MY_raises():
|
||||
msg = (
|
||||
"delta_to_nanoseconds does not support Y or M units, "
|
||||
"as their duration in nanoseconds is ambiguous"
|
||||
)
|
||||
|
||||
td = np.timedelta64(1234, "Y")
|
||||
|
||||
with pytest.raises(ValueError, match=msg):
|
||||
delta_to_nanoseconds(td)
|
||||
|
||||
td = np.timedelta64(1234, "M")
|
||||
|
||||
with pytest.raises(ValueError, match=msg):
|
||||
delta_to_nanoseconds(td)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("unit", ["Y", "M"])
|
||||
def test_unsupported_td64_unit_raises(unit):
|
||||
# GH 52806
|
||||
with pytest.raises(
|
||||
ValueError,
|
||||
match=f"Unit {unit} is not supported. "
|
||||
"Only unambiguous timedelta values durations are supported. "
|
||||
"Allowed units are 'W', 'D', 'h', 'm', 's', 'ms', 'us', 'ns'",
|
||||
):
|
||||
Timedelta(np.timedelta64(1, unit))
|
||||
|
||||
|
||||
def test_huge_nanoseconds_overflow():
|
||||
# GH 32402
|
||||
assert delta_to_nanoseconds(Timedelta(1e10)) == 1e10
|
||||
assert delta_to_nanoseconds(Timedelta(nanoseconds=1e10)) == 1e10
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"kwargs", [{"Seconds": 1}, {"seconds": 1, "Nanoseconds": 1}, {"Foo": 2}]
|
||||
)
|
||||
def test_kwarg_assertion(kwargs):
|
||||
err_message = (
|
||||
"cannot construct a Timedelta from the passed arguments, "
|
||||
"allowed keywords are "
|
||||
"[weeks, days, hours, minutes, seconds, "
|
||||
"milliseconds, microseconds, nanoseconds]"
|
||||
)
|
||||
|
||||
with pytest.raises(ValueError, match=re.escape(err_message)):
|
||||
Timedelta(**kwargs)
|
||||
|
||||
|
||||
class TestArrayToTimedelta64:
|
||||
def test_array_to_timedelta64_string_with_unit_2d_raises(self):
|
||||
# check the 'unit is not None and errors != "coerce"' path
|
||||
# in array_to_timedelta64 raises correctly with 2D values
|
||||
values = np.array([["1", 2], [3, "4"]], dtype=object)
|
||||
with pytest.raises(ValueError, match="unit must not be specified"):
|
||||
array_to_timedelta64(values, unit="s")
|
||||
|
||||
def test_array_to_timedelta64_non_object_raises(self):
|
||||
# check we raise, not segfault
|
||||
values = np.arange(5)
|
||||
|
||||
msg = "'values' must have object dtype"
|
||||
with pytest.raises(TypeError, match=msg):
|
||||
array_to_timedelta64(values)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("unit", ["s", "ms", "us"])
|
||||
def test_ints_to_pytimedelta(unit):
|
||||
# tests for non-nanosecond cases
|
||||
arr = np.arange(6, dtype=np.int64).view(f"m8[{unit}]")
|
||||
|
||||
res = ints_to_pytimedelta(arr, box=False)
|
||||
# For non-nanosecond, .astype(object) gives pytimedelta objects
|
||||
# instead of integers
|
||||
expected = arr.astype(object)
|
||||
tm.assert_numpy_array_equal(res, expected)
|
||||
|
||||
res = ints_to_pytimedelta(arr, box=True)
|
||||
expected = np.array([Timedelta(x) for x in arr], dtype=object)
|
||||
tm.assert_numpy_array_equal(res, expected)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("unit", ["Y", "M", "ps", "fs", "as"])
|
||||
def test_ints_to_pytimedelta_unsupported(unit):
|
||||
arr = np.arange(6, dtype=np.int64).view(f"m8[{unit}]")
|
||||
|
||||
with pytest.raises(NotImplementedError, match=r"\d{1,2}"):
|
||||
ints_to_pytimedelta(arr, box=False)
|
||||
msg = "Only resolutions 's', 'ms', 'us', 'ns' are supported"
|
||||
with pytest.raises(NotImplementedError, match=msg):
|
||||
ints_to_pytimedelta(arr, box=True)
|
@ -0,0 +1,168 @@
|
||||
from datetime import (
|
||||
datetime,
|
||||
timedelta,
|
||||
timezone,
|
||||
)
|
||||
|
||||
import dateutil.tz
|
||||
import pytest
|
||||
import pytz
|
||||
|
||||
from pandas._libs.tslibs import (
|
||||
conversion,
|
||||
timezones,
|
||||
)
|
||||
from pandas.compat import is_platform_windows
|
||||
|
||||
from pandas import Timestamp
|
||||
|
||||
|
||||
def test_is_utc(utc_fixture):
|
||||
tz = timezones.maybe_get_tz(utc_fixture)
|
||||
assert timezones.is_utc(tz)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("tz_name", list(pytz.common_timezones))
|
||||
def test_cache_keys_are_distinct_for_pytz_vs_dateutil(tz_name):
|
||||
tz_p = timezones.maybe_get_tz(tz_name)
|
||||
tz_d = timezones.maybe_get_tz("dateutil/" + tz_name)
|
||||
|
||||
if tz_d is None:
|
||||
pytest.skip(tz_name + ": dateutil does not know about this one")
|
||||
|
||||
if not (tz_name == "UTC" and is_platform_windows()):
|
||||
# they both end up as tzwin("UTC") on windows
|
||||
assert timezones._p_tz_cache_key(tz_p) != timezones._p_tz_cache_key(tz_d)
|
||||
|
||||
|
||||
def test_tzlocal_repr():
|
||||
# see gh-13583
|
||||
ts = Timestamp("2011-01-01", tz=dateutil.tz.tzlocal())
|
||||
assert ts.tz == dateutil.tz.tzlocal()
|
||||
assert "tz='tzlocal()')" in repr(ts)
|
||||
|
||||
|
||||
def test_tzlocal_maybe_get_tz():
|
||||
# see gh-13583
|
||||
tz = timezones.maybe_get_tz("tzlocal()")
|
||||
assert tz == dateutil.tz.tzlocal()
|
||||
|
||||
|
||||
def test_tzlocal_offset():
|
||||
# see gh-13583
|
||||
#
|
||||
# Get offset using normal datetime for test.
|
||||
ts = Timestamp("2011-01-01", tz=dateutil.tz.tzlocal())
|
||||
|
||||
offset = dateutil.tz.tzlocal().utcoffset(datetime(2011, 1, 1))
|
||||
offset = offset.total_seconds()
|
||||
|
||||
assert ts._value + offset == Timestamp("2011-01-01")._value
|
||||
|
||||
|
||||
def test_tzlocal_is_not_utc():
|
||||
# even if the machine running the test is localized to UTC
|
||||
tz = dateutil.tz.tzlocal()
|
||||
assert not timezones.is_utc(tz)
|
||||
|
||||
assert not timezones.tz_compare(tz, dateutil.tz.tzutc())
|
||||
|
||||
|
||||
def test_tz_compare_utc(utc_fixture, utc_fixture2):
|
||||
tz = timezones.maybe_get_tz(utc_fixture)
|
||||
tz2 = timezones.maybe_get_tz(utc_fixture2)
|
||||
assert timezones.tz_compare(tz, tz2)
|
||||
|
||||
|
||||
@pytest.fixture(
|
||||
params=[
|
||||
(pytz.timezone("US/Eastern"), lambda tz, x: tz.localize(x)),
|
||||
(dateutil.tz.gettz("US/Eastern"), lambda tz, x: x.replace(tzinfo=tz)),
|
||||
]
|
||||
)
|
||||
def infer_setup(request):
|
||||
eastern, localize = request.param
|
||||
|
||||
start_naive = datetime(2001, 1, 1)
|
||||
end_naive = datetime(2009, 1, 1)
|
||||
|
||||
start = localize(eastern, start_naive)
|
||||
end = localize(eastern, end_naive)
|
||||
|
||||
return eastern, localize, start, end, start_naive, end_naive
|
||||
|
||||
|
||||
def test_infer_tz_compat(infer_setup):
|
||||
eastern, _, start, end, start_naive, end_naive = infer_setup
|
||||
|
||||
assert (
|
||||
timezones.infer_tzinfo(start, end)
|
||||
is conversion.localize_pydatetime(start_naive, eastern).tzinfo
|
||||
)
|
||||
assert (
|
||||
timezones.infer_tzinfo(start, None)
|
||||
is conversion.localize_pydatetime(start_naive, eastern).tzinfo
|
||||
)
|
||||
assert (
|
||||
timezones.infer_tzinfo(None, end)
|
||||
is conversion.localize_pydatetime(end_naive, eastern).tzinfo
|
||||
)
|
||||
|
||||
|
||||
def test_infer_tz_utc_localize(infer_setup):
|
||||
_, _, start, end, start_naive, end_naive = infer_setup
|
||||
utc = pytz.utc
|
||||
|
||||
start = utc.localize(start_naive)
|
||||
end = utc.localize(end_naive)
|
||||
|
||||
assert timezones.infer_tzinfo(start, end) is utc
|
||||
|
||||
|
||||
@pytest.mark.parametrize("ordered", [True, False])
|
||||
def test_infer_tz_mismatch(infer_setup, ordered):
|
||||
eastern, _, _, _, start_naive, end_naive = infer_setup
|
||||
msg = "Inputs must both have the same timezone"
|
||||
|
||||
utc = pytz.utc
|
||||
start = utc.localize(start_naive)
|
||||
end = conversion.localize_pydatetime(end_naive, eastern)
|
||||
|
||||
args = (start, end) if ordered else (end, start)
|
||||
|
||||
with pytest.raises(AssertionError, match=msg):
|
||||
timezones.infer_tzinfo(*args)
|
||||
|
||||
|
||||
def test_maybe_get_tz_invalid_types():
|
||||
with pytest.raises(TypeError, match="<class 'float'>"):
|
||||
timezones.maybe_get_tz(44.0)
|
||||
|
||||
with pytest.raises(TypeError, match="<class 'module'>"):
|
||||
timezones.maybe_get_tz(pytz)
|
||||
|
||||
msg = "<class 'pandas._libs.tslibs.timestamps.Timestamp'>"
|
||||
with pytest.raises(TypeError, match=msg):
|
||||
timezones.maybe_get_tz(Timestamp("2021-01-01", tz="UTC"))
|
||||
|
||||
|
||||
def test_maybe_get_tz_offset_only():
|
||||
# see gh-36004
|
||||
|
||||
# timezone.utc
|
||||
tz = timezones.maybe_get_tz(timezone.utc)
|
||||
assert tz == timezone(timedelta(hours=0, minutes=0))
|
||||
|
||||
# without UTC+- prefix
|
||||
tz = timezones.maybe_get_tz("+01:15")
|
||||
assert tz == timezone(timedelta(hours=1, minutes=15))
|
||||
|
||||
tz = timezones.maybe_get_tz("-01:15")
|
||||
assert tz == timezone(-timedelta(hours=1, minutes=15))
|
||||
|
||||
# with UTC+- prefix
|
||||
tz = timezones.maybe_get_tz("UTC+02:45")
|
||||
assert tz == timezone(timedelta(hours=2, minutes=45))
|
||||
|
||||
tz = timezones.maybe_get_tz("UTC-02:45")
|
||||
assert tz == timezone(-timedelta(hours=2, minutes=45))
|
@ -0,0 +1,219 @@
|
||||
import re
|
||||
|
||||
import pytest
|
||||
|
||||
from pandas._libs.tslibs import (
|
||||
Timedelta,
|
||||
offsets,
|
||||
to_offset,
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"freq_input,expected",
|
||||
[
|
||||
(to_offset("10us"), offsets.Micro(10)),
|
||||
(offsets.Hour(), offsets.Hour()),
|
||||
("2h30min", offsets.Minute(150)),
|
||||
("2h 30min", offsets.Minute(150)),
|
||||
("2h30min15s", offsets.Second(150 * 60 + 15)),
|
||||
("2h 60min", offsets.Hour(3)),
|
||||
("2h 20.5min", offsets.Second(8430)),
|
||||
("1.5min", offsets.Second(90)),
|
||||
("0.5s", offsets.Milli(500)),
|
||||
("15ms500us", offsets.Micro(15500)),
|
||||
("10s75ms", offsets.Milli(10075)),
|
||||
("1s0.25ms", offsets.Micro(1000250)),
|
||||
("1s0.25ms", offsets.Micro(1000250)),
|
||||
("2800ns", offsets.Nano(2800)),
|
||||
("2SME", offsets.SemiMonthEnd(2)),
|
||||
("2SME-16", offsets.SemiMonthEnd(2, day_of_month=16)),
|
||||
("2SMS-14", offsets.SemiMonthBegin(2, day_of_month=14)),
|
||||
("2SMS-15", offsets.SemiMonthBegin(2)),
|
||||
],
|
||||
)
|
||||
def test_to_offset(freq_input, expected):
|
||||
result = to_offset(freq_input)
|
||||
assert result == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"freqstr,expected", [("-1s", -1), ("-2SME", -2), ("-1SMS", -1), ("-5min10s", -310)]
|
||||
)
|
||||
def test_to_offset_negative(freqstr, expected):
|
||||
result = to_offset(freqstr)
|
||||
assert result.n == expected
|
||||
|
||||
|
||||
@pytest.mark.filterwarnings("ignore:.*'m' is deprecated.*:FutureWarning")
|
||||
@pytest.mark.parametrize(
|
||||
"freqstr",
|
||||
[
|
||||
"2h20m",
|
||||
"us1",
|
||||
"-us",
|
||||
"3us1",
|
||||
"-2-3us",
|
||||
"-2D:3h",
|
||||
"1.5.0s",
|
||||
"2SMS-15-15",
|
||||
"2SMS-15D",
|
||||
"100foo",
|
||||
# Invalid leading +/- signs.
|
||||
"+-1d",
|
||||
"-+1h",
|
||||
"+1",
|
||||
"-7",
|
||||
"+d",
|
||||
"-m",
|
||||
# Invalid shortcut anchors.
|
||||
"SME-0",
|
||||
"SME-28",
|
||||
"SME-29",
|
||||
"SME-FOO",
|
||||
"BSM",
|
||||
"SME--1",
|
||||
"SMS-1",
|
||||
"SMS-28",
|
||||
"SMS-30",
|
||||
"SMS-BAR",
|
||||
"SMS-BYR",
|
||||
"BSMS",
|
||||
"SMS--2",
|
||||
],
|
||||
)
|
||||
def test_to_offset_invalid(freqstr):
|
||||
# see gh-13930
|
||||
|
||||
# We escape string because some of our
|
||||
# inputs contain regex special characters.
|
||||
msg = re.escape(f"Invalid frequency: {freqstr}")
|
||||
with pytest.raises(ValueError, match=msg):
|
||||
to_offset(freqstr)
|
||||
|
||||
|
||||
def test_to_offset_no_evaluate():
|
||||
msg = str(("", ""))
|
||||
with pytest.raises(TypeError, match=msg):
|
||||
to_offset(("", ""))
|
||||
|
||||
|
||||
def test_to_offset_tuple_unsupported():
|
||||
with pytest.raises(TypeError, match="pass as a string instead"):
|
||||
to_offset((5, "T"))
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"freqstr,expected",
|
||||
[
|
||||
("2D 3h", offsets.Hour(51)),
|
||||
("2 D3 h", offsets.Hour(51)),
|
||||
("2 D 3 h", offsets.Hour(51)),
|
||||
(" 2 D 3 h ", offsets.Hour(51)),
|
||||
(" h ", offsets.Hour()),
|
||||
(" 3 h ", offsets.Hour(3)),
|
||||
],
|
||||
)
|
||||
def test_to_offset_whitespace(freqstr, expected):
|
||||
result = to_offset(freqstr)
|
||||
assert result == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"freqstr,expected", [("00h 00min 01s", 1), ("-00h 03min 14s", -194)]
|
||||
)
|
||||
def test_to_offset_leading_zero(freqstr, expected):
|
||||
result = to_offset(freqstr)
|
||||
assert result.n == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize("freqstr,expected", [("+1d", 1), ("+2h30min", 150)])
|
||||
def test_to_offset_leading_plus(freqstr, expected):
|
||||
result = to_offset(freqstr)
|
||||
assert result.n == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"kwargs,expected",
|
||||
[
|
||||
({"days": 1, "seconds": 1}, offsets.Second(86401)),
|
||||
({"days": -1, "seconds": 1}, offsets.Second(-86399)),
|
||||
({"hours": 1, "minutes": 10}, offsets.Minute(70)),
|
||||
({"hours": 1, "minutes": -10}, offsets.Minute(50)),
|
||||
({"weeks": 1}, offsets.Day(7)),
|
||||
({"hours": 1}, offsets.Hour(1)),
|
||||
({"hours": 1}, to_offset("60min")),
|
||||
({"microseconds": 1}, offsets.Micro(1)),
|
||||
({"microseconds": 0}, offsets.Nano(0)),
|
||||
],
|
||||
)
|
||||
def test_to_offset_pd_timedelta(kwargs, expected):
|
||||
# see gh-9064
|
||||
td = Timedelta(**kwargs)
|
||||
result = to_offset(td)
|
||||
assert result == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"shortcut,expected",
|
||||
[
|
||||
("W", offsets.Week(weekday=6)),
|
||||
("W-SUN", offsets.Week(weekday=6)),
|
||||
("QE", offsets.QuarterEnd(startingMonth=12)),
|
||||
("QE-DEC", offsets.QuarterEnd(startingMonth=12)),
|
||||
("QE-MAY", offsets.QuarterEnd(startingMonth=5)),
|
||||
("SME", offsets.SemiMonthEnd(day_of_month=15)),
|
||||
("SME-15", offsets.SemiMonthEnd(day_of_month=15)),
|
||||
("SME-1", offsets.SemiMonthEnd(day_of_month=1)),
|
||||
("SME-27", offsets.SemiMonthEnd(day_of_month=27)),
|
||||
("SMS-2", offsets.SemiMonthBegin(day_of_month=2)),
|
||||
("SMS-27", offsets.SemiMonthBegin(day_of_month=27)),
|
||||
],
|
||||
)
|
||||
def test_anchored_shortcuts(shortcut, expected):
|
||||
result = to_offset(shortcut)
|
||||
assert result == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"freq_depr",
|
||||
[
|
||||
"2ye-mar",
|
||||
"2ys",
|
||||
"2qe",
|
||||
"2qs-feb",
|
||||
"2bqs",
|
||||
"2sms",
|
||||
"2bms",
|
||||
"2cbme",
|
||||
"2me",
|
||||
"2w",
|
||||
],
|
||||
)
|
||||
def test_to_offset_lowercase_frequency_deprecated(freq_depr):
|
||||
# GH#54939
|
||||
depr_msg = f"'{freq_depr[1:]}' is deprecated and will be removed in a "
|
||||
f"future version, please use '{freq_depr.upper()[1:]}' instead."
|
||||
|
||||
with pytest.raises(FutureWarning, match=depr_msg):
|
||||
to_offset(freq_depr)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"freq_depr",
|
||||
[
|
||||
"2H",
|
||||
"2BH",
|
||||
"2MIN",
|
||||
"2S",
|
||||
"2Us",
|
||||
"2NS",
|
||||
],
|
||||
)
|
||||
def test_to_offset_uppercase_frequency_deprecated(freq_depr):
|
||||
# GH#54939
|
||||
depr_msg = f"'{freq_depr[1:]}' is deprecated and will be removed in a "
|
||||
f"future version, please use '{freq_depr.lower()[1:]}' instead."
|
||||
|
||||
with pytest.raises(FutureWarning, match=depr_msg):
|
||||
to_offset(freq_depr)
|
@ -0,0 +1,23 @@
|
||||
import numpy as np
|
||||
import pytest
|
||||
import pytz
|
||||
|
||||
from pandas._libs.tslibs.tzconversion import tz_localize_to_utc
|
||||
|
||||
|
||||
class TestTZLocalizeToUTC:
|
||||
def test_tz_localize_to_utc_ambiguous_infer(self):
|
||||
# val is a timestamp that is ambiguous when localized to US/Eastern
|
||||
val = 1_320_541_200_000_000_000
|
||||
vals = np.array([val, val - 1, val], dtype=np.int64)
|
||||
|
||||
with pytest.raises(pytz.AmbiguousTimeError, match="2011-11-06 01:00:00"):
|
||||
tz_localize_to_utc(vals, pytz.timezone("US/Eastern"), ambiguous="infer")
|
||||
|
||||
with pytest.raises(pytz.AmbiguousTimeError, match="are no repeated times"):
|
||||
tz_localize_to_utc(vals[:1], pytz.timezone("US/Eastern"), ambiguous="infer")
|
||||
|
||||
vals[1] += 1
|
||||
msg = "There are 2 dst switches when there should only be 1"
|
||||
with pytest.raises(pytz.AmbiguousTimeError, match=msg):
|
||||
tz_localize_to_utc(vals, pytz.timezone("US/Eastern"), ambiguous="infer")
|
Reference in New Issue
Block a user