Skip to content

Relax nanosecond datetime restriction in CF time decoding #9618

New issue

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

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

Already on GitHub? Sign in to your account

Merged
merged 165 commits into from
Jan 15, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
165 commits
Select commit Hold shift + click to select a range
7b5f323
implement default_precision_timestamp, refactor coding/times.py and c…
kmuehlbauer Oct 10, 2024
8784f33
align tests with new time resolution behaviour
kmuehlbauer Oct 10, 2024
b45ab23
timedelta decoding, fsspec handling
kmuehlbauer Oct 10, 2024
39086ef
fixes in coding/times.py
kmuehlbauer Oct 13, 2024
df49a40
add docs on time coding
kmuehlbauer Oct 13, 2024
adb8ca3
attempt fixing doc tests
kmuehlbauer Oct 13, 2024
266b1ed
fix issue where out-of-bounds floating point values slipped in the pr…
kmuehlbauer Oct 14, 2024
6d5f13b
convert to UTC first before stripping of tz in _unpack_time_units_and…
kmuehlbauer Oct 14, 2024
5d68bfe
reorganize pandas compatibility code, remove unneeded code, attempt t…
kmuehlbauer Oct 14, 2024
07bba69
another attempt to finally fix mypy
kmuehlbauer Oct 14, 2024
6e7f0bb
refactor out _check_date_is_after_shift
kmuehlbauer Oct 14, 2024
b4a49bb
refactor out _maybe_strip_tz_from_timestamp
kmuehlbauer Oct 14, 2024
2e1ff4f
more refactoring in coding.times.py
kmuehlbauer Oct 14, 2024
d5a7da0
more refactoring in coding.times.py
kmuehlbauer Oct 14, 2024
821b68d
minor fix in time-coding.rst
kmuehlbauer Oct 14, 2024
d066edf
set default resolution to "s", which actually means, use pandas lowes…
kmuehlbauer Oct 14, 2024
ed22da1
Add section for default units, fix options
kmuehlbauer Oct 14, 2024
8bf23f4
attempt to fix typing
kmuehlbauer Oct 14, 2024
c3a2b39
attempt to fix typing
kmuehlbauer Oct 14, 2024
3c44aed
fix scalar datetime/timedelta
kmuehlbauer Oct 15, 2024
48be73a
fix user docs
kmuehlbauer Oct 15, 2024
7ac9983
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Oct 18, 2024
d86ad04
Fix variable tests, mostly datetime/timedelta is inittialized with us…
kmuehlbauer Oct 18, 2024
b5d0795
revert changes in _possible_convert_objects, this needs to be checked…
kmuehlbauer Oct 18, 2024
60324f0
fix doc link
kmuehlbauer Oct 18, 2024
6f2861a
Merge branch 'main' into any-time-resolution-2
kmuehlbauer Nov 8, 2024
1f07500
Apply suggestions from code review
kmuehlbauer Nov 8, 2024
798b444
Merge branch 'main' into any-time-resolution-2
kmuehlbauer Nov 8, 2024
f487599
Merge branch 'main' into any-time-resolution-2
kmuehlbauer Nov 16, 2024
20d6c9d
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Nov 16, 2024
7391948
remove outdated description
kmuehlbauer Nov 16, 2024
308091c
use set instead list
kmuehlbauer Nov 16, 2024
5f40b4e
remove global option
kmuehlbauer Nov 16, 2024
2a65d8d
mypy thinks `unit` is Literal, because the pandas-stubs suggest so, b…
kmuehlbauer Nov 17, 2024
43f7d61
ignore mypy arg-type
kmuehlbauer Nov 17, 2024
59934b9
fix docstring of `default_precision_timestamp`
kmuehlbauer Nov 17, 2024
a01f9f3
add 'time_unit'-kwarg to decode_cf and descendent functions with "ns"…
kmuehlbauer Nov 17, 2024
8b91128
fix tests
kmuehlbauer Nov 17, 2024
0e351ca
fix more tests
kmuehlbauer Nov 17, 2024
07a8e9c
fix docstring
kmuehlbauer Nov 17, 2024
2be5739
use pd.Timestamp(np.datetime64(cftime)) to convert from cftime to numpy
kmuehlbauer Nov 17, 2024
b9d0a8e
use dt = np.datetime64(cftime.isoformat()) to convert from cftime to …
kmuehlbauer Nov 18, 2024
08afc3b
fix time-coding.rst
kmuehlbauer Nov 18, 2024
edc55e1
use us in to_datetimeindex
kmuehlbauer Nov 18, 2024
bffe919
revert back to us for datetimeindex tests
kmuehlbauer Nov 18, 2024
150b982
estimate fitting resolution for floating point values, when decoding …
kmuehlbauer Nov 18, 2024
7113ceb
add test
kmuehlbauer Nov 18, 2024
7f47f0b
refactor floating point decoding
kmuehlbauer Nov 18, 2024
512808d
Merge branch 'main' into any-time-resolution-2
kmuehlbauer Nov 18, 2024
63c83f4
simplify recursive function, update tests
kmuehlbauer Nov 18, 2024
0efbbeb
more refactoring, update tests
kmuehlbauer Nov 19, 2024
2910250
add fixture, apply fixture to more tests.
kmuehlbauer Nov 19, 2024
57d8d72
update time-coding.rst
kmuehlbauer Nov 19, 2024
5333240
fix typing
kmuehlbauer Nov 19, 2024
6f35c81
try to fix test, remove stale print
kmuehlbauer Nov 19, 2024
d0c17a4
another attempt to fix test
kmuehlbauer Nov 19, 2024
b2b6bb1
debug failing test
kmuehlbauer Nov 19, 2024
5dbc8a7
refactor cftime fallback in datetime decoding
kmuehlbauer Nov 21, 2024
be0d3e0
Merge branch 'main' into any-time-resolution-2
kmuehlbauer Nov 21, 2024
f95408a
fix merge-collission
kmuehlbauer Nov 21, 2024
609e15c
Merge branch 'main' into any-time-resolution-2
kmuehlbauer Nov 21, 2024
ec7f165
use CFDatetimeCoder instance to transport unit/use_cftime
kmuehlbauer Nov 22, 2024
1f1cf1c
decode_times with CFDatetimeCoder
kmuehlbauer Nov 25, 2024
14b1a88
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Nov 25, 2024
05627dd
Merge branch 'main' into any-time-resolution-2
kmuehlbauer Nov 25, 2024
e7cbf3a
fix mypy, warning/error
kmuehlbauer Nov 26, 2024
fc87e04
api, docs, docstrings
kmuehlbauer Nov 26, 2024
9ae645e
Merge branch 'main' into any-time-resolution-2
kmuehlbauer Nov 26, 2024
6e3ca57
Merge branch 'main' into any-time-resolution-2
kmuehlbauer Nov 27, 2024
277d1c6
docs, whats-new.rst
kmuehlbauer Nov 27, 2024
81a9d94
fix whats-new.rst
kmuehlbauer Nov 27, 2024
be8642f
Merge branch 'main' into any-time-resolution-2
kmuehlbauer Nov 27, 2024
f3f62e5
Merge branch 'main' into any-time-resolution-2
kmuehlbauer Dec 2, 2024
c07df41
Merge remote-tracking branch 'origin/main' into any-time-resolution-2
kmuehlbauer Dec 10, 2024
9653a01
fix tests after merge
kmuehlbauer Dec 10, 2024
f5822fd
Merge branch 'main' into any-time-resolution-2
kmuehlbauer Dec 12, 2024
66c0b9f
Apply suggestions from code review
kmuehlbauer Dec 13, 2024
ba51274
provide CFDatetimeCoder from xarray.coders
kmuehlbauer Dec 13, 2024
3ba3e3f
provide CFDatetimeCoder from xarray.coders
kmuehlbauer Dec 13, 2024
1ab43eb
provide CFDatetimeCoder from xarray.coders
kmuehlbauer Dec 13, 2024
45ba9d3
fix tests as suggested by code review
kmuehlbauer Dec 13, 2024
091a90d
Merge branch 'main' into any-time-resolution-2
kmuehlbauer Dec 14, 2024
ab3c9ed
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Dec 14, 2024
53fe43a
Merge branch 'main' into any-time-resolution-2
kmuehlbauer Dec 16, 2024
a16a890
Move scalar handling logic into `_possibly_convert_objects` as sugges…
kmuehlbauer Dec 16, 2024
4283f8a
Add note on ``proleptic_gregorian`` calendar
kmuehlbauer Dec 16, 2024
0ba848d
remove time_resolution from docstring
kmuehlbauer Dec 16, 2024
6cb8702
update time.coding.rst wrt default time unit
kmuehlbauer Dec 16, 2024
5de8d0d
fix empty array
kmuehlbauer Dec 16, 2024
fc985d9
revert some tests to align with scalar logic handling
kmuehlbauer Dec 16, 2024
799b750
Merge branch 'main' into any-time-resolution-2
kmuehlbauer Dec 16, 2024
a2d8e69
split out CFDatetimeCoder into coders, deprecate use_cftime as keywor…
kmuehlbauer Nov 22, 2024
d6fe956
add whats-new.rst entry
kmuehlbauer Dec 17, 2024
bd6a5d1
Apply suggestions from code review
kmuehlbauer Dec 17, 2024
6557ef9
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Dec 17, 2024
759fb72
fix warning
kmuehlbauer Dec 17, 2024
2118191
fix docstrings
kmuehlbauer Dec 17, 2024
262295a
try fix typing
kmuehlbauer Dec 17, 2024
941c4b5
Merge branch 'main' into any-time-resolution-2
kmuehlbauer Dec 18, 2024
6e41425
Merge branch 'main' into coders
kmuehlbauer Dec 18, 2024
adebafa
Apply suggestions from code review
kmuehlbauer Dec 30, 2024
6cd81e5
Apply suggestions from code review
kmuehlbauer Dec 30, 2024
1ae9a22
Merge branch 'main' into coders
kmuehlbauer Dec 30, 2024
1cec644
Update xarray/conventions.py
kmuehlbauer Dec 30, 2024
60aed87
Merge branch 'main' into coders
kmuehlbauer Jan 1, 2025
797dc85
Merge branch 'main' into any-time-resolution-2-wip
kmuehlbauer Jan 1, 2025
225c5b3
remove duplicate function (introduced when merging main)
kmuehlbauer Jan 1, 2025
33a1563
Update deprecated directive
kmuehlbauer Jan 2, 2025
4efe8b0
merge main into any-time-resolution-2
kmuehlbauer Jan 3, 2025
21a0ec6
Merge branch 'main' into coders
kmuehlbauer Jan 3, 2025
48dea20
merge coders into any-time-resolution-2
kmuehlbauer Jan 3, 2025
1145f4b
fix typing
kmuehlbauer Jan 3, 2025
a9990cf
re-fix doctests
kmuehlbauer Jan 3, 2025
5fa630f
merge main into any-time-resolution-2
kmuehlbauer Jan 4, 2025
43c85d1
fix whats-new.rst after merging main
kmuehlbauer Jan 4, 2025
a4702d6
Apply suggestions from code review
kmuehlbauer Jan 4, 2025
9bd292a
Apply suggestions from code review
kmuehlbauer Jan 4, 2025
25b797e
rewrite recursive function using for-loop
kmuehlbauer Jan 5, 2025
3bd8cf4
remove astype-construct in _possibly_convert_objects
kmuehlbauer Jan 5, 2025
8b9c85a
Update xarray/coding/times.py
kmuehlbauer Jan 5, 2025
2555d89
Merge branch 'main' into any-time-resolution-2
kmuehlbauer Jan 7, 2025
3b2d861
add suggestions from code review
kmuehlbauer Jan 7, 2025
66e181c
rephrase per suggestion
kmuehlbauer Jan 7, 2025
e380968
add article per suggestion
kmuehlbauer Jan 7, 2025
305938c
Apply suggestions from code review
kmuehlbauer Jan 7, 2025
b32b02c
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jan 7, 2025
a2c46b1
fix scalar handling for timedelta based indexer
kmuehlbauer Jan 7, 2025
fa2c4b6
remove stale error message and "ignore:Converting non-default" in tes…
kmuehlbauer Jan 7, 2025
c65c9af
add per review suggestions
kmuehlbauer Jan 7, 2025
21dffc1
add/remove todo
kmuehlbauer Jan 7, 2025
8eeeb78
rename timeunit -> format
kmuehlbauer Jan 7, 2025
7ad2183
return "ns" resolution per default for timedeltas, if not specified
kmuehlbauer Jan 7, 2025
9e4cab6
Be specific on types/dtpyes
kmuehlbauer Jan 7, 2025
5964a9e
add comment
kmuehlbauer Jan 7, 2025
308391d
add suggestions from code review
kmuehlbauer Jan 7, 2025
0e886d6
Merge branch 'main' into any-time-resolution-2
kmuehlbauer Jan 7, 2025
d494fe0
fix docs
kmuehlbauer Jan 8, 2025
ef6f722
fix test which isn't run for numpy2 atm
kmuehlbauer Jan 8, 2025
4ea5241
add notes on to_datetime section, update examples showing usage of 'a…
kmuehlbauer Jan 8, 2025
151e9cd
use np.timedelta64 for to_timedelta example, update as_unit example, …
kmuehlbauer Jan 8, 2025
8ecda4e
remove note
kmuehlbauer Jan 8, 2025
2bbf0ff
Apply suggestions from code review
kmuehlbauer Jan 8, 2025
0308672
refactor timedelta decoding to _numbers_to_timedelta and res-use it w…
kmuehlbauer Jan 9, 2025
b043020
fix conventions test, add todo
kmuehlbauer Jan 9, 2025
7182ce2
run times through pd.Timestamp to catch possible overflows
kmuehlbauer Jan 9, 2025
470235e
fix tests for cftime_to_nptime
kmuehlbauer Jan 9, 2025
e619a4c
fix cftime_to_nptime in cftimeindex
kmuehlbauer Jan 9, 2025
700e78d
introduce pd.Timestamp instance check
kmuehlbauer Jan 9, 2025
4525ea1
warn if out-of-bound datetimes are encoded with standard calendar, fa…
kmuehlbauer Jan 9, 2025
0b93dbd
fix time-coding.rst, add reference to time-series.rst.
kmuehlbauer Jan 9, 2025
b38cd7e
try to fix typing, ignore one
kmuehlbauer Jan 9, 2025
a2d1c96
try to fix docs
kmuehlbauer Jan 9, 2025
c4b2af3
revert doc-changes
kmuehlbauer Jan 9, 2025
45a0d56
Add a non-ns test for polyval, polyfit
dcherian Jan 9, 2025
3ef79cd
Merge branch 'main' into any-time-resolution-2
kmuehlbauer Jan 10, 2025
ac719e8
more doc cosmetics
kmuehlbauer Jan 10, 2025
5292569
add whats-new.rst entry
kmuehlbauer Jan 10, 2025
ecd603b
add/fix coder docstring
kmuehlbauer Jan 10, 2025
f6716dc
add xr.date_range example as suggested per review
kmuehlbauer Jan 10, 2025
0556376
Apply suggestions from code review
kmuehlbauer Jan 13, 2025
ffc1828
Implement `time_unit` option for `decode_cf_timedelta` (#3)
spencerkclark Jan 13, 2025
eaf3c73
fix typing
kmuehlbauer Jan 13, 2025
1e6ba18
use nanmin/nanmax, catch numpy RuntimeWarnings
kmuehlbauer Jan 13, 2025
85a340b
Apply suggestions from code review
spencerkclark Jan 14, 2025
db69b63
Merge branch 'main' into any-time-resolution-2
kmuehlbauer Jan 15, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
align tests with new time resolution behaviour
  • Loading branch information
kmuehlbauer committed Oct 18, 2024
commit 8784f33a739c873088034020a666385f6949c84a
2 changes: 1 addition & 1 deletion xarray/tests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,7 @@ def create_test_data(
f'Not enough letters for filling this dimension size ({_dims["dim3"]})'
)
obj["dim3"] = ("dim3", list(string.ascii_lowercase[0 : _dims["dim3"]]))
obj["time"] = ("time", pd.date_range("2000-01-01", periods=20))
obj["time"] = ("time", pd.date_range("2000-01-01", periods=20, unit="s"))
for v, dims in sorted(_vars.items()):
data = rs.normal(size=tuple(_dims[d] for d in dims))
obj[v] = (dims, data)
Expand Down
22 changes: 16 additions & 6 deletions xarray/tests/test_backends.py
Original file line number Diff line number Diff line change
Expand Up @@ -584,6 +584,12 @@ def test_roundtrip_cftime_datetime_data(self) -> None:
warnings.filterwarnings("ignore", "Unable to decode time axis")

with self.roundtrip(expected, save_kwargs=kwargs) as actual:
# proleptic gregorian will be decoded into numpy datetime64
# fixing to expectations
if actual.t.dtype.kind == "M":
dtype = f"datetime64[{np.datetime_data(actual.t)[0]}]"
expected_decoded_t = expected_decoded_t.astype(dtype)
expected_decoded_t0 = expected_decoded_t0.astype(dtype)
abs_diff = abs(actual.t.values - expected_decoded_t)
assert (abs_diff <= np.timedelta64(1, "s")).all()
assert (
Expand All @@ -598,7 +604,8 @@ def test_roundtrip_cftime_datetime_data(self) -> None:
assert actual.t.encoding["calendar"] == expected_calendar

def test_roundtrip_timedelta_data(self) -> None:
time_deltas = pd.to_timedelta(["1h", "2h", "NaT"]) # type: ignore[arg-type, unused-ignore]
# todo: check, if default unit "s" is enough
time_deltas = pd.to_timedelta(["1h", "2h", "NaT"]).as_unit("s") # type: ignore[arg-type, unused-ignore]
expected = Dataset({"td": ("td", time_deltas), "td0": time_deltas[0]})
with self.roundtrip(expected) as actual:
assert_identical(expected, actual)
Expand Down Expand Up @@ -1583,7 +1590,8 @@ def test_open_encodings(self) -> None:

expected = Dataset()

time = pd.date_range("1999-01-05", periods=10)
# todo: check, if specifying "s" is enough
time = pd.date_range("1999-01-05", periods=10, unit="s")
encoding = {"units": units, "dtype": np.dtype("int32")}
expected["time"] = ("time", time, {}, encoding)

Expand Down Expand Up @@ -5379,11 +5387,12 @@ def test_use_cftime_standard_calendar_default_in_range(calendar) -> None:

@requires_cftime
@requires_scipy_or_netCDF4
@pytest.mark.parametrize("calendar", _STANDARD_CALENDARS)
@pytest.mark.parametrize("units_year", [1500, 2500])
@pytest.mark.parametrize("calendar", ["standard", "gregorian"])
@pytest.mark.parametrize("units_year", [1500, 1582])
def test_use_cftime_standard_calendar_default_out_of_range(
calendar, units_year
) -> None:
# todo: check, if we still need to test for two dates
import cftime

x = [0, 1]
Expand Down Expand Up @@ -5472,9 +5481,10 @@ def test_use_cftime_false_standard_calendar_in_range(calendar) -> None:


@requires_scipy_or_netCDF4
@pytest.mark.parametrize("calendar", _STANDARD_CALENDARS)
@pytest.mark.parametrize("units_year", [1500, 2500])
@pytest.mark.parametrize("calendar", ["standard", "gregorian"])
@pytest.mark.parametrize("units_year", [1500, 1582])
def test_use_cftime_false_standard_calendar_out_of_range(calendar, units_year) -> None:
# todo: check, if we still need to check for two dates
x = [0, 1]
time = [0, 720]
units = f"days since {units_year}-01-01"
Expand Down
2 changes: 1 addition & 1 deletion xarray/tests/test_cftime_offsets.py
Original file line number Diff line number Diff line change
Expand Up @@ -1496,7 +1496,7 @@ def test_date_range_like_same_calendar():
assert src is out


@pytest.mark.filterwarnings("ignore:Converting non-nanosecond")
@pytest.mark.filterwarnings("ignore:Converting non-default")
def test_date_range_like_errors():
src = date_range("1899-02-03", periods=20, freq="D", use_cftime=False)
src = src[np.arange(20) != 10] # Remove 1 day so the frequency is not inferable.
Expand Down
11 changes: 8 additions & 3 deletions xarray/tests/test_cftimeindex.py
Original file line number Diff line number Diff line change
Expand Up @@ -1159,7 +1159,7 @@ def test_strftime_of_cftime_array(calendar):
@pytest.mark.parametrize("unsafe", [False, True])
def test_to_datetimeindex(calendar, unsafe):
index = xr.cftime_range("2000", periods=5, calendar=calendar)
expected = pd.date_range("2000", periods=5)
expected = pd.date_range("2000", periods=5, unit="us")

if calendar in _NON_STANDARD_CALENDARS and not unsafe:
with pytest.warns(RuntimeWarning, match="non-standard"):
Expand All @@ -1176,7 +1176,11 @@ def test_to_datetimeindex(calendar, unsafe):
@pytest.mark.parametrize("calendar", _ALL_CALENDARS)
def test_to_datetimeindex_out_of_range(calendar):
index = xr.cftime_range("0001", periods=5, calendar=calendar)
with pytest.raises(ValueError, match="0001"):
# todo: needs discussion, do we need this test?
if calendar in _NON_STANDARD_CALENDARS:
with pytest.warns(RuntimeWarning, match="non-standard"):
index.to_datetimeindex()
else:
index.to_datetimeindex()


Expand All @@ -1199,7 +1203,8 @@ def test_multiindex():
@pytest.mark.parametrize("freq", ["3663s", "33min", "2h"])
@pytest.mark.parametrize("method", ["floor", "ceil", "round"])
def test_rounding_methods_against_datetimeindex(freq, method):
expected = pd.date_range("2000-01-02T01:03:51", periods=10, freq="1777s")
# todo: check, if setting to "us" is enough
expected = pd.date_range("2000-01-02T01:03:51", periods=10, freq="1777s", unit="us")
expected = getattr(expected, method)(freq)
result = xr.cftime_range("2000-01-02T01:03:51", periods=10, freq="1777s")
result = getattr(result, method)(freq).to_datetimeindex()
Expand Down
67 changes: 47 additions & 20 deletions xarray/tests/test_coding_times.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,15 +129,20 @@ def test_cf_datetime(num_dates, units, calendar) -> None:
expected = cftime.num2date(
num_dates, units, calendar, only_use_cftime_datetimes=True
)
min_y = np.ravel(np.atleast_1d(expected))[np.nanargmin(num_dates)].year
max_y = np.ravel(np.atleast_1d(expected))[np.nanargmax(num_dates)].year
if min_y >= 1678 and max_y < 2262:
print("0:", expected)

min_y = np.ravel(np.atleast_1d(expected))[np.nanargmin(num_dates)] # .year
max_y = np.ravel(np.atleast_1d(expected))[np.nanargmax(num_dates)] # .year
typ = type(min_y)
border = typ(1582, 10, 15)
if calendar == "proleptic_gregorian" or (min_y >= border and max_y >= border):
expected = cftime_to_nptime(expected)
print("1:", expected)

with warnings.catch_warnings():
warnings.filterwarnings("ignore", "Unable to decode time axis")
actual = decode_cf_datetime(num_dates, units, calendar)

print("2:", actual, type(actual), actual.dtype)
abs_diff = np.asarray(abs(actual - expected)).ravel()
abs_diff = pd.to_timedelta(abs_diff.tolist()).to_numpy()

Expand All @@ -146,6 +151,8 @@ def test_cf_datetime(num_dates, units, calendar) -> None:
# https://github.com/Unidata/netcdf4-python/issues/355
assert (abs_diff <= np.timedelta64(1, "s")).all()
encoded1, _, _ = encode_cf_datetime(actual, units, calendar)

print("1:", encoded1)
assert_duckarray_allclose(num_dates, encoded1)

if hasattr(num_dates, "ndim") and num_dates.ndim == 1 and "1000" not in units:
Expand Down Expand Up @@ -211,14 +218,21 @@ def test_decode_standard_calendar_inside_timestamp_range(calendar) -> None:
import cftime

units = "days since 0001-01-01"
times = pd.date_range("2001-04-01-00", end="2001-04-30-23", freq="h")
unit = "us"
times = pd.date_range("2001-04-01-00", end="2001-04-30-23", unit=unit, freq="h")
print("A:", times)
time = cftime.date2num(times.to_pydatetime(), units, calendar=calendar)
expected = times.values
expected_dtype = np.dtype("M8[ns]")

if calendar == "proleptic_gregorian":
unit = "s"
expected_dtype = np.dtype(f"M8[{unit}]")
print("0:", time[0], units, calendar)
print("1:", expected.astype("int64")[0], expected.dtype)
actual = decode_cf_datetime(time, units, calendar=calendar)
print("2:", actual[0], actual.astype("int64")[0], actual.dtype)
assert actual.dtype == expected_dtype
abs_diff = abs(actual - expected)
print("3:", abs_diff[0], abs_diff.dtype)
# once we no longer support versions of netCDF4 older than 1.1.5,
# we could do this check with near microsecond accuracy:
# https://github.com/Unidata/netcdf4-python/issues/355
Expand Down Expand Up @@ -262,6 +276,9 @@ def test_decode_dates_outside_timestamp_range(calendar) -> None:
expected = cftime.num2date(
time, units, calendar=calendar, only_use_cftime_datetimes=True
)
# special case proleptic_gregorian
if calendar == "proleptic_gregorian":
expected = expected.astype("=M8[us]")
expected_date_type = type(expected[0])

with warnings.catch_warnings():
Expand All @@ -272,7 +289,7 @@ def test_decode_dates_outside_timestamp_range(calendar) -> None:
# once we no longer support versions of netCDF4 older than 1.1.5,
# we could do this check with near microsecond accuracy:
# https://github.com/Unidata/netcdf4-python/issues/355
assert (abs_diff <= np.timedelta64(1, "s")).all()
assert (abs_diff <= np.timedelta64(1, "us")).all()


@requires_cftime
Expand All @@ -281,11 +298,13 @@ def test_decode_standard_calendar_single_element_inside_timestamp_range(
calendar,
) -> None:
units = "days since 0001-01-01"
unit = "s" if calendar == "proleptic_gregorian" else "us"
for num_time in [735368, [735368], [[735368]]]:
with warnings.catch_warnings():
warnings.filterwarnings("ignore", "Unable to decode time axis")
actual = decode_cf_datetime(num_time, units, calendar=calendar)
assert actual.dtype == np.dtype("M8[ns]")

assert actual.dtype == np.dtype(f"M8[{unit}]")


@requires_cftime
Expand Down Expand Up @@ -327,6 +346,7 @@ def test_decode_standard_calendar_multidim_time_inside_timestamp_range(
import cftime

units = "days since 0001-01-01"
unit = "s" if calendar == "proleptic_gregorian" else "us"
times1 = pd.date_range("2001-04-01", end="2001-04-05", freq="D")
times2 = pd.date_range("2001-05-01", end="2001-05-05", freq="D")
time1 = cftime.date2num(times1.to_pydatetime(), units, calendar=calendar)
Expand All @@ -339,7 +359,7 @@ def test_decode_standard_calendar_multidim_time_inside_timestamp_range(
expected2 = times2.values

actual = decode_cf_datetime(mdim_time, units, calendar=calendar)
assert actual.dtype == np.dtype("M8[ns]")
assert actual.dtype == np.dtype(f"M8[{unit}]")

abs_diff1 = abs(actual[:, 0] - expected1)
abs_diff2 = abs(actual[:, 1] - expected2)
Expand Down Expand Up @@ -414,7 +434,14 @@ def test_decode_multidim_time_outside_timestamp_range(calendar) -> None:
warnings.filterwarnings("ignore", "Unable to decode time axis")
actual = decode_cf_datetime(mdim_time, units, calendar=calendar)

assert actual.dtype == np.dtype("O")
if calendar == "proleptic_gregorian":
dtype = np.dtype("=M8[s]")
expected1 = expected1.astype(dtype)
expected2 = expected2.astype(dtype)
else:
dtype = np.dtype("O")

assert actual.dtype == dtype

abs_diff1 = abs(actual[:, 0] - expected1)
abs_diff2 = abs(actual[:, 1] - expected2)
Expand Down Expand Up @@ -509,7 +536,7 @@ def test_decoded_cf_datetime_array_2d() -> None:
("x", "y"), np.array([[0, 1], [2, 3]]), {"units": "days since 2000-01-01"}
)
result = CFDatetimeCoder().decode(variable)
assert result.dtype == "datetime64[ns]"
assert result.dtype == "datetime64[s]"
expected = pd.date_range("2000-01-01", periods=4).values.reshape(2, 2)
assert_array_equal(np.asarray(result), expected)

Expand Down Expand Up @@ -675,7 +702,7 @@ def test_decode_cf(calendar) -> None:
if calendar not in _STANDARD_CALENDARS:
assert ds.test.dtype == np.dtype("O")
else:
assert ds.test.dtype == np.dtype("M8[ns]")
assert ds.test.dtype == np.dtype("M8[s]")


def test_decode_cf_time_bounds() -> None:
Expand All @@ -700,7 +727,7 @@ def test_decode_cf_time_bounds() -> None:
"calendar": "standard",
}
dsc = decode_cf(ds)
assert dsc.time_bnds.dtype == np.dtype("M8[ns]")
assert dsc.time_bnds.dtype == np.dtype("M8[s]")
dsc = decode_cf(ds, decode_times=False)
assert dsc.time_bnds.dtype == np.dtype("int64")

Expand Down Expand Up @@ -917,8 +944,8 @@ def test_use_cftime_default_standard_calendar_in_range(calendar) -> None:


@requires_cftime
@pytest.mark.parametrize("calendar", _STANDARD_CALENDARS)
@pytest.mark.parametrize("units_year", [1500, 2500])
@pytest.mark.parametrize("calendar", ["standard", "gregorian"])
@pytest.mark.parametrize("units_year", [1500, 1580])
def test_use_cftime_default_standard_calendar_out_of_range(
calendar, units_year
) -> None:
Expand Down Expand Up @@ -980,8 +1007,8 @@ def test_use_cftime_false_standard_calendar_in_range(calendar) -> None:
np.testing.assert_array_equal(result, expected)


@pytest.mark.parametrize("calendar", _STANDARD_CALENDARS)
@pytest.mark.parametrize("units_year", [1500, 2500])
@pytest.mark.parametrize("calendar", ["standard", "gregorian"])
@pytest.mark.parametrize("units_year", [1500, 1582])
def test_use_cftime_false_standard_calendar_out_of_range(calendar, units_year) -> None:
numerical_dates = [0, 1]
units = f"days since {units_year}-01-01"
Expand Down Expand Up @@ -1266,7 +1293,7 @@ def test_roundtrip_datetime64_nanosecond_precision(
encoding = {}

var = Variable(["time"], times, encoding=encoding)
assert var.dtype == np.dtype("=M8[ns]")
assert var.dtype == np.dtype(f"=M8[{timeunit}]")

encoded_var = conventions.encode_cf_variable(var)
assert (
Expand All @@ -1277,7 +1304,7 @@ def test_roundtrip_datetime64_nanosecond_precision(
assert encoded_var.data.dtype == dtype

decoded_var = conventions.decode_cf_variable("foo", encoded_var)
assert decoded_var.dtype == np.dtype("=M8[ns]")
assert decoded_var.dtype == np.dtype(f"=M8[{timeunit}]")
assert (
decoded_var.encoding["units"]
== f"{_numpy_to_netcdf_timeunit(timeunit)} since 1970-01-01 00:00:00"
Expand Down
2 changes: 1 addition & 1 deletion xarray/tests/test_concat.py
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@ def test_concat_multiple_datasets_with_multiple_missing_variables() -> None:
assert_identical(actual, expected)


@pytest.mark.filterwarnings("ignore:Converting non-nanosecond")
@pytest.mark.filterwarnings("ignore:Converting non-default")
def test_concat_type_of_missing_fill() -> None:
datasets = create_typed_datasets(2, seed=123)
expected1 = concat(datasets, dim="day", fill_value=dtypes.NA)
Expand Down
10 changes: 5 additions & 5 deletions xarray/tests/test_conventions.py
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ def test_deterministic_coords_encoding(self) -> None:
vars, attrs = conventions.encode_dataset_coordinates(ds)
assert attrs["coordinates"] == "bar baz"

@pytest.mark.filterwarnings("ignore:Converting non-nanosecond")
@pytest.mark.filterwarnings("ignore:Converting non-default")
def test_emit_coordinates_attribute_in_attrs(self) -> None:
orig = Dataset(
{"a": 1, "b": 1},
Expand All @@ -231,7 +231,7 @@ def test_emit_coordinates_attribute_in_attrs(self) -> None:
assert enc["b"].attrs.get("coordinates") == "t"
assert "coordinates" not in enc["b"].encoding

@pytest.mark.filterwarnings("ignore:Converting non-nanosecond")
@pytest.mark.filterwarnings("ignore:Converting non-default")
def test_emit_coordinates_attribute_in_encoding(self) -> None:
orig = Dataset(
{"a": 1, "b": 1},
Expand Down Expand Up @@ -364,7 +364,7 @@ def test_dataset_repr_with_netcdf4_datetimes(self) -> None:

attrs = {"units": "days since 1900-01-01"}
ds = decode_cf(Dataset({"time": ("time", [0, 1], attrs)}))
assert "(time) datetime64[ns]" in repr(ds)
assert "(time) datetime64[s]" in repr(ds)

@requires_cftime
def test_decode_cf_datetime_transition_to_invalid(self) -> None:
Expand Down Expand Up @@ -447,13 +447,13 @@ def test_decode_cf_time_kwargs(self) -> None:

dsc = conventions.decode_cf(ds)
assert dsc.timedelta.dtype == np.dtype("m8[ns]")
assert dsc.time.dtype == np.dtype("M8[ns]")
assert dsc.time.dtype == np.dtype("M8[s]")
dsc = conventions.decode_cf(ds, decode_times=False)
assert dsc.timedelta.dtype == np.dtype("int64")
assert dsc.time.dtype == np.dtype("int64")
dsc = conventions.decode_cf(ds, decode_times=True, decode_timedelta=False)
assert dsc.timedelta.dtype == np.dtype("int64")
assert dsc.time.dtype == np.dtype("M8[ns]")
assert dsc.time.dtype == np.dtype("M8[s]")
dsc = conventions.decode_cf(ds, decode_times=False, decode_timedelta=True)
assert dsc.timedelta.dtype == np.dtype("m8[ns]")
assert dsc.time.dtype == np.dtype("int64")
Expand Down
4 changes: 2 additions & 2 deletions xarray/tests/test_dataarray.py
Original file line number Diff line number Diff line change
Expand Up @@ -3657,7 +3657,7 @@ def test_to_and_from_dict(
actual_no_data = da.to_dict(data=False, encoding=encoding)
assert expected_no_data == actual_no_data

@pytest.mark.filterwarnings("ignore:Converting non-nanosecond")
@pytest.mark.filterwarnings("ignore:Converting non-default")
def test_to_and_from_dict_with_time_dim(self) -> None:
x = np.random.randn(10, 3)
t = pd.date_range("20130101", periods=10)
Expand All @@ -3666,7 +3666,7 @@ def test_to_and_from_dict_with_time_dim(self) -> None:
roundtripped = DataArray.from_dict(da.to_dict())
assert_identical(da, roundtripped)

@pytest.mark.filterwarnings("ignore:Converting non-nanosecond")
@pytest.mark.filterwarnings("ignore:Converting non-default")
def test_to_and_from_dict_with_nan_nat(self) -> None:
y = np.random.randn(10, 3)
y[2] = np.nan
Expand Down
Loading
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy