Moved shared OpenMeteo time parsing code into a shared internal/providers/openmeteo library.

This commit is contained in:
2026-01-15 10:17:56 -06:00
parent 675c5a6117
commit e92577c30e
4 changed files with 91 additions and 56 deletions

View File

@@ -2,39 +2,18 @@
package openmeteo
import (
"fmt"
"strings"
"time"
openmeteo "gitea.maximumdirect.net/ejr/weatherfeeder/internal/providers/openmeteo"
)
// 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.
// The actual parsing logic lives in internal/providers/openmeteo so both the
// source (envelope EffectiveAt / event ID) and normalizer (canonical payload)
// can share identical timestamp behavior.
//
// This is provider-specific because it relies on Open-Meteo's timezone and offset fields.
// We keep this thin wrapper to avoid churn in the normalizer package.
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)
return openmeteo.ParseTime(s, tz, utcOffsetSeconds)
}