Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

### Bug Fixes

1. Avoid floating-point timestamp rounding across microsecond, millisecond, and second boundaries.

1. [#706](https://github.com/influxdata/influxdb-client-python/pull/706): Use logger instead logging.
1. [#710](https://github.com/influxdata/influxdb-client-python/pull/710): Stop `default_tags` from one client leaking into other clients' `WriteApi` (shared mutable default `PointSettings`).
1. [#713](https://github.com/influxdata/influxdb-client-python/pull/713): Replace invalid tuple type annotations `(str, str, str)` with `Tuple[str, str, str]` in batching callbacks, examples and docs.
Expand Down
11 changes: 8 additions & 3 deletions influxdb_client/client/write/point.py
Original file line number Diff line number Diff line change
Expand Up @@ -351,11 +351,16 @@ def _convert_timestamp(timestamp, precision=DEFAULT_WRITE_PRECISION):
if precision is None or precision == WritePrecision.NS:
return ns
elif precision == WritePrecision.US:
return ns / 1e3
divisor = 1000
elif precision == WritePrecision.MS:
return ns / 1e6
divisor = 1000000
elif precision == WritePrecision.S:
return ns / 1e9
divisor = 1000000000
else:
raise ValueError(timestamp)

# Keep truncation toward zero without rounding through a float.
return ns // divisor if ns >= 0 else -(-ns // divisor)

raise ValueError(timestamp)

Expand Down
31 changes: 31 additions & 0 deletions tests/test_PointTimestampBoundaries.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
"""Timestamp boundary regressions through the public Point API."""

import pandas as pd
import pytest

from influxdb_client import Point, WritePrecision
from influxdb_client.client.util import date_utils
from influxdb_client.client.util.date_utils_pandas import PandasDateTimeHelper


@pytest.mark.parametrize("precision, divisor", [
(WritePrecision.US, 1000),
(WritePrecision.MS, 1000000),
(WritePrecision.S, 1000000000),
])
@pytest.mark.parametrize("sign", [1, -1])
@pytest.mark.parametrize("on_boundary", [False, True])
def test_point_timestamp_boundary(monkeypatch, precision, divisor, sign, on_boundary):
monkeypatch.setattr(date_utils, "date_helper", PandasDateTimeHelper())
magnitude = 1700000000000000000 + divisor - (0 if on_boundary else 1)
stamp = pd.Timestamp(sign * magnitude, unit="ns", tz="UTC")
point = Point("sensor").field("value", 1).time(stamp, precision)
assert point.to_line_protocol() == f"sensor value=1i {sign * (magnitude // divisor)}"


@pytest.mark.parametrize("sign", [1, -1])
def test_point_nanosecond_timestamp_unchanged(monkeypatch, sign):
monkeypatch.setattr(date_utils, "date_helper", PandasDateTimeHelper())
ns = sign * 1700000000000000999
point = Point("sensor").field("value", 1).time(pd.Timestamp(ns, unit="ns", tz="UTC"))
assert point.to_line_protocol() == f"sensor value=1i {ns}"