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]

Reply via email to