diff --git a/src/main/java/com/ethlo/time/internal/token/TimeZoneOffsetToken.java b/src/main/java/com/ethlo/time/internal/token/TimeZoneOffsetToken.java index 2e9bcf2..76a0cc3 100644 --- a/src/main/java/com/ethlo/time/internal/token/TimeZoneOffsetToken.java +++ b/src/main/java/com/ethlo/time/internal/token/TimeZoneOffsetToken.java @@ -50,6 +50,7 @@ public int read(final String text, final ParsePosition parsePosition) final char c = text.charAt(idx); if (c == 'Z' || c == 'z') { + parsePosition.setIndex(idx + 1); return 0; } @@ -77,6 +78,7 @@ public int read(final String text, final ParsePosition parsePosition) } } + parsePosition.setIndex(idx + 6); return hours * 3600 + minutes * 60; } diff --git a/src/main/java/com/ethlo/time/token/ConfigurableDateTimeParser.java b/src/main/java/com/ethlo/time/token/ConfigurableDateTimeParser.java index 6c4ed76..58246d9 100644 --- a/src/main/java/com/ethlo/time/token/ConfigurableDateTimeParser.java +++ b/src/main/java/com/ethlo/time/token/ConfigurableDateTimeParser.java @@ -24,6 +24,7 @@ import static com.ethlo.time.Field.YEAR; import java.text.ParsePosition; +import java.time.format.DateTimeParseException; import java.util.Arrays; import java.util.HashSet; import java.util.Set; @@ -57,10 +58,25 @@ public static DateTimeParser of(DateTimeToken... tokens) @Override public DateTime parse(String text, ParsePosition parsePosition) + { + try + { + return doParse(text, parsePosition); + } + catch (DateTimeParseException exc) + { + parsePosition.setIndex(exc.getErrorIndex()); + parsePosition.setErrorIndex(exc.getErrorIndex()); + throw exc; + } + } + + private DateTime doParse(String text, ParsePosition parsePosition) { int fractionsLength = 0; int highestOrdinal = YEAR.ordinal(); final int[] values = new int[]{0, 1, 1, 0, 0, 0, 0, -1}; + for (DateTimeToken token : tokens) { final int index = parsePosition.getIndex(); diff --git a/src/test/java/com/ethlo/time/token/ConfigurableDateTimeParserTest.java b/src/test/java/com/ethlo/time/token/ConfigurableDateTimeParserTest.java index 118e40c..61a0365 100644 --- a/src/test/java/com/ethlo/time/token/ConfigurableDateTimeParserTest.java +++ b/src/test/java/com/ethlo/time/token/ConfigurableDateTimeParserTest.java @@ -45,11 +45,26 @@ public class ConfigurableDateTimeParserTest { + private final DateTimeParser rfc3339Parser = DateTimeParsers.of( + digits(YEAR, 4), + separators('-'), + digits(MONTH, 2), + separators('-'), + digits(DAY, 2), + separators('T', 't', ' '), + digits(HOUR, 2), + separators(':'), + digits(MINUTE, 2), + separators(':'), + digits(SECOND, 2), + separators('.'), + fractions(), + zoneOffset() + ); + @Test void parseCustomFormat() { - final ParsePosition pos = new ParsePosition(0); - final String input = "31-12-2000 235937,123456"; final DateTimeParser parser = DateTimeParsers.of( digits(DAY, 2), separators('-'), @@ -63,6 +78,8 @@ void parseCustomFormat() separators(','), fractions() ); + final ParsePosition pos = new ParsePosition(0); + final String input = "31-12-2000 235937,123456"; final DateTime result = parser.parse(input, pos); assertThat(result).isEqualTo(DateTime.of(2000, 12, 31, 23, 59, 37, 123456000, null, 6)); } @@ -184,4 +201,23 @@ void readTimeZoneNegative() final int secs = new TimeZoneOffsetToken().read("-06:30", pos); assertThat(secs).isEqualTo(-23400); } + + @Test + void testOffset() + { + final ParsePosition pos = new ParsePosition(10); + final String text = "2019-12-31T22:20:14.123+05:30"; + rfc3339Parser.parse("123456789," + text + ",something", pos); + assertThat(pos.getIndex()).isEqualTo(10 + text.length()); + } + + @Test + void testOffsetError() + { + final ParsePosition pos = new ParsePosition(10); + final String text = "2019-12-31T22:20X14.123+05:30"; + assertThrows(DateTimeParseException.class, () -> rfc3339Parser.parse("123456789," + text + ",something", pos)); + assertThat(pos.getIndex()).isEqualTo(26); + assertThat(pos.getErrorIndex()).isEqualTo(26); + } }