Updated script that can be controled by Nodejs web app

This commit is contained in:
mac OS
2024-11-25 12:24:18 +07:00
parent c440eda1f4
commit 8b0ab2bd3a
8662 changed files with 1803808 additions and 34 deletions

View 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

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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]

View File

@ -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)

View File

@ -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

View File

@ -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

View 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

View 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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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))

View File

@ -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)

View File

@ -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")