diff --git a/db/src/rest/rest.go b/db/src/rest/rest.go index c02824c..fb46a9f 100644 --- a/db/src/rest/rest.go +++ b/db/src/rest/rest.go @@ -13,6 +13,7 @@ import ( "strings" "time" + "github.com/apache/arrow-go/v18/arrow" "github.com/gin-contrib/cors" "github.com/gin-gonic/gin" swaggerFiles "github.com/swaggo/files" @@ -298,6 +299,20 @@ func formatField(v any) string { } } +// formatTime normalizes a time value (possibly a nanosecond int64) into an RFC3339 UTC string. +func formatTime(v any) any { + switch t := v.(type) { + case time.Time: + return t.UTC().Format(time.RFC3339) + case arrow.Timestamp: + return time.Unix(0, int64(t)).UTC().Format(time.RFC3339) + case int64: + return time.Unix(0, t).UTC().Format(time.RFC3339) + default: + return v + } +} + func (g *RestGateway) Run(addr string) error { return g.engine.Run(addr) } @@ -343,7 +358,7 @@ func (g *RestGateway) getRoomCurrent(c *gin.Context) { // Get the last record for the specific room by matching node IDs, aggregated by 5m intervals query := fmt.Sprintf(` SELECT - date_bin(INTERVAL '5 minutes', time) AS time, + date_bin(INTERVAL '5 minutes', time)::TIMESTAMP AS time, ROUND(AVG(co2_ppm)) AS co2_ppm, ROUND(AVG(temp), 2) AS temp, ROUND(AVG(humidity), 2) AS humidity, @@ -367,6 +382,9 @@ func (g *RestGateway) getRoomCurrent(c *gin.Context) { if it.Next() { val := it.Value() val["room"] = roomID + if t, ok := val["time"]; ok { + val["time"] = formatTime(t) + } c.JSON(http.StatusOK, val) return } @@ -404,7 +422,7 @@ func (g *RestGateway) getRoomHistory(c *gin.Context) { query := fmt.Sprintf(` SELECT - date_bin(INTERVAL '5 minutes', time) AS time, + date_bin(INTERVAL '5 minutes', time)::TIMESTAMP AS time, ROUND(AVG(co2_ppm)) AS co2_ppm, ROUND(AVG(temp), 2) AS temp, ROUND(AVG(humidity), 2) AS humidity, @@ -428,6 +446,9 @@ func (g *RestGateway) getRoomHistory(c *gin.Context) { for it.Next() { val := it.Value() val["room"] = roomID + if t, ok := val["time"]; ok { + val["time"] = formatTime(t) + } history = append(history, val) }