Skip to content

Commit 58f020a

Browse files
authored
Merge pull request #368 from ChargeTimeEU/ensure_millis_precision_in_timestamps
Ensure millis precision in timestamps of outgoing messages
2 parents b9392be + 6012785 commit 58f020a

File tree

2 files changed

+70
-1
lines changed

2 files changed

+70
-1
lines changed

OCPP-J/src/main/java/eu/chargetime/ocpp/JSONCommunicator.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
import java.lang.reflect.Type;
1010
import java.time.ZonedDateTime;
1111
import java.time.format.DateTimeFormatter;
12+
import java.time.format.DateTimeFormatterBuilder;
13+
import java.time.format.ResolverStyle;
1214
import org.slf4j.Logger;
1315
import org.slf4j.LoggerFactory;
1416

@@ -46,6 +48,16 @@ public class JSONCommunicator extends Communicator {
4648

4749
private static final Logger logger = LoggerFactory.getLogger(JSONCommunicator.class);
4850

51+
/**
52+
* a derivation of ISO_INSTANT that always serializes to three millisecond digits, even if zero
53+
*/
54+
public static final DateTimeFormatter ISO_INSTANT_WITH_MILLIS_PRECISION =
55+
new DateTimeFormatterBuilder()
56+
.parseCaseInsensitive()
57+
.appendInstant(3)
58+
.toFormatter()
59+
.withResolverStyle(ResolverStyle.STRICT);
60+
4961
private static final int INDEX_MESSAGEID = 0;
5062
private static final int TYPENUMBER_CALL = 2;
5163
private static final int INDEX_CALL_ACTION = 2;
@@ -94,7 +106,7 @@ private static class ZonedDateTimeSerializer
94106
@Override
95107
public JsonElement serialize(
96108
ZonedDateTime zonedDateTime, Type type, JsonSerializationContext jsonSerializationContext) {
97-
return new JsonPrimitive(zonedDateTime.format(DateTimeFormatter.ISO_INSTANT));
109+
return new JsonPrimitive(zonedDateTime.format(ISO_INSTANT_WITH_MILLIS_PRECISION));
98110
}
99111

100112
@Override

ocpp-v1_6/src/test/java/eu/chargetime/ocpp/test/JSONCommunicatorTest.java

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,22 @@ public void unpackPayload_aCalendarPayload_returnsTestModelWithACalendar() throw
102102
assertThat(model.getCalendarTest().compareTo(someDate), is(0));
103103
}
104104

105+
@Test
106+
public void unpackPayload_aCalendarPayload_parsesNoFractionalAsZeroFractional() throws Exception {
107+
// Given
108+
String aCalendar = "2016-04-28T07:16:11Z";
109+
String payload = "{\"calendarTest\":\"%s\"}";
110+
111+
ZonedDateTime someDate = ZonedDateTime.parse("2016-04-28T07:16:11.000Z");
112+
113+
// When
114+
TestModel model =
115+
communicator.unpackPayload(String.format(payload, aCalendar), TestModel.class);
116+
117+
// Then
118+
assertThat(model.getCalendarTest().compareTo(someDate), is(0));
119+
}
120+
105121
@Test
106122
public void unpackPayload_anIntegerPayload_returnsTestModelWithAnInteger() throws Exception {
107123
// Given
@@ -276,6 +292,24 @@ public void pack_bootNotificationRequest_returnsBootNotificationRequestPayload()
276292
assertThat(payload, equalTo(expected));
277293
}
278294

295+
@Test
296+
public void pack_bootNotificationConfirmation_limitsTimeFractionalDigitsToThree()
297+
throws Exception {
298+
// Given
299+
String expected =
300+
"{\"currentTime\":\"2016-04-28T06:41:13.123Z\",\"interval\":300,\"status\":\"Accepted\"}";
301+
BootNotificationConfirmation confirmation = new BootNotificationConfirmation();
302+
confirmation.setCurrentTime(createDateTimeInNanos(1461825673123456789L)); // will be truncated
303+
confirmation.setInterval(300);
304+
confirmation.setStatus(RegistrationStatus.Accepted);
305+
306+
// When
307+
Object payload = communicator.packPayload(confirmation);
308+
309+
// Then
310+
assertThat(payload, equalTo(expected));
311+
}
312+
279313
@Test
280314
public void pack_bootNotificationConfirmation_returnsBootNotificationConfirmationPayload()
281315
throws Exception {
@@ -294,6 +328,24 @@ public void pack_bootNotificationConfirmation_returnsBootNotificationConfirmatio
294328
assertThat(payload, equalTo(expected));
295329
}
296330

331+
@Test
332+
public void pack_bootNotificationConfirmation_alwaysFormatsTimeWithThreeFractionalDigits()
333+
throws Exception {
334+
// Given
335+
String expected =
336+
"{\"currentTime\":\"2016-04-28T06:41:13.000Z\",\"interval\":300,\"status\":\"Accepted\"}";
337+
BootNotificationConfirmation confirmation = new BootNotificationConfirmation();
338+
confirmation.setCurrentTime(createDateTimeInMillis(1461825673000L)); // will not be truncated
339+
confirmation.setInterval(300);
340+
confirmation.setStatus(RegistrationStatus.Accepted);
341+
342+
// When
343+
Object payload = communicator.packPayload(confirmation);
344+
345+
// Then
346+
assertThat(payload, equalTo(expected));
347+
}
348+
297349
@Test
298350
public void disconnect_disconnects() {
299351
// When
@@ -319,4 +371,9 @@ public void sendError_transmitsError() throws Exception {
319371
private ZonedDateTime createDateTimeInMillis(long dateInMillis) {
320372
return Instant.ofEpochMilli(dateInMillis).atOffset(ZoneOffset.UTC).toZonedDateTime();
321373
}
374+
375+
private ZonedDateTime createDateTimeInNanos(long dateInNanos) {
376+
return Instant.ofEpochSecond(dateInNanos / 1000000000, dateInNanos % 1000000000)
377+
.atOffset(ZoneOffset.UTC).toZonedDateTime();
378+
}
322379
}

0 commit comments

Comments
 (0)