package briefing import ( "fmt" "math" "time" "gitea.maximumdirect.net/eric/weatherreporter/internal/forecast" "gitea.maximumdirect.net/eric/weatherreporter/internal/timeutil" ) func rangeLabel(value forecast.Range) string { if value.Min == nil && value.Max == nil { return "" } if value.Min != nil && value.Max != nil { low := roundedInt(value.Min) high := roundedInt(value.Max) if low != nil && high != nil && *low == *high { return fmt.Sprintf("%d", *low) } return fmt.Sprintf("%d-%d", *low, *high) } if value.Min != nil { low := roundedInt(value.Min) return fmt.Sprintf("%d", *low) } high := roundedInt(value.Max) return fmt.Sprintf("%d", *high) } func daypartApparentRangeLabel(value forecast.Range) string { if value.Min == nil && value.Max == nil { return "" } return rangeLabel(value) } func roundedInt(value *float64) *int { if value == nil { return nil } rounded := int(*value + 0.5) if *value < 0 { rounded = int(*value - 0.5) } return &rounded } func windDirectionLabel(degrees *float64) string { if degrees == nil { return "" } labels := []string{"N", "NNE", "NE", "ENE", "E", "ESE", "SE", "SSE", "S", "SSW", "SW", "WSW", "W", "WNW", "NW", "NNW"} normalized := math.Mod(*degrees, 360) if normalized < 0 { normalized += 360 } sector := int(math.Floor((normalized+11.25)/22.5)) % len(labels) return labels[sector] } func windDirectionTextLabel(degrees *float64) string { if degrees == nil { return "" } labels := []string{ "north", "north-northeast", "northeast", "east-northeast", "east", "east-southeast", "southeast", "south-southeast", "south", "south-southwest", "southwest", "west-southwest", "west", "west-northwest", "northwest", "north-northwest", } normalized := math.Mod(*degrees, 360) if normalized < 0 { normalized += 360 } sector := int(math.Floor((normalized+11.25)/22.5)) % len(labels) return labels[sector] } func timedClockLabel(value *forecast.TimedValue, timezone string) string { if value == nil { return "" } return clockLabel(value.Time, timezone) } func friendlyPeriodBeginsLabel(period timeutil.Period, timezone string) string { if !period.IsValid() { return "" } return friendlyDateTimeLabel(period.Start, timezone) } func friendlyPeriodEndsLabel(period timeutil.Period, timezone string) string { if !period.IsValid() { return "" } return friendlyDateTimeLabel(period.End, timezone) } func friendlyDateTimeLabel(value time.Time, timezone string) string { if value.IsZero() { return "" } location, err := timeutil.LoadLocation(timezone) if err != nil { location = time.UTC } return value.In(location).Format("2006-01-02 at 3:04 PM") } func friendlyMonthDayTimeLabel(value time.Time, timezone string) string { if value.IsZero() { return "" } location, err := timeutil.LoadLocation(timezone) if err != nil { location = time.UTC } return value.In(location).Format("January 2 at 3:04 PM") } func friendlyDateLabel(date string, timezone string) string { location, err := timeutil.LoadLocation(timezone) if err != nil { location = time.UTC } parsed, err := time.ParseInLocation(timeutil.DateLayout, date, location) if err != nil { return date } return parsed.Format("Monday, January 2, 2006") } func localDateLabel(value time.Time, timezone string) string { if value.IsZero() { return "" } location, err := timeutil.LoadLocation(timezone) if err != nil { location = time.UTC } return value.In(location).Format(timeutil.DateLayout) } func clockLabel(value time.Time, timezone string) string { location, err := timeutil.LoadLocation(timezone) if err != nil { location = time.UTC } label := value.In(location).Format("3 PM") if label == "12 AM" && value.In(location).Minute() == 0 { return "12 AM" } return label } func hourMinuteLabel(value time.Time, timezone string) string { location, err := timeutil.LoadLocation(timezone) if err != nil { location = time.UTC } return value.In(location).Format("3:04 PM") }