venv
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -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
|
@ -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
|
@ -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