diff --git a/hub/internal/store/store.go b/hub/internal/store/store.go index 1f54899..8d59cad 100644 --- a/hub/internal/store/store.go +++ b/hub/internal/store/store.go @@ -148,7 +148,7 @@ func (s *Store) GetCustomers() ([]CustomerSummary, error) { return nil, err } - c.ReceivedAt, _ = time.Parse("2006-01-02 15:04:05", receivedAt) + c.ReceivedAt = parseSQLiteTime(receivedAt) c.TimeSinceReport = time.Since(c.ReceivedAt) if backupSnapshot.Valid { @@ -199,7 +199,7 @@ func (s *Store) GetCustomer(customerID string) (*CustomerSummary, error) { return nil, err } - c.ReceivedAt, _ = time.Parse("2006-01-02 15:04:05", receivedAt) + c.ReceivedAt = parseSQLiteTime(receivedAt) c.TimeSinceReport = time.Since(c.ReceivedAt) if backupSnapshot.Valid { @@ -250,7 +250,7 @@ func (s *Store) GetCustomerHistory(customerID string, since time.Duration) ([]Cu return nil, err } - c.ReceivedAt, _ = time.Parse("2006-01-02 15:04:05", receivedAt) + c.ReceivedAt = parseSQLiteTime(receivedAt) c.TimeSinceReport = time.Since(c.ReceivedAt) if backupSnapshot.Valid { @@ -280,6 +280,28 @@ func (s *Store) Close() error { 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 { var report struct { Storage []struct {