Skip to content

Commit 2ca7897

Browse files
authored
Always use millisecond precision for ISO8601 timestamps in identity/buckets (#1852)
* Always use millisecond precision for ISO8601 timestamps in identity buckets endpoints * refactor
1 parent 3bf6d4f commit 2ca7897

2 files changed

Lines changed: 39 additions & 1 deletion

File tree

src/main/java/com/uid2/operator/vertx/UIDOperatorVerticle.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,9 @@ public class UIDOperatorVerticle extends AbstractVerticle {
8686
*/
8787
public static final Duration TOKEN_LIFETIME_TOLERANCE = Duration.ofSeconds(10);
8888
private static final long SECOND_IN_MILLIS = 1000;
89-
private static final DateTimeFormatter API_DATE_TIME_FORMATTER = DateTimeFormatter.ISO_LOCAL_DATE_TIME.withZone(ZoneOffset.UTC);
89+
// Use a formatter that always prints three-digit millisecond precision (e.g. 2024-07-02T14:15:16.000)
90+
private static final DateTimeFormatter API_DATE_TIME_FORMATTER =
91+
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS").withZone(ZoneOffset.UTC);
9092

9193
private static final String REQUEST = "request";
9294
private final HealthComponent healthComponent = HealthManager.instance.registerComponent("http-server");

src/test/java/com/uid2/operator/UIDOperatorVerticleTest.java

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5675,4 +5675,40 @@ void keyBidstreamRespectsConfigValuesWithRemoteConfig(Vertx vertx, VertxTestCont
56755675
testContext.completeNow();
56765676
});
56775677
}
5678+
5679+
private void assertLastUpdatedHasMillis(JsonArray buckets) {
5680+
for (int i = 0; i < buckets.size(); i++) {
5681+
JsonObject bucket = buckets.getJsonObject(i);
5682+
String lastUpdated = bucket.getString("last_updated");
5683+
// Verify pattern yyyy-MM-dd'T'HH:mm:ss.SSS
5684+
assertTrue(lastUpdated.matches("\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{3}"),
5685+
"last_updated does not contain millisecond precision: " + lastUpdated);
5686+
}
5687+
}
5688+
5689+
@ParameterizedTest
5690+
@ValueSource(strings = {"v1", "v2"})
5691+
void identityBucketsAlwaysReturnMilliseconds(String apiVersion, Vertx vertx, VertxTestContext testContext) {
5692+
final int clientSiteId = 201;
5693+
fakeAuth(clientSiteId, Role.MAPPER);
5694+
setupSalts();
5695+
5696+
// SaltEntry with a lastUpdated that has 0 milliseconds
5697+
long lastUpdatedMillis = Instant.parse("2024-01-01T00:00:00Z").toEpochMilli();
5698+
SaltEntry bucketEntry = new SaltEntry(456, "hashed456", lastUpdatedMillis, "salt456", null, null, null, null);
5699+
when(saltProviderSnapshot.getModifiedSince(any())).thenReturn(List.of(bucketEntry));
5700+
5701+
String sinceTimestamp = "2023-12-31T00:00:00"; // earlier timestamp
5702+
5703+
boolean isV1 = apiVersion.equals("v1");
5704+
String v1Param = isV1 ? "since_timestamp=" + sinceTimestamp : null;
5705+
JsonObject req = isV1 ? null : new JsonObject().put("since_timestamp", sinceTimestamp);
5706+
5707+
send(apiVersion, vertx, apiVersion + "/identity/buckets", isV1, v1Param, req, 200, respJson -> {
5708+
JsonArray buckets = respJson.getJsonArray("body");
5709+
assertFalse(buckets.isEmpty());
5710+
assertLastUpdatedHasMillis(buckets);
5711+
testContext.completeNow();
5712+
});
5713+
}
56785714
}

0 commit comments

Comments
 (0)