diff --git a/CHANGELOG.md b/CHANGELOG.md index eeaeca6..85ac427 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [2.0.2](https://github.com/sondresjolyst/garge-api/compare/v2.0.1...v2.0.2) (2026-04-19) + + +### Bug Fixes + +* **electricity:** normalize date parsing to prevent timezone-dependent duplicates ([#103](https://github.com/sondresjolyst/garge-api/issues/103)) ([cf90a26](https://github.com/sondresjolyst/garge-api/commit/cf90a2614f863c415b78beb3d4bf966a7ec7e8ac)) + ## [2.0.1](https://github.com/sondresjolyst/garge-api/compare/v2.0.0...v2.0.1) (2026-04-19) diff --git a/Services/NordPoolService.cs b/Services/NordPoolService.cs index 424c741..b2413aa 100644 --- a/Services/NordPoolService.cs +++ b/Services/NordPoolService.cs @@ -107,7 +107,7 @@ private void ParsePriceEntries(dynamic json, string dataType, PriceResponse pric if (json.updatedAt != null) { - priceResponse.Updated = DateTime.Parse((string)json.updatedAt); + priceResponse.Updated = DateTime.Parse((string)json.updatedAt, CultureInfo.InvariantCulture); } else { @@ -118,8 +118,8 @@ private void ParsePriceEntries(dynamic json, string dataType, PriceResponse pric /// /// Parses a NordPool delivery date string to UTC. /// HOURLY entries use full ISO timestamps (e.g. "2026-04-18T22:00:00Z") — parsed as exact UTC. - /// DAILY/MONTHLY entries use date-only strings (e.g. "2026-04-11") — treated as UTC midnight of - /// that calendar date, making storage environment-independent (Docker UTC vs Windows UTC+2). + /// DAILY/MONTHLY entries may arrive as "MM/dd/yyyy HH:mm:ss" or "yyyy-MM-dd" — always stored + /// as UTC midnight of that calendar date so results are environment-independent (UTC vs UTC+2). /// private static DateTime ParseDeliveryDate(string raw) { @@ -129,6 +129,12 @@ private static DateTime ParseDeliveryDate(string raw) return DateTimeOffset.Parse(raw, CultureInfo.InvariantCulture).UtcDateTime; } + // "MM/dd/yyyy HH:mm:ss" format returned by NordPool + if (DateTime.TryParseExact(raw, "MM/dd/yyyy HH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.None, out var dtSlash)) + { + return DateTime.SpecifyKind(dtSlash, DateTimeKind.Utc); + } + // Date-only string — always store as UTC midnight of that date return DateTime.SpecifyKind( DateTime.ParseExact(raw, "yyyy-MM-dd", CultureInfo.InvariantCulture), diff --git a/garge-api.csproj b/garge-api.csproj index 251fa17..3c7f683 100644 --- a/garge-api.csproj +++ b/garge-api.csproj @@ -31,10 +31,10 @@ - + - +