Copilot commented on code in PR #17387:
URL: https://github.com/apache/iotdb/pull/17387#discussion_r3048921237
##########
external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/filter/AuthorizationFilter.java:
##########
@@ -147,6 +154,33 @@ private User checkLogin(
return user;
}
+ /**
+ * Resolves the Time-Zone header from the request.
+ *
+ * @param requestContext the incoming HTTP request
+ * @return the resolved ZoneId, or {@code null} if the header is invalid
(the request is aborted)
+ */
+ private ZoneId resolveTimeZone(ContainerRequestContext requestContext) {
+ String timeZoneHeader = requestContext.getHeaderString("Time-Zone");
+ if (timeZoneHeader == null || timeZoneHeader.isEmpty()) {
+ return ZoneId.systemDefault();
+ }
Review Comment:
PR description mentions supporting an `X-TimeZone` header, but the
implementation reads `Time-Zone` only. If clients (or the issue) expect
`X-TimeZone`, requests will be ignored and the session will continue using the
system default. Consider either updating the PR description and examples to
match `Time-Zone`, or accepting both headers (e.g., prefer `Time-Zone` then
fall back to `X-TimeZone`) for compatibility.
##########
external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/filter/AuthorizationFilter.java:
##########
@@ -147,6 +154,33 @@ private User checkLogin(
return user;
}
+ /**
+ * Resolves the Time-Zone header from the request.
+ *
+ * @param requestContext the incoming HTTP request
+ * @return the resolved ZoneId, or {@code null} if the header is invalid
(the request is aborted)
+ */
+ private ZoneId resolveTimeZone(ContainerRequestContext requestContext) {
+ String timeZoneHeader = requestContext.getHeaderString("Time-Zone");
+ if (timeZoneHeader == null || timeZoneHeader.isEmpty()) {
+ return ZoneId.systemDefault();
+ }
+ try {
+ return ZoneId.of(timeZoneHeader);
+ } catch (DateTimeException e) {
Review Comment:
`timeZoneHeader` is used as-is for parsing. If the header is present but
contains only whitespace (or has leading/trailing spaces), `ZoneId.of(...)`
will throw and the request will be rejected. Consider trimming the header value
before validation/parsing so common client formatting issues don’t cause a 400.
##########
integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBRestServiceIT.java:
##########
@@ -2354,4 +2363,206 @@ public void queryDateAndBlobV2(CloseableHttpClient
httpClient) {
}
}
}
+
+ public void queryWithValidTimeZoneHeader(CloseableHttpClient httpClient) {
+ CloseableHttpResponse response = null;
+ try {
+ HttpPost httpPost = getHttpPost("http://127.0.0.1:" + port +
"/rest/v1/query");
+ httpPost.setHeader("Time-Zone", "+05:00");
+ String sql =
+ "{\"sql\":\"SELECT count(s3) FROM root.sg25 GROUP BY
([2026-03-28T00:00:00, 2026-03-29T00:00:00), 1d)\"}";
+ httpPost.setEntity(new StringEntity(sql, Charset.defaultCharset()));
+ response = httpClient.execute(httpPost);
+ assertEquals(200, response.getStatusLine().getStatusCode());
+ String message = EntityUtils.toString(response.getEntity(), "utf-8");
+ JsonObject result = JsonParser.parseString(message).getAsJsonObject();
+ assertTrue(result.has("timestamps"));
+ assertTrue(result.getAsJsonArray("timestamps").size() > 0);
+ long expectedTimestamp =
+ ZonedDateTime.of(2026, 3, 28, 0, 0, 0, 0,
ZoneId.of("+05:00")).toInstant().toEpochMilli();
+ assertEquals(expectedTimestamp,
result.getAsJsonArray("timestamps").get(0).getAsLong());
Review Comment:
The GROUP BY time range here uses 2026-03-28/2026-03-29, but the test data
inserted into root.sg25 earlier in this IT uses fixed timestamps
1635232143960/1635232153960 (~2021-10-26). As a result, this query will likely
return an empty result set and fail the `timestamps.size() > 0` assertion.
Consider changing the query time range (and expectedTimestamp) to align with
the inserted data, or insert additional rows for root.sg25 within the queried
range before asserting on the first window timestamp.
##########
integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBRestServiceIT.java:
##########
@@ -2354,4 +2363,206 @@ public void queryDateAndBlobV2(CloseableHttpClient
httpClient) {
}
}
}
+
+ public void queryWithValidTimeZoneHeader(CloseableHttpClient httpClient) {
+ CloseableHttpResponse response = null;
+ try {
+ HttpPost httpPost = getHttpPost("http://127.0.0.1:" + port +
"/rest/v1/query");
+ httpPost.setHeader("Time-Zone", "+05:00");
+ String sql =
+ "{\"sql\":\"SELECT count(s3) FROM root.sg25 GROUP BY
([2026-03-28T00:00:00, 2026-03-29T00:00:00), 1d)\"}";
+ httpPost.setEntity(new StringEntity(sql, Charset.defaultCharset()));
+ response = httpClient.execute(httpPost);
+ assertEquals(200, response.getStatusLine().getStatusCode());
+ String message = EntityUtils.toString(response.getEntity(), "utf-8");
+ JsonObject result = JsonParser.parseString(message).getAsJsonObject();
+ assertTrue(result.has("timestamps"));
+ assertTrue(result.getAsJsonArray("timestamps").size() > 0);
+ long expectedTimestamp =
+ ZonedDateTime.of(2026, 3, 28, 0, 0, 0, 0,
ZoneId.of("+05:00")).toInstant().toEpochMilli();
+ assertEquals(expectedTimestamp,
result.getAsJsonArray("timestamps").get(0).getAsLong());
+ } catch (IOException e) {
+ e.printStackTrace();
+ fail(e.getMessage());
+ } finally {
+ try {
+ if (response != null) {
+ response.close();
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ fail(e.getMessage());
+ }
+ }
+ }
+
+ public void nonQueryWithValidTimeZoneHeader(CloseableHttpClient httpClient) {
+ CloseableHttpResponse response = null;
+ try {
+ HttpPost createPost = getHttpPost("http://127.0.0.1:" + port +
"/rest/v1/nonQuery");
+ nonQuery(
+ httpClient,
+ "{\"sql\":\"CREATE TIMESERIES root.sg_tz.d1.s1 WITH
DATATYPE=INT32\"}",
+ createPost);
+
+ HttpPost insertPost = getHttpPost("http://127.0.0.1:" + port +
"/rest/v1/nonQuery");
+ insertPost.setHeader("Time-Zone", "+05:00");
+ nonQuery(
+ httpClient,
+ "{\"sql\":\"INSERT INTO root.sg_tz.d1(time, s1) VALUES
(2026-03-28T00:00:00, 123)\"}",
+ insertPost);
+
+ HttpPost queryPost = getHttpPost("http://127.0.0.1:" + port +
"/rest/v1/query");
+ queryPost.setEntity(
+ new StringEntity("{\"sql\":\"SELECT s1 FROM root.sg_tz.d1\"}",
StandardCharsets.UTF_8));
+ response = httpClient.execute(queryPost);
+ String message = EntityUtils.toString(response.getEntity(),
StandardCharsets.UTF_8);
+ JsonObject result = JsonParser.parseString(message).getAsJsonObject();
+ long expected =
+ ZonedDateTime.of(2026, 3, 28, 0, 0, 0, 0,
ZoneId.of("+05:00")).toInstant().toEpochMilli();
+ assertEquals(expected,
result.getAsJsonArray("timestamps").get(0).getAsLong());
+
+ } catch (IOException e) {
+ e.printStackTrace();
+ fail(e.getMessage());
+ } finally {
+ try {
+ if (response != null) {
+ response.close();
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ fail(e.getMessage());
+ }
+ }
+ }
+
+ public void queryWithValidTimeZoneHeaderV2(CloseableHttpClient httpClient) {
+ CloseableHttpResponse response = null;
+ try {
+ HttpPost httpPost = getHttpPost("http://127.0.0.1:" + port +
"/rest/v2/query");
+ httpPost.setHeader("Time-Zone", "+05:00");
+ String sql =
+ "{\"sql\":\"SELECT count(s3) FROM root.sg25 GROUP BY
([2026-03-28T00:00:00, 2026-03-29T00:00:00), 1d)\"}";
+ httpPost.setEntity(new StringEntity(sql, Charset.defaultCharset()));
+ response = httpClient.execute(httpPost);
+ assertEquals(200, response.getStatusLine().getStatusCode());
+ String message = EntityUtils.toString(response.getEntity(), "utf-8");
+ JsonObject result = JsonParser.parseString(message).getAsJsonObject();
+ assertTrue(result.has("timestamps"));
+ assertTrue(result.getAsJsonArray("timestamps").size() > 0);
+ long expectedTimestamp =
+ ZonedDateTime.of(2026, 3, 28, 0, 0, 0, 0,
ZoneId.of("+05:00")).toInstant().toEpochMilli();
+ assertEquals(expectedTimestamp,
result.getAsJsonArray("timestamps").get(0).getAsLong());
Review Comment:
Same issue as the v1 test: this GROUP BY time range is in 2026, but
root.sg25 test data is inserted with timestamps around 2021-10-26. This will
likely return no rows and break the `timestamps.size() > 0` assertion. Please
align the queried time range (and expectedTimestamp) with the inserted test
data, or insert data that falls into the specified 2026 range before querying.
##########
example/rest-java-example/src/main/java/org/apache/iotdb/HttpExample.java:
##########
@@ -138,4 +139,29 @@ public void query() {
}
}
}
+
+ public void queryWithTimeZone() {
+ CloseableHttpClient httpClient = SSLClient.getInstance().getHttpClient();
+ CloseableHttpResponse response = null;
+ try {
+ HttpPost httpPost = getHttpPost("http://127.0.0.1:18080/rest/v1/query");
Review Comment:
`queryWithTimeZone()` doesn’t actually send the Time-Zone header (unlike the
HTTPS and table examples). As written, this method behaves the same as
`query()` and won’t demonstrate the feature. Add the `Time-Zone` (or intended
header name) to this request so the example matches the method name and the
PR’s new behavior.
```suggestion
HttpPost httpPost =
getHttpPost("http://127.0.0.1:18080/rest/v1/query");
httpPost.setHeader("Time-Zone", "Asia/Shanghai");
```
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]