TimestampSpec: Have "auto" detect timestamps in almost-iso format. (#4682)

Fixes #4082.
This commit is contained in:
Gian Merlino 2017-08-11 13:02:42 -07:00 committed by Fangjin Yang
parent 1bddfc089c
commit d775347b06
3 changed files with 57 additions and 4 deletions

View File

@ -22,9 +22,7 @@ package io.druid.data.input.impl;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.base.Function;
import io.druid.java.util.common.parsers.TimestampParser;
import org.joda.time.DateTime;
import java.util.List;

View File

@ -25,6 +25,9 @@ import io.druid.java.util.common.IAE;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import org.joda.time.format.DateTimeFormatterBuilder;
import org.joda.time.format.DateTimeParser;
import org.joda.time.format.ISODateTimeFormat;
public class TimestampParser
{
@ -34,16 +37,16 @@ public class TimestampParser
{
if (format.equalsIgnoreCase("auto")) {
// Could be iso or millis
final DateTimeFormatter parser = createAutoParser();
return new Function<String, DateTime>()
{
@Override
public DateTime apply(String input)
{
Preconditions.checkArgument(input != null && !input.isEmpty(), "null timestamp");
for (int i = 0; i < input.length(); i++) {
if (input.charAt(i) < '0' || input.charAt(i) > '9') {
return new DateTime(ParserUtils.stripQuotes(input));
return parser.parseDateTime(ParserUtils.stripQuotes(input));
}
}
@ -161,4 +164,28 @@ public class TimestampParser
}
};
}
private static DateTimeFormatter createAutoParser()
{
final DateTimeFormatter offsetElement = new DateTimeFormatterBuilder()
.appendTimeZoneOffset("Z", true, 2, 4)
.toFormatter();
DateTimeParser timeOrOffset = new DateTimeFormatterBuilder()
.append(
null,
new DateTimeParser[]{
new DateTimeFormatterBuilder().appendLiteral('T').toParser(),
new DateTimeFormatterBuilder().appendLiteral(' ').toParser()
}
)
.appendOptional(ISODateTimeFormat.timeElementParser().getParser())
.appendOptional(offsetElement.getParser())
.toParser();
return new DateTimeFormatterBuilder()
.append(ISODateTimeFormat.dateElementParser())
.appendOptional(timeOrOffset)
.toFormatter();
}
}

View File

@ -22,10 +22,14 @@ package io.druid.java.util.common.parsers;
import com.google.common.base.Function;
import org.joda.time.DateTime;
import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
public class TimestampParserTest
{
@Rule
public ExpectedException expectedException = ExpectedException.none();
@Test
public void testStripQuotes() throws Exception
@ -40,9 +44,33 @@ public class TimestampParserTest
final Function<Object, DateTime> parser = TimestampParser.createObjectTimestampParser("auto");
Assert.assertEquals(new DateTime("2009-02-13T23:31:30Z"), parser.apply("1234567890000"));
Assert.assertEquals(new DateTime("2009-02-13T23:31:30Z"), parser.apply("2009-02-13T23:31:30Z"));
Assert.assertEquals(new DateTime("2009-02-13T23:31:30-08:00"), parser.apply("2009-02-13T23:31:30-08:00"));
Assert.assertEquals(new DateTime("2009-02-13T23:31:30Z"), parser.apply("2009-02-13 23:31:30Z"));
Assert.assertEquals(new DateTime("2009-02-13T23:31:30-08:00"), parser.apply("2009-02-13 23:31:30-08:00"));
Assert.assertEquals(new DateTime("2009-02-13T00:00:00Z"), parser.apply("2009-02-13"));
Assert.assertEquals(new DateTime("2009-02-13T00:00:00Z"), parser.apply("\"2009-02-13\""));
Assert.assertEquals(new DateTime("2009-02-13T23:31:30Z"), parser.apply("2009-02-13 23:31:30"));
Assert.assertEquals(new DateTime("2009-02-13T23:31:30Z"), parser.apply(1234567890000L));
}
@Test
public void testAutoNull() throws Exception
{
final Function<Object, DateTime> parser = TimestampParser.createObjectTimestampParser("auto");
expectedException.expect(IllegalArgumentException.class);
parser.apply(null);
}
@Test
public void testAutoInvalid() throws Exception
{
final Function<Object, DateTime> parser = TimestampParser.createObjectTimestampParser("auto");
expectedException.expect(IllegalArgumentException.class);
parser.apply("asdf");
}
@Test
public void testRuby() throws Exception
{