first commit
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.
@@ -0,0 +1,56 @@
|
||||
"""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_single",
|
||||
"to_offset",
|
||||
"tz_compare",
|
||||
]
|
||||
|
||||
expected = set(submodules + api)
|
||||
names = [x for x in dir(tslibs) if not x.startswith("__")]
|
||||
assert set(names) == expected
|
||||
@@ -0,0 +1,200 @@
|
||||
from datetime import (
|
||||
date,
|
||||
datetime,
|
||||
)
|
||||
|
||||
from dateutil.tz.tz import tzoffset
|
||||
import numpy as np
|
||||
import pytest
|
||||
import pytz
|
||||
|
||||
from pandas._libs import (
|
||||
iNaT,
|
||||
tslib,
|
||||
)
|
||||
|
||||
from pandas import Timestamp
|
||||
import pandas._testing as tm
|
||||
|
||||
|
||||
@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 is pytz.FixedOffset(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)
|
||||
|
||||
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 pytz.FixedOffset(0)
|
||||
|
||||
|
||||
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)
|
||||
|
||||
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"
|
||||
|
||||
with pytest.raises(ValueError, 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"
|
||||
|
||||
with pytest.raises(tslib.OutOfBoundsDatetime, match=msg):
|
||||
tslib.array_to_datetime(arr)
|
||||
|
||||
|
||||
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.randint(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,141 @@
|
||||
from datetime import datetime
|
||||
|
||||
import numpy as np
|
||||
import pytest
|
||||
from pytz import UTC
|
||||
|
||||
from pandas._libs.tslibs import (
|
||||
OutOfBoundsTimedelta,
|
||||
conversion,
|
||||
iNaT,
|
||||
timezones,
|
||||
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 = tzconversion.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_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", "A"])
|
||||
def test_tz_convert_single_matches_tz_convert(tz_aware_fixture, freq):
|
||||
tz = tz_aware_fixture
|
||||
tz_didx = date_range("2000-01-01", "2020-01-01", freq=freq, tz=tz)
|
||||
naive_didx = date_range("2000-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 = tzconversion.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 = tzconversion.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 = conversion.ensure_datetime64ns(arr, copy=copy)
|
||||
assert result.base is (None if copy else arr)
|
||||
|
||||
|
||||
def test_ensure_datetime64ns_bigendian():
|
||||
# GH#29684
|
||||
arr = np.array([np.datetime64(1, "ms")], dtype=">M8[ms]")
|
||||
result = conversion.ensure_datetime64ns(arr)
|
||||
|
||||
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"Out of bounds for nanosecond timedelta64\[Y\] 900"
|
||||
with pytest.raises(OutOfBoundsTimedelta, match=msg):
|
||||
conversion.ensure_timedelta64ns(arr)
|
||||
|
||||
|
||||
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, "days")
|
||||
expected = np.arange(5, dtype=np.int32) * 32
|
||||
tm.assert_numpy_array_equal(result, expected)
|
||||
@@ -0,0 +1,29 @@
|
||||
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"),
|
||||
("A-DEC", "DEC"),
|
||||
("Y-DEC", "DEC"),
|
||||
(offsets.YearEnd().freqstr, "DEC"),
|
||||
("A-MAY", "MAY"),
|
||||
("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,72 @@
|
||||
from datetime import datetime
|
||||
|
||||
import pytest
|
||||
|
||||
from pandas._libs import tslib
|
||||
|
||||
|
||||
@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)),
|
||||
],
|
||||
)
|
||||
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
|
||||
@@ -0,0 +1,280 @@
|
||||
"""
|
||||
Tests for Timestamp parsing, aimed at pandas/_libs/tslibs/parsing.pyx
|
||||
"""
|
||||
from datetime import datetime
|
||||
import re
|
||||
|
||||
from dateutil.parser import parse
|
||||
import numpy as np
|
||||
import pytest
|
||||
|
||||
from pandas._libs.tslibs import parsing
|
||||
from pandas._libs.tslibs.parsing import parse_time_string
|
||||
import pandas.util._test_decorators as td
|
||||
|
||||
import pandas._testing as tm
|
||||
|
||||
|
||||
def test_parse_time_string():
|
||||
(parsed, reso) = parse_time_string("4Q1984")
|
||||
(parsed_lower, reso_lower) = parse_time_string("4q1984")
|
||||
|
||||
assert reso == reso_lower
|
||||
assert parsed == parsed_lower
|
||||
|
||||
|
||||
def test_parse_time_string_invalid_type():
|
||||
# Raise on invalid input, don't just return it
|
||||
msg = "Argument 'arg' has incorrect type (expected str, got tuple)"
|
||||
with pytest.raises(TypeError, match=re.escape(msg)):
|
||||
parse_time_string((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_time_string(dashed)
|
||||
(parsed, reso) = parse_time_string(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_time_string(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_time_string(date_str, **kwargs)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"date_str,freq,expected",
|
||||
[
|
||||
("2013Q2", None, datetime(2013, 4, 1)),
|
||||
("2013Q2", "A-APR", datetime(2012, 8, 1)),
|
||||
("2013-Q2", "A-DEC", datetime(2013, 4, 1)),
|
||||
],
|
||||
)
|
||||
def test_parsers_quarterly_with_freq(date_str, freq, expected):
|
||||
result, _ = parsing.parse_time_string(date_str, freq=freq)
|
||||
assert result == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"date_str", ["2Q 2005", "2Q-200A", "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_time_string(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_time_string(date_str, freq="M")
|
||||
assert result == expected
|
||||
|
||||
|
||||
@td.skip_if_not_us_locale
|
||||
@pytest.mark.parametrize(
|
||||
"string,fmt",
|
||||
[
|
||||
("20111230", "%Y%m%d"),
|
||||
("2011-12-30", "%Y-%m-%d"),
|
||||
("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", "%Y-%m-%dT%H:%M:%S%z"),
|
||||
("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", "%Y-%m-%dT%H:%M:%S.%f%z"),
|
||||
("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 AM", "%a %d %b %Y %H:%M:%S %p"),
|
||||
("Tuesday 24 Aug 2021 01:30:48 AM", "%A %d %b %Y %H:%M:%S %p"),
|
||||
],
|
||||
)
|
||||
def test_guess_datetime_format_with_parseable_formats(string, 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_has_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",
|
||||
[
|
||||
"2013",
|
||||
"01/2013",
|
||||
"12:00:00",
|
||||
"1/1/1/1",
|
||||
"this_is_not_a_datetime",
|
||||
"51a",
|
||||
9,
|
||||
datetime(2011, 1, 1),
|
||||
],
|
||||
)
|
||||
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(
|
||||
"string,fmt",
|
||||
[
|
||||
("2011-1-1", "%Y-%m-%d"),
|
||||
("1/1/2011", "%m/%d/%Y"),
|
||||
("30-1-2011", "%d-%m-%Y"),
|
||||
("2011-1-1 0:0:0", "%Y-%m-%d %H:%M:%S"),
|
||||
("2011-1-3T00:00:0", "%Y-%m-%dT%H:%M:%S"),
|
||||
("2011-1-1 00:00:00", "%Y-%m-%d %H:%M:%S"),
|
||||
],
|
||||
)
|
||||
def test_guess_datetime_format_no_padding(string, fmt):
|
||||
# see gh-11142
|
||||
result = parsing.guess_datetime_format(string)
|
||||
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, dayfirst=True)
|
||||
|
||||
expected = np.array([parse(d, dayfirst=True) for d in arr])
|
||||
tm.assert_numpy_array_equal(result, expected)
|
||||
|
||||
|
||||
def test_parse_time_string_check_instance_type_raise_exception():
|
||||
# issue 20684
|
||||
msg = "Argument 'arg' has incorrect type (expected str, got tuple)"
|
||||
with pytest.raises(TypeError, match=re.escape(msg)):
|
||||
parse_time_string((1, 2, 3))
|
||||
|
||||
result = parse_time_string("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", True),
|
||||
("%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", True),
|
||||
("%Y%m%d", False),
|
||||
("%Y%m", False),
|
||||
("%Y", False),
|
||||
("%Y-%m-%d", True),
|
||||
("%Y-%m", True),
|
||||
],
|
||||
)
|
||||
def test_is_iso_format(fmt, expected):
|
||||
# see gh-41047
|
||||
result = parsing.format_is_iso(fmt)
|
||||
assert result == expected
|
||||
@@ -0,0 +1,90 @@
|
||||
import pytest
|
||||
|
||||
from pandas._libs.tslibs import to_offset
|
||||
from pandas._libs.tslibs.period import (
|
||||
period_asfreq,
|
||||
period_ordinal,
|
||||
)
|
||||
|
||||
|
||||
def get_freq_code(freqstr: str) -> int:
|
||||
off = to_offset(freqstr)
|
||||
code = off._period_dtype_code
|
||||
return code
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"freq1,freq2,expected",
|
||||
[
|
||||
("D", "H", 24),
|
||||
("D", "T", 1440),
|
||||
("D", "S", 86400),
|
||||
("D", "L", 86400000),
|
||||
("D", "U", 86400000000),
|
||||
("D", "N", 86400000000000),
|
||||
("H", "T", 60),
|
||||
("H", "S", 3600),
|
||||
("H", "L", 3600000),
|
||||
("H", "U", 3600000000),
|
||||
("H", "N", 3600000000000),
|
||||
("T", "S", 60),
|
||||
("T", "L", 60000),
|
||||
("T", "U", 60000000),
|
||||
("T", "N", 60000000000),
|
||||
("S", "L", 1000),
|
||||
("S", "U", 1000000),
|
||||
("S", "N", 1000000000),
|
||||
("L", "U", 1000),
|
||||
("L", "N", 1000000),
|
||||
("U", "N", 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", [("A", 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
|
||||
@@ -0,0 +1,65 @@
|
||||
import re
|
||||
|
||||
import numpy as np
|
||||
import pytest
|
||||
|
||||
from pandas._libs.tslibs.timedeltas import delta_to_nanoseconds
|
||||
|
||||
from pandas import (
|
||||
Timedelta,
|
||||
offsets,
|
||||
)
|
||||
|
||||
|
||||
@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),
|
||||
(1, 1),
|
||||
(np.int64(2), 2),
|
||||
(np.int32(3), 3),
|
||||
],
|
||||
)
|
||||
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)
|
||||
|
||||
|
||||
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)
|
||||
@@ -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 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):
|
||||
if tz_name == "UTC":
|
||||
pytest.skip("UTC: special case in dateutil")
|
||||
|
||||
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")
|
||||
|
||||
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() * 1000000000
|
||||
|
||||
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,174 @@
|
||||
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)),
|
||||
("15l500u", offsets.Micro(15500)),
|
||||
("10s75L", offsets.Milli(10075)),
|
||||
("1s0.25ms", offsets.Micro(1000250)),
|
||||
("1s0.25L", offsets.Micro(1000250)),
|
||||
("2800N", offsets.Nano(2800)),
|
||||
("2SM", offsets.SemiMonthEnd(2)),
|
||||
("2SM-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), ("-2SM", -2), ("-1SMS", -1), ("-5min10s", -310)]
|
||||
)
|
||||
def test_to_offset_negative(freqstr, expected):
|
||||
result = to_offset(freqstr)
|
||||
assert result.n == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"freqstr",
|
||||
[
|
||||
"2h20m",
|
||||
"U1",
|
||||
"-U",
|
||||
"3U1",
|
||||
"-2-3U",
|
||||
"-2D:3H",
|
||||
"1.5.0S",
|
||||
"2SMS-15-15",
|
||||
"2SMS-15D",
|
||||
"100foo",
|
||||
# Invalid leading +/- signs.
|
||||
"+-1d",
|
||||
"-+1h",
|
||||
"+1",
|
||||
"-7",
|
||||
"+d",
|
||||
"-m",
|
||||
# Invalid shortcut anchors.
|
||||
"SM-0",
|
||||
"SM-28",
|
||||
"SM-29",
|
||||
"SM-FOO",
|
||||
"BSM",
|
||||
"SM--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 00T 01S", 1), ("-00H 03T 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)),
|
||||
("Q", offsets.QuarterEnd(startingMonth=12)),
|
||||
("Q-DEC", offsets.QuarterEnd(startingMonth=12)),
|
||||
("Q-MAY", offsets.QuarterEnd(startingMonth=5)),
|
||||
("SM", offsets.SemiMonthEnd(day_of_month=15)),
|
||||
("SM-15", offsets.SemiMonthEnd(day_of_month=15)),
|
||||
("SM-1", offsets.SemiMonthEnd(day_of_month=1)),
|
||||
("SM-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
|
||||
Reference in New Issue
Block a user