Tariff: keep fixed tariff rates ordered when chargesZones markers are combined (#32165)

This commit is contained in:
andig 2026-07-26 12:31:26 +02:00 • committed by GitHub
parent 408f9a056b
commit 60f313cbfb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 76 additions and 15 deletions

View file

@ -104,25 +104,18 @@ func (r Zones) TimeTableMarkers() []HourMin {
}
}
HOURS:
// 1hr intervals
for hour := range 24 {
for _, m := range res {
if m.Hour == hour && m.Min == 0 {
continue HOURS
hm := HourMin{Hour: hour}
if !slices.Contains(res, hm) {
res = append(res, hm)
}
}
// hour is missing
for i, m := range res {
if m.Hour >= hour {
res = slices.Insert(res, i, HourMin{Hour: hour, Min: 0})
continue HOURS
}
}
res = append(res, HourMin{Hour: hour, Min: 0})
}
// zones may be unsorted, e.g. when price and charges zones are combined
slices.SortFunc(res, func(i, j HourMin) int {
return i.Minutes() - j.Minutes()
})
return res
}

View file

@ -81,3 +81,38 @@ func TestZonesTimeTableMarkers(t *testing.T) {
assert.Equal(t, expect, zones.TimeTableMarkers())
}
func TestZonesTimeTableMarkersUnsorted(t *testing.T) {
// price and charges zones are concatenated unsorted, see Fixed.Rates
zones := Zones{
{Hours: TimeRange{
From: HourMin{12, 0},
To: HourMin{14, 0},
}},
{Hours: TimeRange{
From: HourMin{10, 15}, // minutes must not sort before the earlier hour's 9:45
To: HourMin{11, 0},
}},
{Hours: TimeRange{
From: HourMin{9, 45},
To: HourMin{10, 0},
}},
{Hours: TimeRange{
From: HourMin{0, 0},
To: HourMin{5, 30},
}},
}
expect := []HourMin{{0, 0}, {1, 0}, {2, 0}, {3, 0}, {4, 0}, {5, 0}, {5, 30}}
for hour := 6; hour < 24; hour++ {
expect = append(expect, HourMin{hour, 0})
switch hour {
case 9:
expect = append(expect, HourMin{9, 45})
case 10:
expect = append(expect, HourMin{10, 15})
}
}
assert.Equal(t, expect, zones.TimeTableMarkers())
}

View file

@ -133,3 +133,36 @@ func TestFixedChargesZonesMarkers(t *testing.T) {
assert.Equal(t, dayStart.Add(5*time.Hour+30*time.Minute), rates[6].Start)
assert.Equal(t, 0.5, rates[6].Value)
}
func TestFixedChargesZonesOrder(t *testing.T) {
at, err := NewFixedFromConfig(map[string]any{
"price": 0.5,
"zones": []struct {
Price float64
Hours string
}{
{0.2, "12-14"},
},
"chargesZones": []struct {
Charges float64
Hours string
}{
{0.1, "0-5:30"},
},
})
require.NoError(t, err)
tf := at.(*Fixed)
tf.clock = clock.NewMock()
rates, err := tf.Rates()
require.NoError(t, err)
// rates must stay ordered and contiguous even if charges zone markers don't align with price zones
for i, r := range rates {
require.True(t, r.End.After(r.Start), "invalid rate %d: %v", i, r)
if i > 0 {
require.Equal(t, rates[i-1].End, r.Start, "non-contiguous rate %d: %v", i, r)
}
}
}