Moved shared OpenMeteo time parsing code into a shared internal/providers/openmeteo library.
This commit is contained in:
@@ -17,10 +17,6 @@ import (
|
||||
|
||||
// ObservationSource polls an NWS station observation endpoint and emits a RAW observation Event.
|
||||
//
|
||||
// Key refactor:
|
||||
// - Source responsibility: fetch bytes + emit a valid event envelope.
|
||||
// - Normalizer responsibility: interpret raw JSON + map to canonical domain model.
|
||||
//
|
||||
// This corresponds to URLs like:
|
||||
//
|
||||
// https://api.weather.gov/stations/KSTL/observations/latest
|
||||
@@ -62,7 +58,7 @@ func (s *ObservationSource) Poll(ctx context.Context) ([]event.Event, error) {
|
||||
}
|
||||
|
||||
// Event.ID must be set BEFORE normalization (feedkit requires it).
|
||||
// Prefer NWS-provided "id" (stable URL). Fallback to a stable-ish computed key.
|
||||
// Prefer NWS-provided "id" (stable URL). Fallback to a stable computed key.
|
||||
eventID := strings.TrimSpace(meta.ID)
|
||||
if eventID == "" {
|
||||
ts := meta.ParsedTimestamp
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
|
||||
"gitea.maximumdirect.net/ejr/feedkit/config"
|
||||
"gitea.maximumdirect.net/ejr/feedkit/event"
|
||||
"gitea.maximumdirect.net/ejr/weatherfeeder/internal/providers/openmeteo"
|
||||
"gitea.maximumdirect.net/ejr/weatherfeeder/internal/sources/common"
|
||||
"gitea.maximumdirect.net/ejr/weatherfeeder/internal/standards"
|
||||
)
|
||||
@@ -103,7 +104,9 @@ func (s *ObservationSource) fetchRaw(ctx context.Context) (json.RawMessage, open
|
||||
return raw, openMeteoMeta{}, nil
|
||||
}
|
||||
|
||||
if t, err := parseOpenMeteoTime(meta.Current.Time, meta.Timezone, meta.UTCOffsetSeconds); err == nil {
|
||||
// Best effort: compute a stable EffectiveAt + event ID component.
|
||||
// If parsing fails, we simply omit EffectiveAt and fall back to time.Now() in buildEventID.
|
||||
if t, err := openmeteo.ParseTime(meta.Current.Time, meta.Timezone, meta.UTCOffsetSeconds); err == nil {
|
||||
meta.ParsedTimestamp = t.UTC()
|
||||
}
|
||||
|
||||
@@ -125,25 +128,3 @@ func buildEventID(sourceName string, meta openMeteoMeta) string {
|
||||
|
||||
return fmt.Sprintf("openmeteo:current:%s:%s:%s", sourceName, locKey, ts.Format(time.RFC3339Nano))
|
||||
}
|
||||
|
||||
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 t, err := time.Parse(time.RFC3339, s); err == nil {
|
||||
return t, nil
|
||||
}
|
||||
|
||||
const layout = "2006-01-02T15:04"
|
||||
|
||||
if tz != "" {
|
||||
if loc, err := time.LoadLocation(tz); err == nil {
|
||||
return time.ParseInLocation(layout, s, loc)
|
||||
}
|
||||
}
|
||||
|
||||
loc := time.FixedZone("open-meteo", utcOffsetSeconds)
|
||||
return time.ParseInLocation(layout, s, loc)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user