add support for ISO-like date formats
Recommind is using a pseudo ISO date format for their log files. It uses a comma instead of a dot for the second to milli second separator and it does not add a timezone. Dates without timezone are assumed to be UTC.
This commit is contained in:
@@ -39,7 +39,8 @@ public class FastISODateParser {
|
|||||||
final int nanos = nanosAndCharsRead[0];
|
final int nanos = nanosAndCharsRead[0];
|
||||||
final int offsetTimezone = 19 + nanosAndCharsRead[1];
|
final int offsetTimezone = 19 + nanosAndCharsRead[1];
|
||||||
|
|
||||||
final ZoneOffset offset = date.charAt(offsetTimezone) == 'Z' ? ZoneOffset.UTC
|
final ZoneOffset offset = offsetTimezone >= date.length() || date.charAt(offsetTimezone) == 'Z'
|
||||||
|
? ZoneOffset.UTC
|
||||||
: parseZone(date.subSequence(offsetTimezone, date.length()));
|
: parseZone(date.subSequence(offsetTimezone, date.length()));
|
||||||
return OffsetDateTime.of(year, month, dayOfMonth, hour, minute, second, nanos, offset);
|
return OffsetDateTime.of(year, month, dayOfMonth, hour, minute, second, nanos, offset);
|
||||||
} catch (final RuntimeException e) {
|
} catch (final RuntimeException e) {
|
||||||
@@ -61,7 +62,7 @@ public class FastISODateParser {
|
|||||||
final long nanos = nanosAndCharsRead[0];
|
final long nanos = nanosAndCharsRead[0];
|
||||||
final int offsetTimezone = 19 + nanosAndCharsRead[1];
|
final int offsetTimezone = 19 + nanosAndCharsRead[1];
|
||||||
|
|
||||||
final long zoneOffsetMillis = date.charAt(offsetTimezone) == 'Z' ? 0
|
final long zoneOffsetMillis = offsetTimezone >= date.length() || date.charAt(offsetTimezone) == 'Z' ? 0
|
||||||
: parseZoneToMillis(date.subSequence(offsetTimezone, date.length()));
|
: parseZoneToMillis(date.subSequence(offsetTimezone, date.length()));
|
||||||
|
|
||||||
final int epochMilliMonthOffsetKey = (int) (year * 12 + month - 1);
|
final int epochMilliMonthOffsetKey = (int) (year * 12 + month - 1);
|
||||||
@@ -116,21 +117,28 @@ public class FastISODateParser {
|
|||||||
|
|
||||||
private int[] parseMilliseconds(final String date, final int start) {
|
private int[] parseMilliseconds(final String date, final int start) {
|
||||||
int result = 0;
|
int result = 0;
|
||||||
|
int readChars = 0;
|
||||||
int i = start;
|
int i = start;
|
||||||
|
|
||||||
|
char c = date.charAt(i);
|
||||||
|
if (c != '.' && c != ',') {
|
||||||
|
return new int[] { result, readChars };
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
readChars++;
|
||||||
|
|
||||||
while (i < date.length()) {
|
while (i < date.length()) {
|
||||||
final char c = date.charAt(i);
|
c = date.charAt(i);
|
||||||
i++;
|
i++;
|
||||||
if (c == '.') {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (c < '0' || c > '9') {
|
if (c < '0' || c > '9') {
|
||||||
|
i--;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
result = result * 10 + (c - '0');
|
result = result * 10 + (c - '0');
|
||||||
|
readChars++;
|
||||||
}
|
}
|
||||||
final int readChars = i - start - 1;
|
|
||||||
|
|
||||||
while (i <= start + 10) {
|
while (i <= start + 9) {
|
||||||
result *= 10;
|
result *= 10;
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,6 +68,34 @@ public class FastISODateParserTest {
|
|||||||
Assert.assertEquals(actualDate, expectedDate.toInstant().toEpochMilli());
|
Assert.assertEquals(actualDate, expectedDate.toInstant().toEpochMilli());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@DataProvider(name = "providerPseudoISODate")
|
||||||
|
public Object[][] providerPseudoISODate() {
|
||||||
|
return new Object[][] { //
|
||||||
|
{ "2018-11-18T14:42:49,123Z", "2018-11-18T14:42:49.123Z" }, // with comman instead of dot
|
||||||
|
{ "2018-11-18T14:42:49,123+12:34", "2018-11-18T14:42:49.123+12:34" }, // with comman instead of dot
|
||||||
|
{ "2018-11-18T14:42:49.123", "2018-11-18T14:42:49.123Z" }, // without timezone
|
||||||
|
{ "2018-11-18T14:42:49,123", "2018-11-18T14:42:49.123Z" }, // with command, without timezone
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(dataProvider = "providerPseudoISODate")
|
||||||
|
public void testParsePseudoISODate(final String date, final String expectedDate) {
|
||||||
|
|
||||||
|
final OffsetDateTime actualDate = new FastISODateParser().parse(date);
|
||||||
|
|
||||||
|
final OffsetDateTime expected = OffsetDateTime.from(DateTimeFormatter.ISO_DATE_TIME.parse(expectedDate));
|
||||||
|
Assert.assertEquals(actualDate, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(dataProvider = "providerPseudoISODate")
|
||||||
|
public void testParsePseudoISODateAsEpochMilli(final String date, final String expectedDate) {
|
||||||
|
|
||||||
|
final long actualDate = new FastISODateParser().parseAsEpochMilli(date);
|
||||||
|
|
||||||
|
final OffsetDateTime expected = OffsetDateTime.from(DateTimeFormatter.ISO_DATE_TIME.parse(expectedDate));
|
||||||
|
Assert.assertEquals(actualDate, expected.toInstant().toEpochMilli());
|
||||||
|
}
|
||||||
|
|
||||||
@DataProvider(name = "providerParseInvalidDate")
|
@DataProvider(name = "providerParseInvalidDate")
|
||||||
public Object[][] providerParseInvalidDate() {
|
public Object[][] providerParseInvalidDate() {
|
||||||
return new Object[][] { //
|
return new Object[][] { //
|
||||||
|
|||||||
Reference in New Issue
Block a user