|
1 | 1 | """Helper functions for **FilesAPI** and **AsyncFilesAPI** classes.""" |
2 | 2 |
|
3 | 3 | import enum |
| 4 | +from datetime import datetime, timezone |
4 | 5 | from io import BytesIO |
5 | 6 | from json import dumps, loads |
| 7 | +from typing import Any |
6 | 8 | from urllib.parse import unquote |
7 | 9 | from xml.etree import ElementTree |
8 | 10 |
|
@@ -69,6 +71,16 @@ def get_propfind_properties(capabilities: dict) -> list: |
69 | 71 | return r |
70 | 72 |
|
71 | 73 |
|
| 74 | +def _dav_literal(val: Any) -> str: |
| 75 | + """Return a string suitable for <d:literal>.""" |
| 76 | + if isinstance(val, datetime): |
| 77 | + # make timezone-aware, force UTC, second precision |
| 78 | + dt = val if val.tzinfo else val.replace(tzinfo=timezone.utc) |
| 79 | + dt = dt.astimezone(timezone.utc).replace(microsecond=0) |
| 80 | + return dt.isoformat().replace("+00:00", "Z") # 2025-03-10T12:34:56Z |
| 81 | + return str(val) |
| 82 | + |
| 83 | + |
72 | 84 | def build_find_request(req: list, path: str | FsNode, user: str, capabilities: dict) -> ElementTree.Element: |
73 | 85 | path = path.user_path if isinstance(path, FsNode) else path |
74 | 86 | root = ElementTree.Element( |
@@ -126,7 +138,7 @@ def _add_value(xml_element, val=None) -> None: |
126 | 138 | ElementTree.SubElement(_, SEARCH_PROPERTIES_MAP[req.pop(0)]) |
127 | 139 | _ = ElementTree.SubElement(_root, "d:literal") |
128 | 140 | value = req.pop(0) |
129 | | - _.text = value if isinstance(value, str) else str(value) |
| 141 | + _.text = _dav_literal(value) |
130 | 142 |
|
131 | 143 | while len(req): |
132 | 144 | where_part = req.pop(0) |
|
0 commit comments