From e180f3276f65e265b32145b090ee07ea4756007b Mon Sep 17 00:00:00 2001 From: NguyenHoangSon96 Date: Mon, 11 May 2026 16:53:16 +0700 Subject: [PATCH] fix: send correct time unit when writing Points --- CHANGELOG.md | 5 +++ .../v3/client/config/ClientConfig.java | 10 ++++- .../client/internal/InfluxDBClientImpl.java | 18 ++++++++- .../v3/client/write/WriteOptions.java | 28 +++++++++++++- .../v3/client/InfluxDBClientWriteTest.java | 10 ++++- .../v3/client/integration/E2ETest.java | 37 ++++++++++++++++++- 6 files changed, 100 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b01b05fa..ee031daf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,11 @@ See [Partial writes](https://docs.influxdata.com/influxdb3/core/write-data/http-api/v3-write-lp/#partial-writes) for more. For InfluxDB Clustered version, set `useV2Api=true` for writing. +### Bug Fixes + +1. [#384](https://github.com/InfluxCommunity/influxdb3-java/pull/384): Always set `precision` to `nanosecond` when + writing Points. + ## 1.9.0 [2026-04-23] ### Features diff --git a/src/main/java/com/influxdb/v3/client/config/ClientConfig.java b/src/main/java/com/influxdb/v3/client/config/ClientConfig.java index 11021d6d..3f4bce9a 100644 --- a/src/main/java/com/influxdb/v3/client/config/ClientConfig.java +++ b/src/main/java/com/influxdb/v3/client/config/ClientConfig.java @@ -53,7 +53,10 @@ *
  • authScheme - authentication scheme
  • *
  • organization - organization to be used for operations
  • *
  • database - database to be used for InfluxDB operations
  • - *
  • writePrecision - precision to use when writing points to InfluxDB
  • + *
  • writePrecision - precision to use when writing points to InfluxDB. + * This setting is ignored when writing {@link com.influxdb.v3.client.Point}; + * for those writes, the client always sends {@link WritePrecision#NS} + * precision to the server.
  • *
  • defaultTags - defaultTags added when writing points to InfluxDB
  • *
  • gzipThreshold - threshold when gzip compression is used for writing points to InfluxDB
  • *
  • writeNoSync - skip waiting for WAL persistence on write
  • @@ -548,7 +551,10 @@ public Builder database(@Nullable final String database) { * if no precision is specified in the write API call. * * @param writePrecision default precision to use for the timestamp of points - * if no precision is specified in the write API call + * if no precision is specified in the write API call. + * This setting is ignored when writing {@link com.influxdb.v3.client.Point}; + * for those writes, the client always sends {@link WritePrecision#NS} + * precision to the server. * @return this */ @Nonnull diff --git a/src/main/java/com/influxdb/v3/client/internal/InfluxDBClientImpl.java b/src/main/java/com/influxdb/v3/client/internal/InfluxDBClientImpl.java index 3dc05155..5880549c 100644 --- a/src/main/java/com/influxdb/v3/client/internal/InfluxDBClientImpl.java +++ b/src/main/java/com/influxdb/v3/client/internal/InfluxDBClientImpl.java @@ -304,7 +304,14 @@ private void writeData(@Nonnull final List data, @Nonnull final WriteOpti + "or use default configuration at 'ClientConfig.database'."); } - WritePrecision precision = options.precisionSafe(config); + WritePrecision precision; + + if (isWritePoint(data)) { + // When writing Point(s), the timestamp is always converted to nanoseconds. + precision = WritePrecision.NS; + } else { + precision = options.precisionSafe(config); + } options.validate(config); String path; @@ -472,4 +479,13 @@ private byte[] gzipData(@Nonnull final byte[] data) throws IOException { return out.toByteArray(); } + + private boolean isWritePoint(@Nonnull final List data) { + for (T writeAble : data) { + if (writeAble instanceof Point) { + return true; + } + } + return false; + } } diff --git a/src/main/java/com/influxdb/v3/client/write/WriteOptions.java b/src/main/java/com/influxdb/v3/client/write/WriteOptions.java index 00618ec1..7faf0428 100644 --- a/src/main/java/com/influxdb/v3/client/write/WriteOptions.java +++ b/src/main/java/com/influxdb/v3/client/write/WriteOptions.java @@ -40,7 +40,9 @@ *
      *
    • database - specifies the database to be used for InfluxDB operations
    • *
    • organization - specifies the organization to be used for InfluxDB operations
    • - *
    • precision - specifies the precision to use for the timestamp of points
    • + *
    • precision - specifies the precision to use for timestamps in line protocol records. + * This setting is ignored when writing {@link com.influxdb.v3.client.Point}; for those writes, the client + * always sends {@link WritePrecision#NS} precision to the server.
    • *
    • defaultTags - specifies tags to be added by default to all write operations using points.
    • *
    • tagOrder - specifies preferred tag order for point serialization.
    • *
    • noSync - skip waiting for WAL persistence on write
    • @@ -124,6 +126,9 @@ public static WriteOptions defaultWriteOptions() { * If it is not specified then use {@link ClientConfig#getDatabase()}. * @param precision The precision to use for the timestamp of points. * If it is not specified then use {@link ClientConfig#getWritePrecision()}. + * This setting is ignored when writing {@link com.influxdb.v3.client.Point}; + * for those writes, the client always sends {@link WritePrecision#NS} + * precision to the server. * @param gzipThreshold The threshold for compressing request body. * If it is not specified then use {@link WriteOptions#DEFAULT_GZIP_THRESHOLD}. */ @@ -140,6 +145,9 @@ public WriteOptions(@Nullable final String database, * If it is not specified then use {@link ClientConfig#getDatabase()}. * @param precision The precision to use for the timestamp of points. * If it is not specified then use {@link ClientConfig#getWritePrecision()}. + * This setting is ignored when writing {@link com.influxdb.v3.client.Point}; + * for those writes, the client always sends {@link WritePrecision#NS} + * precision to the server. * @param gzipThreshold The threshold for compressing request body. * If it is not specified then use {@link WriteOptions#DEFAULT_GZIP_THRESHOLD}. * @param defaultTags Default tags to be added when writing points. @@ -158,6 +166,9 @@ public WriteOptions(@Nullable final String database, * If it is not specified then use {@link ClientConfig#getDatabase()}. * @param precision The precision to use for the timestamp of points. * If it is not specified then use {@link ClientConfig#getWritePrecision()}. + * This setting is ignored when writing {@link com.influxdb.v3.client.Point}; + * for those writes, the client always sends {@link WritePrecision#NS} + * precision to the server. * @param gzipThreshold The threshold for compressing request body. * If it is not specified then use {@link WriteOptions#DEFAULT_GZIP_THRESHOLD}. * @param noSync Skip waiting for WAL persistence on write. @@ -187,6 +198,9 @@ public WriteOptions(@Nullable final Map headers) { * If it is not specified then use {@link ClientConfig#getDatabase()}. * @param precision The precision to use for the timestamp of points. * If it is not specified then use {@link ClientConfig#getWritePrecision()}. + * This setting is ignored when writing {@link com.influxdb.v3.client.Point}; + * for those writes, the client always sends {@link WritePrecision#NS} + * precision to the server. * @param gzipThreshold The threshold for compressing request body. * If it is not specified then use {@link WriteOptions#DEFAULT_GZIP_THRESHOLD}. * @param defaultTags Default tags to be added when writing points. @@ -209,6 +223,9 @@ public WriteOptions(@Nullable final String database, * If it is not specified then use {@link ClientConfig#getDatabase()}. * @param precision The precision to use for the timestamp of points. * If it is not specified then use {@link ClientConfig#getWritePrecision()}. + * This setting is ignored when writing {@link com.influxdb.v3.client.Point}; + * for those writes, the client always sends {@link WritePrecision#NS} + * precision to the server. * @param gzipThreshold The threshold for compressing request body. * If it is not specified then use {@link WriteOptions#DEFAULT_GZIP_THRESHOLD}. * @param noSync Skip waiting for WAL persistence on write. @@ -234,6 +251,9 @@ public WriteOptions(@Nullable final String database, * If it is not specified then use {@link ClientConfig#getDatabase()}. * @param precision The precision to use for the timestamp of points. * If it is not specified then use {@link ClientConfig#getWritePrecision()}. + * This setting is ignored when writing {@link com.influxdb.v3.client.Point}; + * for those writes, the client always sends {@link WritePrecision#NS} + * precision to the server. * @param gzipThreshold The threshold for compressing request body. * If it is not specified then use {@link WriteOptions#DEFAULT_GZIP_THRESHOLD}. * @param noSync Skip waiting for WAL persistence on write. @@ -265,6 +285,9 @@ public WriteOptions(@Nullable final String database, * If it is not specified then use {@link ClientConfig#getDatabase()}. * @param precision The precision to use for the timestamp of points. * If it is not specified then use {@link ClientConfig#getWritePrecision()}. + * This setting is ignored when writing {@link com.influxdb.v3.client.Point}; + * for those writes, the client always sends {@link WritePrecision#NS} + * precision to the server. * @param gzipThreshold The threshold for compressing request body. * If it is not specified then use {@link WriteOptions#DEFAULT_GZIP_THRESHOLD}. * @param noSync Skip waiting for WAL persistence on write. @@ -307,6 +330,9 @@ public WriteOptions(@Nullable final String database, * If it is not specified then use {@link ClientConfig#getDatabase()}. * @param precision The precision to use for the timestamp of points. * If it is not specified then use {@link ClientConfig#getWritePrecision()}. + * This setting is ignored when writing {@link com.influxdb.v3.client.Point}; + * for those writes, the client always sends {@link WritePrecision#NS} + * precision to the server. * @param gzipThreshold The threshold for compressing request body. * If it is not specified then use {@link WriteOptions#DEFAULT_GZIP_THRESHOLD}. * @param noSync Skip waiting for WAL persistence on write. diff --git a/src/test/java/com/influxdb/v3/client/InfluxDBClientWriteTest.java b/src/test/java/com/influxdb/v3/client/InfluxDBClientWriteTest.java index 4382b646..4d94738d 100644 --- a/src/test/java/com/influxdb/v3/client/InfluxDBClientWriteTest.java +++ b/src/test/java/com/influxdb/v3/client/InfluxDBClientWriteTest.java @@ -412,7 +412,10 @@ void writePointWithDefaultWriteOptionsCustomConfig() throws Exception { client.writePoint(point); } - checkWriteCalled("/api/v3/write_lp", "DB", "second", true, "true", null, true); + // When writing Point, precision sent to the server is always nanosecond + var expectedPrecision = "nanosecond"; + + checkWriteCalled("/api/v3/write_lp", "DB", expectedPrecision, true, "true", null, true); } @Test @@ -447,7 +450,10 @@ void writePointsWithDefaultWriteOptionsCustomConfig() throws Exception { client.writePoints(List.of(point)); } - checkWriteCalled("/api/v3/write_lp", "DB", "second", true, "true", null, true); + // When writing Point, precision sent to the server is always nanosecond + var expectedPrecision = "nanosecond"; + + checkWriteCalled("/api/v3/write_lp", "DB", expectedPrecision, true, "true", null, true); } private void checkWriteCalled(final String expectedPath, final String expectedDB, diff --git a/src/test/java/com/influxdb/v3/client/integration/E2ETest.java b/src/test/java/com/influxdb/v3/client/integration/E2ETest.java index dc02f7da..cba42021 100644 --- a/src/test/java/com/influxdb/v3/client/integration/E2ETest.java +++ b/src/test/java/com/influxdb/v3/client/integration/E2ETest.java @@ -595,10 +595,43 @@ public void testMultipleQueries() throws Exception { } } } - - } + @EnabledIfEnvironmentVariable(named = "TESTING_INFLUXDB_URL", matches = ".*") + @EnabledIfEnvironmentVariable(named = "TESTING_INFLUXDB_TOKEN", matches = ".*") + @EnabledIfEnvironmentVariable(named = "TESTING_INFLUXDB_DATABASE", matches = ".*") + @Test + public void testWriteWithDifferentTimeUnit() throws Exception { + try (InfluxDBClient client = InfluxDBClient.getInstance( + System.getenv("TESTING_INFLUXDB_URL"), + System.getenv("TESTING_INFLUXDB_TOKEN").toCharArray(), + System.getenv("TESTING_INFLUXDB_DATABASE"), + null)) { + var writeOptions = new WriteOptions.Builder().precision(WritePrecision.MS).build(); + String measurement = "test_" + UUID.randomUUID(); + List points = List.of( + Point.measurement(measurement) + .setTag("type", "test") + .setFloatField("rads", 3.14) + .setIntegerField("life", 42) + .setTimestamp(Instant.now().toEpochMilli(), WritePrecision.MS), + Point.measurement(measurement) + .setTag("type", "test") + .setFloatField("rads", 3.14) + .setIntegerField("life", 12) + .setTimestamp(Instant.now().plusSeconds(1).getEpochSecond(), WritePrecision.S), + Point.measurement(measurement) + .setTag("type", "test") + .setFloatField("rads", 3.14) + .setIntegerField("life", 432) + .setTimestamp(Instant.now().plusSeconds(2).toEpochMilli() * 1000, WritePrecision.US) + ); + client.writePoints(points, writeOptions); + var results = client.queryPoints(String.format("select * from \"%s\"", measurement)) + .collect(Collectors.toList()); + Assertions.assertThat(results).hasSize(3); + } + } private void assertGetDataSuccess(@Nonnull final InfluxDBClient influxDBClient) { influxDBClient.writePoint(