From 02f2991620025890f028879fc24e40d9c73bdcef Mon Sep 17 00:00:00 2001 From: Matt Jeanes Date: Sun, 4 Jul 2021 01:54:07 +0100 Subject: [PATCH] Fix timezone related issues in FixedPrice provider and add tests for those scenarios Also clarify documentation/tests around the unit for FixedPrice (which even I got wrong!) --- README.md | 4 +- .../Services/FixedPriceServiceTests.cs | 162 ++++++++++++------ TeslaMateAgile/Helpers/PriceHelper.cs | 2 - TeslaMateAgile/Services/FixedPriceService.cs | 6 +- 4 files changed, 110 insertions(+), 64 deletions(-) diff --git a/README.md b/README.md index b46c5ee..bb3cc1d 100644 --- a/README.md +++ b/README.md @@ -58,8 +58,8 @@ See below for how to configure the environment variables appropriately ```yaml - TeslaMate__EnergyProvider=FixedPrice - FixedPrice__TimeZone=Europe/London # IANA (tz database) time zone code, used for below times -- FixedPrice__Prices__0=08:00-13:00=1.5 # You can have as many as these as you need -- FixedPrice__Prices__1=13:00-20:00=5 +- FixedPrice__Prices__0=08:00-13:00=0.1559 # Cost is in your currency e.g. pounds, euros, dollars (not pennies, cents, etc) +- FixedPrice__Prices__1=13:00-20:00=0.05 # You can have as many as these as you need - FixedPrice__Prices__2=20:00-03:30=4 - FixedPrice__Prices__3=03:30-06:00=3.5 - FixedPrice__Prices__4=06:00-08:00=2 diff --git a/TeslaMateAgile.Tests/Services/FixedPriceServiceTests.cs b/TeslaMateAgile.Tests/Services/FixedPriceServiceTests.cs index 9528ee4..5713d8d 100644 --- a/TeslaMateAgile.Tests/Services/FixedPriceServiceTests.cs +++ b/TeslaMateAgile.Tests/Services/FixedPriceServiceTests.cs @@ -25,11 +25,11 @@ public FixedPriceService Setup(string timeZone, List prices) "Etc/UTC", new List { - "08:00-13:00=1.5", - "13:00-20:00=5", - "20:00-03:30=4", - "03:30-06:00=3.5", - "06:00-08:00=2", + "08:00-13:00=0.015", + "13:00-20:00=0.05", + "20:00-03:30=0.04", + "03:30-06:00=0.035", + "06:00-08:00=0.02", }, DateTimeOffset.Parse("2021-02-01T03:00:00Z"), DateTimeOffset.Parse("2021-02-01T18:00:00Z"), @@ -39,31 +39,31 @@ public FixedPriceService Setup(string timeZone, List prices) { ValidFrom = DateTimeOffset.Parse("2021-01-31T20:00:00Z"), ValidTo = DateTimeOffset.Parse("2021-02-01T03:30:00Z"), - Value = 4M + Value = 0.04M }, new Price { ValidFrom = DateTimeOffset.Parse("2021-02-01T03:30:00Z"), ValidTo = DateTimeOffset.Parse("2021-02-01T06:00:00Z"), - Value = 3.5M + Value = 0.035M }, new Price { ValidFrom = DateTimeOffset.Parse("2021-02-01T06:00:00Z"), ValidTo = DateTimeOffset.Parse("2021-02-01T08:00:00Z"), - Value = 2M + Value = 0.02M }, new Price { ValidFrom = DateTimeOffset.Parse("2021-02-01T08:00:00Z"), ValidTo = DateTimeOffset.Parse("2021-02-01T13:00:00Z"), - Value = 1.5M + Value = 0.015M }, new Price { ValidFrom = DateTimeOffset.Parse("2021-02-01T13:00:00Z"), ValidTo = DateTimeOffset.Parse("2021-02-01T20:00:00Z"), - Value = 5M + Value = 0.05M } } }, @@ -73,11 +73,11 @@ public FixedPriceService Setup(string timeZone, List prices) "Etc/UTC", new List { - "08:00-13:00=1.5", - "13:00-20:00=5", - "20:00-03:30=4", - "03:30-06:00=3.5", - "06:00-08:00=2", + "08:00-13:00=0.015", + "13:00-20:00=0.05", + "20:00-03:30=0.04", + "03:30-06:00=0.035", + "06:00-08:00=0.02", }, DateTimeOffset.Parse("2021-02-01T08:00:00Z"), DateTimeOffset.Parse("2021-02-01T18:00:00Z"), @@ -87,13 +87,13 @@ public FixedPriceService Setup(string timeZone, List prices) { ValidFrom = DateTimeOffset.Parse("2021-02-01T08:00:00Z"), ValidTo = DateTimeOffset.Parse("2021-02-01T13:00:00Z"), - Value = 1.5M + Value = 0.015M }, new Price { ValidFrom = DateTimeOffset.Parse("2021-02-01T13:00:00Z"), ValidTo = DateTimeOffset.Parse("2021-02-01T20:00:00Z"), - Value = 5M + Value = 0.05M } } }, @@ -103,11 +103,11 @@ public FixedPriceService Setup(string timeZone, List prices) "Etc/UTC", new List { - "08:00-13:00=1.5", - "13:00-20:00=5", - "20:00-03:30=4", - "03:30-06:00=3.5", - "06:00-08:00=2", + "08:00-13:00=0.015", + "13:00-20:00=0.05", + "20:00-03:30=0.04", + "03:30-06:00=0.035", + "06:00-08:00=0.02", }, DateTimeOffset.Parse("2021-02-01T15:00:00Z"), DateTimeOffset.Parse("2021-02-01T20:00:00Z"), @@ -117,7 +117,7 @@ public FixedPriceService Setup(string timeZone, List prices) { ValidFrom = DateTimeOffset.Parse("2021-02-01T13:00:00Z"), ValidTo = DateTimeOffset.Parse("2021-02-01T20:00:00Z"), - Value = 5M + Value = 0.05M } } }, @@ -127,11 +127,11 @@ public FixedPriceService Setup(string timeZone, List prices) "Etc/UTC", new List { - "08:00-13:00=1.5", - "13:00-20:00=5", - "20:00-03:30=4", - "03:30-06:00=3.5", - "06:00-08:00=2", + "08:00-13:00=0.015", + "13:00-20:00=0.05", + "20:00-03:30=0.04", + "03:30-06:00=0.035", + "06:00-08:00=0.02", }, DateTimeOffset.Parse("2021-02-01T15:00:00Z"), DateTimeOffset.Parse("2021-02-02T07:00:00Z"), @@ -141,25 +141,25 @@ public FixedPriceService Setup(string timeZone, List prices) { ValidFrom = DateTimeOffset.Parse("2021-02-01T13:00:00Z"), ValidTo = DateTimeOffset.Parse("2021-02-01T20:00:00Z"), - Value = 5M + Value = 0.05M }, new Price { ValidFrom = DateTimeOffset.Parse("2021-02-01T20:00:00Z"), ValidTo = DateTimeOffset.Parse("2021-02-02T03:30:00Z"), - Value = 4M + Value = 0.04M }, new Price { ValidFrom = DateTimeOffset.Parse("2021-02-02T03:30:00Z"), ValidTo = DateTimeOffset.Parse("2021-02-02T06:00:00Z"), - Value = 3.5M + Value = 0.035M }, new Price { ValidFrom = DateTimeOffset.Parse("2021-02-02T06:00:00Z"), ValidTo = DateTimeOffset.Parse("2021-02-02T08:00:00Z"), - Value = 2M + Value = 0.02M } } }, @@ -169,11 +169,11 @@ public FixedPriceService Setup(string timeZone, List prices) "America/New_York", new List { - "08:00-13:00=1.5", - "13:00-20:00=5", - "20:00-03:30=4", - "03:30-06:00=3.5", - "06:00-08:00=2", + "08:00-13:00=0.015", + "13:00-20:00=0.05", + "20:00-03:30=0.04", + "03:30-06:00=0.035", + "06:00-08:00=0.02", }, DateTimeOffset.Parse("2021-02-01T15:00:00Z"), DateTimeOffset.Parse("2021-02-02T07:00:00Z"), @@ -183,19 +183,19 @@ public FixedPriceService Setup(string timeZone, List prices) { ValidFrom = DateTimeOffset.Parse("2021-02-01T13:00:00Z"), ValidTo = DateTimeOffset.Parse("2021-02-01T18:00:00Z"), - Value = 1.5M + Value = 0.015M }, new Price { ValidFrom = DateTimeOffset.Parse("2021-02-01T18:00:00Z"), ValidTo = DateTimeOffset.Parse("2021-02-02T01:00:00Z"), - Value = 5M + Value = 0.05M }, new Price { ValidFrom = DateTimeOffset.Parse("2021-02-02T01:00:00Z"), ValidTo = DateTimeOffset.Parse("2021-02-02T08:30:00Z"), - Value = 4M + Value = 0.04M } } }, @@ -205,11 +205,11 @@ public FixedPriceService Setup(string timeZone, List prices) "America/New_York", new List { - "08:00-13:00=1.5", - "13:00-20:00=5", - "20:00-03:30=4", - "03:30-06:00=3.5", - "06:00-08:00=2", + "08:00-13:00=0.015", + "13:00-20:00=0.05", + "20:00-03:30=0.04", + "03:30-06:00=0.035", + "06:00-08:00=0.02", }, DateTimeOffset.Parse("2021-02-01T03:00:00Z"), DateTimeOffset.Parse("2021-02-01T10:00:00Z"), @@ -219,13 +219,13 @@ public FixedPriceService Setup(string timeZone, List prices) { ValidFrom = DateTimeOffset.Parse("2021-01-31T20:00:00-05:00"), ValidTo = DateTimeOffset.Parse("2021-02-01T03:30:00-05:00"), - Value = 4M + Value = 0.04M }, new Price { ValidFrom = DateTimeOffset.Parse("2021-02-01T03:30:00-05:00"), ValidTo = DateTimeOffset.Parse("2021-02-01T06:00:00-05:00"), - Value = 3.5M + Value = 0.035M } } }, @@ -235,11 +235,11 @@ public FixedPriceService Setup(string timeZone, List prices) "America/New_York", new List { - "08:00-13:00=1.5", - "13:00-20:00=5", - "20:00-03:30=4", - "03:30-06:00=3.5", - "06:00-08:00=2", + "08:00-13:00=0.015", + "13:00-20:00=0.05", + "20:00-03:30=0.04", + "03:30-06:00=0.035", + "06:00-08:00=0.02", }, DateTimeOffset.Parse("2021-02-01T15:00:00Z"), DateTimeOffset.Parse("2021-02-01T23:00:00Z"), @@ -249,13 +249,13 @@ public FixedPriceService Setup(string timeZone, List prices) { ValidFrom = DateTimeOffset.Parse("2021-02-01T08:00:00-05:00"), ValidTo = DateTimeOffset.Parse("2021-02-01T13:00:00-05:00"), - Value = 1.5M + Value = 0.015M }, new Price { ValidFrom = DateTimeOffset.Parse("2021-02-01T13:00:00-05:00"), ValidTo = DateTimeOffset.Parse("2021-02-01T20:00:00-05:00"), - Value = 5M + Value = 0.05M } } }, @@ -294,8 +294,8 @@ public FixedPriceService Setup(string timeZone, List prices) "Europe/London", new List { - "23:30-20:30=13.8", - "20:30-23:30=4.5" + "23:30-20:30=0.138", + "20:30-23:30=0.045" }, DateTimeOffset.Parse("2021-04-13T19:46:13Z"), DateTimeOffset.Parse("2021-04-13T22:02:46Z"), @@ -305,7 +305,55 @@ public FixedPriceService Setup(string timeZone, List prices) { ValidFrom = DateTimeOffset.Parse("2021-04-13T20:30:00+01:00"), ValidTo = DateTimeOffset.Parse("2021-04-13T23:30:00+01:00"), - Value = 4.5M + Value = 0.045M + } + } + }, + new object[] + { + "TimeZone_DSTEdge", + "Europe/London", + new List + { + "00:30-04:30=0.0556", + "04:30-00:30=0.15" + }, + DateTimeOffset.Parse("2021-06-16T23:00:51Z"), + DateTimeOffset.Parse("2021-06-17T00:19:15Z"), + new List + { + new Price + { + ValidFrom = DateTimeOffset.Parse("2021-06-16T03:30:00Z"), + ValidTo = DateTimeOffset.Parse("2021-06-16T23:30:00Z"), + Value = 0.15M + }, + new Price + { + ValidFrom = DateTimeOffset.Parse("2021-06-16T23:30:00Z"), + ValidTo = DateTimeOffset.Parse("2021-06-17T03:30:00Z"), + Value = 0.0556M + } + } + }, + new object[] + { + "TimeZone_SameDayEdge", + "Europe/London", + new List + { + "00:30-04:30=0.05", + "04:30-00:30=0.15" + }, + DateTimeOffset.Parse("2021-07-01T00:09:14Z"), + DateTimeOffset.Parse("2021-07-01T00:46:17Z"), + new List + { + new Price + { + ValidFrom = DateTimeOffset.Parse("2021-06-30T23:30:00Z"), + ValidTo = DateTimeOffset.Parse("2021-07-01T03:30:00Z"), + Value = 0.05M } } } diff --git a/TeslaMateAgile/Helpers/PriceHelper.cs b/TeslaMateAgile/Helpers/PriceHelper.cs index b3df811..190234f 100644 --- a/TeslaMateAgile/Helpers/PriceHelper.cs +++ b/TeslaMateAgile/Helpers/PriceHelper.cs @@ -34,8 +34,6 @@ IOptions teslaMateOptions } public async Task Update() { - _logger.LogInformation("Updating prices"); - var chargingProcesses = await _context.ChargingProcesses .Where(x => x.GeofenceId == _teslaMateOptions.GeofenceId && x.EndDate.HasValue && !x.Cost.HasValue) .Include(x => x.Charges) diff --git a/TeslaMateAgile/Services/FixedPriceService.cs b/TeslaMateAgile/Services/FixedPriceService.cs index d22ad5d..7811038 100644 --- a/TeslaMateAgile/Services/FixedPriceService.cs +++ b/TeslaMateAgile/Services/FixedPriceService.cs @@ -29,13 +29,13 @@ IOptions options public Task> GetPriceData(DateTimeOffset from, DateTimeOffset to) { var prices = new List(); - var days = (to.Add(-_timeZone.GetUtcOffset(to)).Date - from.Add(-_timeZone.GetUtcOffset(from)).Date).Days; + var days = (to.Date - from.Date).Days; var lastPrice = _fixedPrices.Last(); FixedPrice lastFixedPriceAdded = null; for (var i = 0; i <= days; i++) { - var date = from.Add(-_timeZone.GetUtcOffset(from)).Date; - if (!_fixedPrices.Any(x => x.FromHour < from.Hour) && (lastPrice != lastFixedPriceAdded)) + var date = from.Date; + if (lastPrice != lastFixedPriceAdded) { var validFrom = DateTime.SpecifyKind(date.AddDays(i).AddHours(lastPrice.FromHour - 24).AddMinutes(lastPrice.FromMinute), DateTimeKind.Utc); var validTo = DateTime.SpecifyKind(date.AddDays(i).AddHours(lastPrice.ToHour - 24).AddMinutes(lastPrice.ToMinute), DateTimeKind.Utc);