diff --git a/nc_py_api/files/_files.py b/nc_py_api/files/_files.py index a15ccd8c..da5138bb 100644 --- a/nc_py_api/files/_files.py +++ b/nc_py_api/files/_files.py @@ -1,8 +1,10 @@ """Helper functions for **FilesAPI** and **AsyncFilesAPI** classes.""" import enum +from datetime import datetime, timezone from io import BytesIO from json import dumps, loads +from typing import Any from urllib.parse import unquote from xml.etree import ElementTree @@ -69,6 +71,16 @@ def get_propfind_properties(capabilities: dict) -> list: return r +def _dav_literal(val: Any) -> str: + """Return a string suitable for .""" + if isinstance(val, datetime): + # make timezone-aware, force UTC, second precision + dt = val if val.tzinfo else val.replace(tzinfo=timezone.utc) + dt = dt.astimezone(timezone.utc).replace(microsecond=0) + return dt.isoformat().replace("+00:00", "Z") # 2025-03-10T12:34:56Z + return str(val) + + def build_find_request(req: list, path: str | FsNode, user: str, capabilities: dict) -> ElementTree.Element: path = path.user_path if isinstance(path, FsNode) else path root = ElementTree.Element( @@ -126,7 +138,7 @@ def _add_value(xml_element, val=None) -> None: ElementTree.SubElement(_, SEARCH_PROPERTIES_MAP[req.pop(0)]) _ = ElementTree.SubElement(_root, "d:literal") value = req.pop(0) - _.text = value if isinstance(value, str) else str(value) + _.text = _dav_literal(value) while len(req): where_part = req.pop(0) diff --git a/tests/actual_tests/files_test.py b/tests/actual_tests/files_test.py index 7e6d89ca..1c2a381f 100644 --- a/tests/actual_tests/files_test.py +++ b/tests/actual_tests/files_test.py @@ -2,7 +2,7 @@ import math import os import zipfile -from datetime import datetime +from datetime import datetime, timedelta from io import BytesIO from pathlib import Path from random import choice, randbytes @@ -753,6 +753,15 @@ def test_find_files_listdir_depth(nc_any): assert len(result) == 4 +def test_find_files_datetime(nc_any): + time_in_past = datetime.now() - timedelta(days=1) + time_in_future = datetime.now() + timedelta(days=1) + assert len(nc_any.files.find(["gt", "last_modified", time_in_past], "/test_dir/subdir/")) + assert not len(nc_any.files.find(["gt", "last_modified", time_in_future], "/test_dir/subdir/")) + assert not len(nc_any.files.find(["lt", "last_modified", time_in_past], "/test_dir/subdir/")) + assert len(nc_any.files.find(["lt", "last_modified", time_in_future], "/test_dir/subdir/")) + + def test_listdir_depth(nc_any): result = nc_any.files.listdir("test_dir/", depth=1) result2 = nc_any.files.listdir("test_dir")