// FILE: ./internal/normalizers/openmeteo/common.go package openmeteo import ( "fmt" "strings" "time" ) // parseOpenMeteoTime parses Open-Meteo timestamps. // // Open-Meteo commonly returns "YYYY-MM-DDTHH:MM" (no timezone suffix) when timezone // is provided separately. When a timezone suffix is present (RFC3339), we accept it too. // // This is provider-specific because it relies on Open-Meteo's timezone and offset fields. func parseOpenMeteoTime(s string, tz string, utcOffsetSeconds int) (time.Time, error) { s = strings.TrimSpace(s) if s == "" { return time.Time{}, fmt.Errorf("empty time") } // If the server returned an RFC3339 timestamp with timezone, treat it as authoritative. if t, err := time.Parse(time.RFC3339, s); err == nil { return t, nil } // Typical Open-Meteo format: "2006-01-02T15:04" const layout = "2006-01-02T15:04" // Best effort: try to load the timezone as an IANA name. if tz != "" { if loc, err := time.LoadLocation(tz); err == nil { return time.ParseInLocation(layout, s, loc) } } // Fallback: use a fixed zone from the offset seconds. loc := time.FixedZone("open-meteo", utcOffsetSeconds) return time.ParseInLocation(layout, s, loc) }