add date parsing method that returns epochMillis instead of date object

This commit is contained in:
2018-12-16 15:38:26 +01:00
parent 20c555c30a
commit 23f800a441
4 changed files with 213 additions and 7 deletions

View File

@@ -17,6 +17,7 @@ public class CsvToEntryTransformer implements LineToEntryTransformer {
private final String[] headers;
private final Pattern splitPattern = Pattern.compile(",");
private final FastISODateParser fastISODateParser = new FastISODateParser();
public CsvToEntryTransformer(final String[] headers) {
this.headers = headers;
@@ -51,7 +52,7 @@ public class CsvToEntryTransformer implements LineToEntryTransformer {
switch (headers[i]) {
case "@timestamp":
date = FastISODateParser.parse(columns[i]);
date = fastISODateParser.parse(columns[i]);
break;
case "duration":
duration = Long.parseLong(columns[i]);

View File

@@ -24,6 +24,7 @@ public class JsonToEntryTransformer implements LineToEntryTransformer {
private final ObjectMapper objectMapper = new ObjectMapper();
private final ObjectReader objectReader = objectMapper.readerFor(typeReferenceForMap);
private final FastISODateParser fastISODateParser = new FastISODateParser();
@Override
public Optional<Entry> toEntry(final String line) throws IOException {
@@ -86,7 +87,7 @@ public class JsonToEntryTransformer implements LineToEntryTransformer {
private OffsetDateTime getDate(final Map<String, Object> map) {
final String timestamp = (String) map.get("@timestamp");
final OffsetDateTime date = FastISODateParser.parse(timestamp);
final OffsetDateTime date = fastISODateParser.parse(timestamp);
return date;
}

View File

@@ -3,6 +3,7 @@ package org.lucares.pdbui.date;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.ConcurrentHashMap;
/**
* A specialized date parser that can only handle ISO-8601 like dates
@@ -12,6 +13,11 @@ import java.time.format.DateTimeFormatter;
*/
public class FastISODateParser {
private final static ConcurrentHashMap<Integer, Long> EPOCH_MILLI_MONTH_OFFSETS = new ConcurrentHashMap<>();
private int cached_epochMilliMonthOffsetKey = 0;
private long cached_epochMilliMonthOffset = 0;
/**
* Parsing ISO-8601 like dates, e.g. 2011-12-03T10:15:30.123Z or
* 2011-12-03T10:15:30+01:00.
@@ -19,7 +25,7 @@ public class FastISODateParser {
* @param date in ISO-8601 format
* @return {@link OffsetDateTime}
*/
public static OffsetDateTime parse(final String date) {
public OffsetDateTime parse(final String date) {
try {
final int year = Integer.parseInt(date, 0, 4, 10);
final int month = Integer.parseInt(date, 5, 7, 10);
@@ -41,7 +47,86 @@ public class FastISODateParser {
}
}
private static int[] parseMilliseconds(final String date, final int start) {
public long parseAsTimestamp(final String date) {
try {
// final long year = Integer.parseInt(date, 0, 4, 10);
// final long month = Integer.parseInt(date, 5, 7, 10);
// final long dayOfMonth = Integer.parseInt(date, 8, 10, 10);
// final long hour = Integer.parseInt(date, 11, 13, 10);
// final long minute = Integer.parseInt(date, 14, 16, 10);
// final long second = Integer.parseInt(date, 17, 19, 10);
final long year = parseLong(date, 0, 4);
final long month = parseLong(date, 5, 7);
final long dayOfMonth = parseLong(date, 8, 10);
final long hour = parseLong(date, 11, 13);
final long minute = parseLong(date, 14, 16);
final long second = parseLong(date, 17, 19);
// final long year = 2018;
// final long month = 10;
// final long dayOfMonth = 12;
// final long hour = 0;
// final long minute = 0;
// final long second = 0;
final int[] nanosAndCharsRead = parseMilliseconds(date, 19);
final long nanos = nanosAndCharsRead[0];
final int offsetTimezone = 19 + nanosAndCharsRead[1];
final long zoneOffsetMillis = date.charAt(offsetTimezone) == 'Z' ? 0
: parseZoneToMillis(date.subSequence(offsetTimezone, date.length()));
final int epochMilliMonthOffsetKey = (int) (year * 12 + month - 1);
final long epochMilliMonthOffset;
if (cached_epochMilliMonthOffsetKey == epochMilliMonthOffsetKey) {
epochMilliMonthOffset = cached_epochMilliMonthOffset;
} else {
epochMilliMonthOffset = EPOCH_MILLI_MONTH_OFFSETS.computeIfAbsent(epochMilliMonthOffsetKey,
FastISODateParser::computeEpochMilliMonthOffset);
cached_epochMilliMonthOffsetKey = epochMilliMonthOffsetKey;
cached_epochMilliMonthOffset = epochMilliMonthOffset;
}
final long epochMilli = epochMilliMonthOffset //
+ (dayOfMonth - 1) * 86_400_000 //
+ hour * 3_600_000 //
+ minute * 60_000 //
+ second * 1_000 //
+ nanos / 1_000_000//
- zoneOffsetMillis;
return epochMilli;
} catch (final RuntimeException e) {
throw new IllegalArgumentException("'" + date + "' is not an ISO-8601 that can be parsed with "
+ FastISODateParser.class.getCanonicalName(), e);
}
}
private static Long computeEpochMilliMonthOffset(final int key) {
final int year = key / 12;
final int month = key % 12 + 1;
final OffsetDateTime date = OffsetDateTime.of(year, month, 1, 0, 0, 0, 0, ZoneOffset.UTC);
return date.toInstant().toEpochMilli();
}
private long parseLong(final String string, final int start, final int end) {
long result = 0;
for (int i = start; i < end; i++) {
// final int c = string.charAt(i);
final int c = string.codePointAt(i);
if (c < '0' || c > '9') {
throw new NumberFormatException(c + " is not a number at offset " + i);
}
result = result * 10 + (c - '0');
}
return result;
}
private int[] parseMilliseconds(final String date, final int start) {
int result = 0;
int i = start;
while (i < date.length()) {
@@ -65,7 +150,7 @@ public class FastISODateParser {
return new int[] { result, readChars };
}
private static ZoneOffset parseZone(final CharSequence zoneString) {
private ZoneOffset parseZone(final CharSequence zoneString) {
final int hours = Integer.parseInt(zoneString, 0, 3, 10);
int minutes = Integer.parseInt(zoneString, 4, 6, 10);
@@ -74,4 +159,15 @@ public class FastISODateParser {
minutes = (hours < 0 ? -1 : 1) * minutes;
return ZoneOffset.ofHoursMinutes(hours, minutes);
}
private long parseZoneToMillis(final CharSequence zoneString) {
final int hours = Integer.parseInt(zoneString, 0, 3, 10);
int minutes = Integer.parseInt(zoneString, 4, 6, 10);
// if hours is negative,then minutes must be too
minutes = (hours < 0 ? -1 : 1) * minutes;
return hours * 3_600_000 + minutes * 60_000;
}
}