From 0235d92b27153740669d9c399c23393e83976ce9 Mon Sep 17 00:00:00 2001 From: Zihan Dai Date: Fri, 14 Aug 2026 23:20:24 +1000 Subject: [PATCH] Correct the date_bin timezone statement in IoTDBTableTimeseriesDao's Javadoc The Javadoc said date_bin "computes in the server's UTC zone only". That is wrong: DateBinFunctionColumnTransformer does its calendar arithmetic in a ZoneId, and ColumnTransformerBuilder passes context.sessionInfo.getZoneId() identically at v2.0.8 and on master. It was never UTC-only. The surrounding design decision is unchanged, but its reason is different and this is the accurate one: the zone is session-scoped and fixed when the session pool is built, so a pooled session cannot rebind it per query, while each ReadTsKvQuery carries its own tzId. Walking the calendar boundaries in Java remains necessary. Comment-only change. --- .../table/IoTDBTableTimeseriesDao.java | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/iotdb-thingsboard-table/src/main/java/org/apache/iotdb/extras/thingsboard/table/IoTDBTableTimeseriesDao.java b/iotdb-thingsboard-table/src/main/java/org/apache/iotdb/extras/thingsboard/table/IoTDBTableTimeseriesDao.java index 96387db..f7c9a27 100644 --- a/iotdb-thingsboard-table/src/main/java/org/apache/iotdb/extras/thingsboard/table/IoTDBTableTimeseriesDao.java +++ b/iotdb-thingsboard-table/src/main/java/org/apache/iotdb/extras/thingsboard/table/IoTDBTableTimeseriesDao.java @@ -389,14 +389,16 @@ private ReadTsKvQueryResult readMillisecondsAggregatedQuery( *

IoTDB 2.0.8's native {@code date_bin} calendar primitive cannot reproduce ThingsBoard's * boundaries: it anchors each calendar bucket on the origin's day-of-month (so {@code * date_bin(1mo, time, startTs)} from a mid-month {@code startTs} steps day-15 → day-15, not to - * the 1st of each month) and it exposes no timezone argument (it computes in the - * server's UTC zone only). ThingsBoard instead advances {@code startTs} to the start of the next - * calendar unit in {@code tzId} via {@link TimeUtils#calculateIntervalEnd}, so the first bucket - * is the partial {@code [startTs, nextCalendarBoundary)} and later buckets are full calendar - * units. This path therefore reproduces ThingsBoard exactly the way ThingsBoard itself does: it - * walks the calendar boundaries in Java and issues one bounded aggregate query per bucket - * (ThingsBoard issues one future per bucket), reusing the very same projection, row mapper and - * typed-COUNT logic as the {@code MILLISECONDS} path. + * the 1st of each month) and it exposes no timezone argument — its calendar arithmetic + * runs in the session's zone, which is fixed when the session pool is built and cannot + * be rebound per query, while each {@link ReadTsKvQuery} carries its own {@code tzId}. + * ThingsBoard instead advances {@code startTs} to the start of the next calendar unit in {@code + * tzId} via {@link TimeUtils#calculateIntervalEnd}, so the first bucket is the partial {@code + * [startTs, nextCalendarBoundary)} and later buckets are full calendar units. This path therefore + * reproduces ThingsBoard exactly the way ThingsBoard itself does: it walks the calendar + * boundaries in Java and issues one bounded aggregate query per bucket (ThingsBoard issues one + * future per bucket), reusing the very same projection, row mapper and typed-COUNT logic as the + * {@code MILLISECONDS} path. * *

Walking {@code [startTs, endPeriod)} where {@code endPeriod = max(startTs + 1, endTs)}: each * iteration takes {@code bucketStart = startPeriod}, {@code bucketEnd = min(calculateIntervalEnd(