Skip to content

Commit

Permalink
Avro time converter respects timezone
Browse files Browse the repository at this point in the history
  • Loading branch information
johnny-schmidt committed Aug 5, 2024
1 parent 2e7d28b commit 5f7941c
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 23 deletions.
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
package tech.allegro.schema.json2avro.converter.util;

import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;

Expand Down Expand Up @@ -67,14 +62,28 @@ public static Long getMicroSeconds(String jsonTime) {
return Long.valueOf(jsonTime);
}
try {
LocalTime time = LocalTime.parse(jsonTime, TIME_FORMATTER);
nanoOfDay = time.toNanoOfDay();
} catch (DateTimeParseException e) {
// This will only succeed if the time has a timezone.
OffsetTime time = OffsetTime.parse(jsonTime, TIME_FORMATTER);
nanoOfDay = time.toLocalTime().toNanoOfDay();

// Apply the offset, wrapping around midnight.
nanoOfDay -= time.getOffset().getTotalSeconds() * 1_000_000_000L;
if (nanoOfDay < 0) {
nanoOfDay += 24 * 60 * 60 * 1_000_000_000L;
}
} catch (DateTimeException e) {
try {
LocalTime time = LocalTime.parse(jsonTime, DATE_TIME_FORMATTER);
// Works on any correctly formatted time without a timezone
LocalTime time = LocalTime.parse(jsonTime, TIME_FORMATTER);
nanoOfDay = time.toNanoOfDay();
} catch (DateTimeParseException ex) {
// no logging since it may generate too much noise
try {
// Catchall
LocalTime time = LocalTime.parse(jsonTime, DATE_TIME_FORMATTER);
nanoOfDay = time.toNanoOfDay();
} catch (DateTimeParseException exc) {
// no logging since it may generate too much noise
}
}
}
return nanoOfDay == null ? null : nanoOfDay / 1000;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ public void testDateTimeConversion() {
assertEquals(3660000000L, getMicroSeconds("01:01"));
assertEquals(44581541000L, getMicroSeconds("12:23:01.541"));
assertEquals(44581541214L, getMicroSeconds("12:23:01.541214"));
assertEquals(39600000000L, getMicroSeconds("12:00:00.000000+01:00"));
assertEquals(84600000000L, getMicroSeconds("03:30:00.000000+04:00"));
}

@Test
Expand Down
100 changes: 88 additions & 12 deletions converter/src/test/resources/field_conversion_failure_listener.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,17 @@
"int"
],
"default": null
},
{
"name": "TIME_WITH_TIMEZONE",
"type": [
"null",
{
"type": "long",
"logicalType": "time-micros"
}
],
"default": null
}
]
}
Expand All @@ -81,7 +92,8 @@
},
"data": {
"name": "Bob",
"id": 1
"id": 1,
"time_with_timezone": "04:00:00+05:30"
}
},
{
Expand All @@ -90,7 +102,8 @@
},
"data": {
"name": "Alice",
"id": 2
"id": 2,
"time_with_timezone": "12:00:00"
}
}
],
Expand All @@ -107,7 +120,8 @@
},
"DATA": {
"NAME": "Bob",
"ID": 1
"ID": 1,
"TIME_WITH_TIMEZONE": 81000000000
}
},
{
Expand All @@ -116,7 +130,8 @@
},
"DATA": {
"NAME": "Alice",
"ID": 2
"ID": 2,
"TIME_WITH_TIMEZONE": 43200000000
}
}
]
Expand All @@ -134,7 +149,8 @@
"o",
"b"
],
"id": 1
"id": 1,
"time_with_timezone": "04:00:00.000+05:30"
}
},
{
Expand All @@ -143,7 +159,8 @@
},
"data": {
"name": "Alice",
"id": 2
"id": 2,
"time_with_timezone": "12:00:00.000"
}
}
],
Expand All @@ -160,7 +177,8 @@
},
"DATA": {
"NAME": null,
"ID": 1
"ID": 1,
"TIME_WITH_TIMEZONE": 81000000000
}
},
{
Expand All @@ -169,7 +187,8 @@
},
"DATA": {
"NAME": "Alice",
"ID": 2
"ID": 2,
"TIME_WITH_TIMEZONE": 43200000000
}
}
]
Expand All @@ -189,7 +208,8 @@
},
"data": {
"name": 808,
"id": 2
"id": 2,
"time_with_timezone": "04:00:00+05:30"
}
},
{
Expand All @@ -198,7 +218,8 @@
},
"data": {
"name": "Alice",
"id": 2
"id": 2,
"time_with_timezone": "12:00:00Z"
}
}
],
Expand All @@ -220,7 +241,8 @@
},
"DATA": {
"NAME": null,
"ID": 2
"ID": 2,
"TIME_WITH_TIMEZONE": 81000000000
}
},
{
Expand All @@ -229,10 +251,64 @@
},
"DATA": {
"NAME": "Alice",
"ID": 2
"ID": 2,
"TIME_WITH_TIMEZONE": 43200000000
}
}
]
},
{
"name": "record with malformed timezone",
"records": [
{
"meta": {
"changes": []
},
"data": {
"name": "Bob",
"id": 1,
"time_with_timezone": "04:00:00+05:30"
}
},
{
"meta": {
"changes": []
},
"data": {
"name": "Alice",
"id": 2,
"time_with_timezone": "12:00:00-3:00"
}
}
],
"expectedOutput": [
{
"META": {
"CHANGES": []
},
"DATA": {
"NAME": "Bob",
"ID": 1,
"TIME_WITH_TIMEZONE": 81000000000
}
},
{
"META": {
"CHANGES": [
{
"FIELD": "time_with_timezone",
"CHANGE": "NULLED",
"REASON": "Could not evaluate union, field TIME_WITH_TIMEZONE is expected to be one of these: NULL, LONG. If this is a complex type, check if offending field (path: DATA.TIME_WITH_TIMEZONE) adheres to schema: 12:00:00-3:00"
}
]
},
"DATA": {
"NAME": "Alice",
"ID": 2,
"TIME_WITH_TIMEZONE": null
}
}
]
}
]
}

0 comments on commit 5f7941c

Please sign in to comment.