fix: robust SQLite timestamp parsing for hub dashboard

Replace hardcoded time.Parse with parseSQLiteTime() that handles multiple
formats returned by modernc.org/sqlite, fixing hub showing DOWN status
and 00:00:00 timestamps in report history.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-16 14:56:30 +01:00
parent 50d9eb66bf
commit 7f4e479c63
+25 -3
View File
@@ -148,7 +148,7 @@ func (s *Store) GetCustomers() ([]CustomerSummary, error) {
return nil, err return nil, err
} }
c.ReceivedAt, _ = time.Parse("2006-01-02 15:04:05", receivedAt) c.ReceivedAt = parseSQLiteTime(receivedAt)
c.TimeSinceReport = time.Since(c.ReceivedAt) c.TimeSinceReport = time.Since(c.ReceivedAt)
if backupSnapshot.Valid { if backupSnapshot.Valid {
@@ -199,7 +199,7 @@ func (s *Store) GetCustomer(customerID string) (*CustomerSummary, error) {
return nil, err return nil, err
} }
c.ReceivedAt, _ = time.Parse("2006-01-02 15:04:05", receivedAt) c.ReceivedAt = parseSQLiteTime(receivedAt)
c.TimeSinceReport = time.Since(c.ReceivedAt) c.TimeSinceReport = time.Since(c.ReceivedAt)
if backupSnapshot.Valid { if backupSnapshot.Valid {
@@ -250,7 +250,7 @@ func (s *Store) GetCustomerHistory(customerID string, since time.Duration) ([]Cu
return nil, err return nil, err
} }
c.ReceivedAt, _ = time.Parse("2006-01-02 15:04:05", receivedAt) c.ReceivedAt = parseSQLiteTime(receivedAt)
c.TimeSinceReport = time.Since(c.ReceivedAt) c.TimeSinceReport = time.Since(c.ReceivedAt)
if backupSnapshot.Valid { if backupSnapshot.Valid {
@@ -280,6 +280,28 @@ func (s *Store) Close() error {
return s.db.Close() return s.db.Close()
} }
// parseSQLiteTime tries multiple formats that modernc.org/sqlite may return.
func parseSQLiteTime(s string) time.Time {
formats := []string{
"2006-01-02 15:04:05", // SQLite datetime('now')
"2006-01-02T15:04:05Z", // RFC3339 without fractional
time.RFC3339, // 2006-01-02T15:04:05Z07:00
time.RFC3339Nano, // with fractional seconds
"2006-01-02 15:04:05+00:00", // with explicit UTC offset
"2006-01-02 15:04:05.999999999", // with fractional, no TZ
}
for _, f := range formats {
if t, err := time.Parse(f, s); err == nil {
return t
}
}
// Last resort: if string is non-empty, log it for debugging
if s != "" {
log.Printf("[WARN] Could not parse timestamp: %q", s)
}
return time.Time{} // zero time
}
func parseDiskSummary(reportJSON string) string { func parseDiskSummary(reportJSON string) string {
var report struct { var report struct {
Storage []struct { Storage []struct {