fix: use explicit UTC formatting in ClickHouse DateTime literals
Timestamp.toString() uses JVM local timezone which can mismatch with ClickHouse's UTC timezone, causing time-filtered queries to return empty results. Replaced with DateTimeFormatter.withZone(UTC) in all lit() methods. Also added warn logging to RouteCatalogController catch blocks to surface query errors instead of silently swallowing them. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -297,9 +297,8 @@ public class AgentRegistrationController {
|
||||
|
||||
/** Format an Instant as a ClickHouse DateTime literal. */
|
||||
private static String lit(Instant instant) {
|
||||
Instant truncated = instant.truncatedTo(ChronoUnit.SECONDS);
|
||||
String ts = new Timestamp(truncated.toEpochMilli()).toString();
|
||||
if (ts.endsWith(".0")) ts = ts.substring(0, ts.length() - 2);
|
||||
return "'" + ts + "'";
|
||||
return "'" + java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
|
||||
.withZone(java.time.ZoneOffset.UTC)
|
||||
.format(instant.truncatedTo(ChronoUnit.SECONDS)) + "'";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +35,8 @@ import java.util.stream.Collectors;
|
||||
@Tag(name = "Route Catalog", description = "Route catalog and discovery")
|
||||
public class RouteCatalogController {
|
||||
|
||||
private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(RouteCatalogController.class);
|
||||
|
||||
private final AgentRegistryService registryService;
|
||||
private final DiagramStore diagramStore;
|
||||
private final JdbcTemplate jdbc;
|
||||
@@ -94,7 +96,7 @@ public class RouteCatalogController {
|
||||
if (ts != null) routeLastSeen.put(key, ts.toInstant());
|
||||
});
|
||||
} catch (Exception e) {
|
||||
// AggregatingMergeTree table may not exist yet
|
||||
log.warn("Failed to query route exchange counts: {}", e.getMessage());
|
||||
}
|
||||
|
||||
// Per-agent TPS from the last minute
|
||||
@@ -157,12 +159,11 @@ public class RouteCatalogController {
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
/** Format an Instant as a ClickHouse DateTime literal. */
|
||||
/** Format an Instant as a ClickHouse DateTime literal in UTC. */
|
||||
private static String lit(Instant instant) {
|
||||
Instant truncated = instant.truncatedTo(ChronoUnit.SECONDS);
|
||||
String ts = new Timestamp(truncated.toEpochMilli()).toString();
|
||||
if (ts.endsWith(".0")) ts = ts.substring(0, ts.length() - 2);
|
||||
return "'" + ts + "'";
|
||||
return "'" + java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
|
||||
.withZone(java.time.ZoneOffset.UTC)
|
||||
.format(instant.truncatedTo(ChronoUnit.SECONDS)) + "'";
|
||||
}
|
||||
|
||||
private String computeWorstHealth(List<AgentInfo> agents) {
|
||||
|
||||
@@ -187,10 +187,9 @@ public class RouteMetricsController {
|
||||
|
||||
/** Format an Instant as a ClickHouse DateTime literal. */
|
||||
private static String lit(Instant instant) {
|
||||
Instant truncated = instant.truncatedTo(ChronoUnit.SECONDS);
|
||||
String ts = new Timestamp(truncated.toEpochMilli()).toString();
|
||||
if (ts.endsWith(".0")) ts = ts.substring(0, ts.length() - 2);
|
||||
return "'" + ts + "'";
|
||||
return "'" + java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
|
||||
.withZone(java.time.ZoneOffset.UTC)
|
||||
.format(instant.truncatedTo(ChronoUnit.SECONDS)) + "'";
|
||||
}
|
||||
|
||||
/** Format a string as a SQL literal with single-quote escaping. */
|
||||
|
||||
@@ -299,12 +299,9 @@ public class ClickHouseStatsStore implements StatsStore {
|
||||
* column compatibility.
|
||||
*/
|
||||
private static String lit(Instant instant) {
|
||||
// Truncate to seconds — ClickHouse DateTime has second precision
|
||||
Instant truncated = instant.truncatedTo(ChronoUnit.SECONDS);
|
||||
String ts = new Timestamp(truncated.toEpochMilli()).toString();
|
||||
// Remove trailing ".0" that Timestamp.toString() always appends
|
||||
if (ts.endsWith(".0")) ts = ts.substring(0, ts.length() - 2);
|
||||
return "'" + ts + "'";
|
||||
return "'" + java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
|
||||
.withZone(java.time.ZoneOffset.UTC)
|
||||
.format(instant.truncatedTo(ChronoUnit.SECONDS)) + "'";
|
||||
}
|
||||
|
||||
/** Format a string as a SQL literal with single-quote escaping. */
|
||||
|
||||
Reference in New Issue
Block a user