From b780d85d0d2e02bc2ff0471f532a8238d1efc760 Mon Sep 17 00:00:00 2001 From: premultiply <4681172+premultiply@users.noreply.github.com> Date: Wed, 24 Jun 2026 22:55:13 +0200 Subject: [PATCH 1/3] serialize dateTime with fractional seconds --- charger/ocpp/instance.go | 11 +++++++++++ charger/ocpp/instance_test.go | 14 ++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/charger/ocpp/instance.go b/charger/ocpp/instance.go index dfb3aadebf8..c0846fe2522 100644 --- a/charger/ocpp/instance.go +++ b/charger/ocpp/instance.go @@ -16,10 +16,21 @@ import ( "github.com/lorenzodonini/ocpp-go/ocpp1.6/remotetrigger" "github.com/lorenzodonini/ocpp-go/ocpp1.6/security" "github.com/lorenzodonini/ocpp-go/ocpp1.6/smartcharging" + "github.com/lorenzodonini/ocpp-go/ocpp1.6/types" "github.com/lorenzodonini/ocpp-go/ocppj" "github.com/lorenzodonini/ocpp-go/ws" ) +// dateTimeFormat fixes the OCPP dateTime serialization to RFC3339 with a +// fractional-second component for all chargers. Sub-second precision is valid +// RFC3339/ISO8601 and is required by some chargers (e.g. Webasto/Ampure NEXT) +// that reject timestamps without it, while remaining compatible with all others. +const dateTimeFormat = "2006-01-02T15:04:05.000Z07:00" + +func init() { + types.DateTimeFormat = dateTimeFormat +} + type Config struct { Port int `json:"port"` } diff --git a/charger/ocpp/instance_test.go b/charger/ocpp/instance_test.go index 1e8ffefab79..87692699dfa 100644 --- a/charger/ocpp/instance_test.go +++ b/charger/ocpp/instance_test.go @@ -1,8 +1,13 @@ package ocpp import ( + "encoding/json" "os" "testing" + "time" + + "github.com/lorenzodonini/ocpp-go/ocpp1.6/types" + "github.com/stretchr/testify/require" ) func TestMain(m *testing.M) { @@ -28,3 +33,12 @@ func TestExternalUrl(t *testing.T) { } } } + +func TestDateTimeFormatHasFractionalSeconds(t *testing.T) { + require.Equal(t, dateTimeFormat, types.DateTimeFormat) + + ts := types.NewDateTime(time.Date(2026, 6, 23, 12, 45, 9, 404_000_000, time.UTC)) + b, err := json.Marshal(ts) + require.NoError(t, err) + require.JSONEq(t, `"2026-06-23T12:45:09.404Z"`, string(b)) +} From 9362e2d7ebda9c30f260ccb9a9c5f8686f005565 Mon Sep 17 00:00:00 2001 From: premultiply <4681172+premultiply@users.noreply.github.com> Date: Wed, 24 Jun 2026 23:03:32 +0200 Subject: [PATCH 2/3] wip --- charger/ocpp/instance.go | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/charger/ocpp/instance.go b/charger/ocpp/instance.go index c0846fe2522..476ac09143e 100644 --- a/charger/ocpp/instance.go +++ b/charger/ocpp/instance.go @@ -21,10 +21,7 @@ import ( "github.com/lorenzodonini/ocpp-go/ws" ) -// dateTimeFormat fixes the OCPP dateTime serialization to RFC3339 with a -// fractional-second component for all chargers. Sub-second precision is valid -// RFC3339/ISO8601 and is required by some chargers (e.g. Webasto/Ampure NEXT) -// that reject timestamps without it, while remaining compatible with all others. +// dateTimeFormat sets the OCPP dateTime serialization to RFC3339 with fractional seconds const dateTimeFormat = "2006-01-02T15:04:05.000Z07:00" func init() { From acf0762b2119c54f3fdc87e0ace1ad519bfa4bd7 Mon Sep 17 00:00:00 2001 From: premultiply <4681172+premultiply@users.noreply.github.com> Date: Wed, 24 Jun 2026 23:26:22 +0200 Subject: [PATCH 3/3] OCPP: assert dateTime format round-trips on decode --- charger/ocpp/instance_test.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/charger/ocpp/instance_test.go b/charger/ocpp/instance_test.go index 87692699dfa..54ce68dd8fa 100644 --- a/charger/ocpp/instance_test.go +++ b/charger/ocpp/instance_test.go @@ -41,4 +41,9 @@ func TestDateTimeFormatHasFractionalSeconds(t *testing.T) { b, err := json.Marshal(ts) require.NoError(t, err) require.JSONEq(t, `"2026-06-23T12:45:09.404Z"`, string(b)) + + // the emitted format must round-trip back to the same instant + var got types.DateTime + require.NoError(t, json.Unmarshal(b, &got)) + require.True(t, ts.Equal(got.Time), "round-trip mismatch: %s != %s", ts, got) }