fix: format daily metric query timestamps

This commit is contained in:
lingniu
2026-07-01 23:33:03 +08:00
parent 1a53011408
commit 56f4811c68
2 changed files with 49 additions and 5 deletions

View File

@@ -9,6 +9,7 @@ import (
"net/http" "net/http"
"strconv" "strconv"
"strings" "strings"
"time"
) )
type Queryer interface { type Queryer interface {
@@ -63,11 +64,14 @@ func (r *MetricRepository) Query(ctx context.Context, query MetricQuery) ([]Metr
var out []MetricRow var out []MetricRow
for rows.Next() { for rows.Next() {
var row MetricRow var row MetricRow
var statDate scanDate
var createdAt scanDateTime
var updatedAt scanDateTime
var first sql.NullFloat64 var first sql.NullFloat64
var latest sql.NullFloat64 var latest sql.NullFloat64
if err := rows.Scan( if err := rows.Scan(
&row.VIN, &row.VIN,
&row.StatDate, &statDate,
&row.Protocol, &row.Protocol,
&row.MetricKey, &row.MetricKey,
&row.MetricValue, &row.MetricValue,
@@ -76,11 +80,14 @@ func (r *MetricRepository) Query(ctx context.Context, query MetricQuery) ([]Metr
&latest, &latest,
&row.SampleCount, &row.SampleCount,
&row.CalculationMethod, &row.CalculationMethod,
&row.CreatedAt, &createdAt,
&row.UpdatedAt, &updatedAt,
); err != nil { ); err != nil {
return nil, err return nil, err
} }
row.StatDate = statDate.String
row.CreatedAt = createdAt.String
row.UpdatedAt = updatedAt.String
if first.Valid { if first.Valid {
row.FirstTotalMileageKM = &first.Float64 row.FirstTotalMileageKM = &first.Float64
} }
@@ -239,3 +246,36 @@ func writeMetricError(w http.ResponseWriter, status int, message string) {
w.WriteHeader(status) w.WriteHeader(status)
_ = json.NewEncoder(w).Encode(map[string]any{"error": message}) _ = json.NewEncoder(w).Encode(map[string]any{"error": message})
} }
type scanDate struct {
String string
}
func (s *scanDate) Scan(value any) error {
s.String = formatSQLTime(value, "2006-01-02")
return nil
}
type scanDateTime struct {
String string
}
func (s *scanDateTime) Scan(value any) error {
s.String = formatSQLTime(value, "2006-01-02 15:04:05")
return nil
}
func formatSQLTime(value any, layout string) string {
switch typed := value.(type) {
case nil:
return ""
case time.Time:
return typed.Format(layout)
case []byte:
return strings.TrimSpace(string(typed))
case string:
return strings.TrimSpace(typed)
default:
return strings.TrimSpace(fmt.Sprint(typed))
}
}

View File

@@ -7,6 +7,7 @@ import (
"net/http/httptest" "net/http/httptest"
"strings" "strings"
"testing" "testing"
"time"
"github.com/DATA-DOG/go-sqlmock" "github.com/DATA-DOG/go-sqlmock"
) )
@@ -24,8 +25,8 @@ func TestMetricRepositoryQueriesDailyMetricsWithFilters(t *testing.T) {
"first_total_mileage_km", "latest_total_mileage_km", "sample_count", "calculation_method", "first_total_mileage_km", "latest_total_mileage_km", "sample_count", "calculation_method",
"created_at", "updated_at", "created_at", "updated_at",
}).AddRow( }).AddRow(
"LKLG7C4E3NA774736", "2026-07-01", "JT808", MetricDailyTotalMileageKM, 12345.6, "km", "LKLG7C4E3NA774736", time.Date(2026, 7, 1, 0, 0, 0, 0, time.FixedZone("Asia/Shanghai", 8*3600)), "JT808", MetricDailyTotalMileageKM, 12345.6, "km",
12345.6, 12345.6, 13, "TOTAL_MILEAGE_DIFF", "2026-07-01 22:49:11", "2026-07-01 23:09:36", 12345.6, 12345.6, 13, "TOTAL_MILEAGE_DIFF", time.Date(2026, 7, 1, 22, 49, 11, 0, time.FixedZone("Asia/Shanghai", 8*3600)), time.Date(2026, 7, 1, 23, 9, 36, 0, time.FixedZone("Asia/Shanghai", 8*3600)),
)) ))
repository := NewMetricRepository(db) repository := NewMetricRepository(db)
@@ -45,6 +46,9 @@ func TestMetricRepositoryQueriesDailyMetricsWithFilters(t *testing.T) {
if rows[0].MetricKey != MetricDailyTotalMileageKM || rows[0].MetricValue != 12345.6 { if rows[0].MetricKey != MetricDailyTotalMileageKM || rows[0].MetricValue != 12345.6 {
t.Fatalf("unexpected row: %#v", rows[0]) t.Fatalf("unexpected row: %#v", rows[0])
} }
if rows[0].StatDate != "2026-07-01" || rows[0].UpdatedAt != "2026-07-01 23:09:36" {
t.Fatalf("unexpected time formatting: %#v", rows[0])
}
if err := mock.ExpectationsWereMet(); err != nil { if err := mock.ExpectationsWereMet(); err != nil {
t.Fatalf("sql expectations: %v", err) t.Fatalf("sql expectations: %v", err)
} }