diff --git a/.gitignore b/.gitignore
index abf22d1..7708236 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,3 +5,4 @@
 .idea
 *.iml
 *.versionsBackup
+.cifuzz-corpus
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 9b5227e..afffd3f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -48,12 +48,26 @@ limitations under the License.
             <version>3.24.2</version>
             <scope>test</scope>
         </dependency>
+        <!--
         <dependency>
             <groupId>com.code-intelligence</groupId>
             <artifactId>jazzer-junit</artifactId>
             <version>0.22.1</version>
             <scope>test</scope>
         </dependency>
+        -->
+        <dependency>
+            <groupId>org.junit.jupiter</groupId>
+            <artifactId>junit-jupiter-api</artifactId>
+            <version>5.10.1</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.junit.jupiter</groupId>
+            <artifactId>junit-jupiter-params</artifactId>
+            <version>5.10.1</version>
+            <scope>test</scope>
+        </dependency>
         <dependency>
             <groupId>com.fasterxml.jackson.core</groupId>
             <artifactId>jackson-databind</artifactId>
@@ -69,7 +83,7 @@ limitations under the License.
         <dependency>
             <groupId>ch.qos.logback</groupId>
             <artifactId>logback-classic</artifactId>
-            <version>1.4.14</version>
+            <version>1.3.14</version>
             <scope>test</scope>
         </dependency>
     </dependencies>
diff --git a/src/main/java/com/ethlo/time/DateTime.java b/src/main/java/com/ethlo/time/DateTime.java
index b16bb9e..534298c 100644
--- a/src/main/java/com/ethlo/time/DateTime.java
+++ b/src/main/java/com/ethlo/time/DateTime.java
@@ -471,7 +471,6 @@ public boolean isSupported(final TemporalField field)
         return Field.of(field).ordinal() <= this.field.ordinal();
     }
 
-    @SuppressWarnings("DuplicatedCode")
     @Override
     public long getLong(final TemporalField temporalField)
     {
diff --git a/src/main/java/com/ethlo/time/internal/ErrorUtil.java b/src/main/java/com/ethlo/time/internal/ErrorUtil.java
new file mode 100644
index 0000000..7285f41
--- /dev/null
+++ b/src/main/java/com/ethlo/time/internal/ErrorUtil.java
@@ -0,0 +1,45 @@
+package com.ethlo.time.internal;
+
+/*-
+ * #%L
+ * Internet Time Utility
+ * %%
+ * Copyright (C) 2017 - 2024 Morten Haraldsen (ethlo)
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * #L%
+ */
+
+import java.time.format.DateTimeParseException;
+
+public class ErrorUtil
+{
+    private ErrorUtil()
+    {
+    }
+
+    public static DateTimeParseException raiseUnexpectedCharacter(String chars, int index)
+    {
+        throw new DateTimeParseException("Unexpected character " + chars.charAt(index) + " at position " + (index + 1) + ": " + chars, chars, index);
+    }
+
+    public static DateTimeParseException raiseUnexpectedEndOfText(final String chars, final int offset)
+    {
+        throw new DateTimeParseException("Unexpected end of input: " + chars, chars, offset);
+    }
+
+    public static DateTimeParseException raiseMissingTimeZone(String chars, int index)
+    {
+        throw new DateTimeParseException("No timezone information: " + chars, chars, index);
+    }
+}
diff --git a/src/main/java/com/ethlo/time/internal/EthloITU.java b/src/main/java/com/ethlo/time/internal/EthloITU.java
index 2035092..12b4ef8 100644
--- a/src/main/java/com/ethlo/time/internal/EthloITU.java
+++ b/src/main/java/com/ethlo/time/internal/EthloITU.java
@@ -20,6 +20,9 @@
  * #L%
  */
 
+import static com.ethlo.time.internal.ErrorUtil.raiseMissingTimeZone;
+import static com.ethlo.time.internal.ErrorUtil.raiseUnexpectedCharacter;
+import static com.ethlo.time.internal.ErrorUtil.raiseUnexpectedEndOfText;
 import static com.ethlo.time.internal.LeapSecondHandler.LEAP_SECOND_SECONDS;
 import static com.ethlo.time.internal.LimitedCharArrayIntegerUtil.DIGIT_9;
 import static com.ethlo.time.internal.LimitedCharArrayIntegerUtil.ZERO;
@@ -96,7 +99,7 @@ private static int scale(int fractions, int len, String parsedData, final int in
         switch (len)
         {
             case 0:
-                throw new DateTimeParseException("Must have at least 1 fraction digit", parsedData, index);
+                throw new DateTimeParseException("Must have at least 1 fraction digit: " + parsedData, parsedData, index);
             case 1:
                 return fractions * 100_000_000;
             case 2:
@@ -137,44 +140,36 @@ private static Object handleTime(String chars, int year, int month, int day, int
                 }
                 return DateTime.of(year, month, day, hour, minute, zoneOffset);
         }
-        throw new DateTimeParseException("Unexpected character at position 16: " + chars.charAt(16), chars, 16);
+        throw raiseUnexpectedCharacter(chars, 16);
     }
 
     private static void assertPositionContains(String chars, int offset, char expected)
     {
         if (offset >= chars.length())
         {
-            raiseDateTimeException(chars, "Unexpected end of input", offset);
+            raiseUnexpectedEndOfText(chars, offset);
         }
 
         if (chars.charAt(offset) != expected)
         {
             throw new DateTimeParseException("Expected character " + expected
-                    + " at position " + (offset + 1) + " '" + chars + "'", chars, offset);
+                    + " at position " + (offset + 1) + ": " + chars, chars, offset);
         }
     }
 
-    private static void assertPositionContains(String chars, char... expected)
+    private static void assertAllowedDateTimeSeparator(String chars)
     {
-        if (10 >= chars.length())
-        {
-            raiseDateTimeException(chars, "Unexpected end of input", 10);
-        }
-
-        boolean found = false;
         final char needle = chars.charAt(10);
-        for (char e : expected)
-        {
-            if (needle == e)
-            {
-                found = true;
-                break;
-            }
-        }
-        if (!found)
+        switch (needle)
         {
-            throw new DateTimeParseException("Expected character " + Arrays.toString(expected)
-                    + " at position " + (10 + 1) + " '" + chars + "'", chars, 10);
+            case SEPARATOR_UPPER:
+            case SEPARATOR_LOWER:
+            case SEPARATOR_SPACE:
+                return;
+
+            default:
+                throw new DateTimeParseException("Expected character " + Arrays.toString(new char[]{SEPARATOR_UPPER, SEPARATOR_LOWER, SEPARATOR_SPACE})
+                        + " at position " + (10 + 1) + ": " + chars, chars, 10);
         }
     }
 
@@ -182,7 +177,7 @@ private static TimezoneOffset parseTimezone(String chars, int offset)
     {
         if (offset >= chars.length())
         {
-            throw new DateTimeParseException("No timezone information: " + chars, chars, offset);
+            raiseMissingTimeZone(chars, offset);
         }
         final int len = chars.length();
         final int left = len - offset;
@@ -196,7 +191,7 @@ private static TimezoneOffset parseTimezone(String chars, int offset)
         final char sign = chars.charAt(offset);
         if (sign != PLUS && sign != MINUS)
         {
-            throw new DateTimeParseException("Invalid character starting at position " + offset + ": " + chars, chars, offset);
+            raiseUnexpectedCharacter(chars, offset);
         }
 
         if (left != 6)
@@ -224,7 +219,7 @@ private static void assertNoMoreChars(String chars, int lastUsed)
     {
         if (chars.length() > lastUsed + 1)
         {
-            throw new DateTimeParseException("Trailing junk data after position " + (lastUsed + 1) + ": " + chars, chars, lastUsed + 1);
+            throw new DateTimeParseException("Trailing junk data after position " + (lastUsed + 2) + ": " + chars, chars, lastUsed + 1);
         }
     }
 
@@ -275,7 +270,7 @@ private static Object parse(String chars, boolean raw)
         }
 
         // HOURS
-        assertPositionContains(chars, SEPARATOR_UPPER, SEPARATOR_LOWER, SEPARATOR_SPACE);
+        assertAllowedDateTimeSeparator(chars);
         final int hours = parsePositiveInt(chars, 11, 13);
 
         // MINUTES
@@ -303,98 +298,89 @@ private static DateTimeException raiseMissingField(Field field, final String cha
     private static Object handleTime(int year, int month, int day, int hour, int minute, String chars, boolean raw)
     {
         // From here the specification is more lenient
-        final int len = chars.length();
-        final int remaining = len - 17;
-        if (remaining == 2)
-        {
-            final int seconds = parsePositiveInt(chars, 17, 19);
-            if (raw)
+        final int length = chars.length();
+        if (length > 19)
+        {
+            TimezoneOffset offset = null;
+            int fractions = 0;
+            int fractionDigits = 0;
+            char c = chars.charAt(19);
+            if (c == FRACTION_SEPARATOR)
             {
-                return new DateTime(Field.SECOND, year, month, day, hour, minute, seconds, 0, null, 0);
-            }
-            throw new DateTimeParseException("No timezone information: " + chars, chars, 19);
-        }
-        else if (remaining == 0)
-        {
-            if (raw)
-            {
-                return new DateTime(Field.SECOND, year, month, day, hour, minute, 0, 0, null, 0);
-            }
-            throw new DateTimeParseException("No timezone information: " + chars, chars, 16);
-        }
-
-        TimezoneOffset offset = null;
-        int fractions = 0;
-        int fractionDigits = 0;
-        if (chars.length() < 20)
-        {
-            throw new DateTimeParseException("Unexpected end of input: " + chars, chars, 16);
-        }
-        char c = chars.charAt(19);
-        if (c == FRACTION_SEPARATOR)
-        {
             if (chars.length() < 21)
             {
-                throw new DateTimeParseException("Unexpected end of input: " + chars, chars, 20);
+                raiseUnexpectedEndOfText(chars, 20);
             }
-            // We have fractional seconds
-            int result = 0;
-            int idx = 20;
-            boolean nonDigitFound = false;
-            do
-            {
-                c = chars.charAt(idx);
-                if (c < ZERO || c > DIGIT_9)
+                // We have fractional seconds
+                int result = 0;
+                int idx = 20;
+                boolean nonDigitFound = false;
+                do
+                {
+                    c = chars.charAt(idx);
+                    if (c < ZERO || c > DIGIT_9)
+                    {
+                        nonDigitFound = true;
+                        fractionDigits = idx - 20;
+                        assertFractionDigits(chars, fractionDigits, idx);
+                        fractions = scale(-result, fractionDigits, chars, idx);
+                        offset = parseTimezone(chars, idx);
+                    }
+                    else
+                    {
+                        fractionDigits = idx - 19;
+                        assertFractionDigits(chars, fractionDigits, idx);
+                        result = (result << 1) + (result << 3);
+                        result -= c - ZERO;
+                    }
+                    idx++;
+                } while (idx < length && !nonDigitFound);
+
+                if (!nonDigitFound)
                 {
-                    nonDigitFound = true;
                     fractionDigits = idx - 20;
-                    assertFractionDigits(chars, fractionDigits, idx);
                     fractions = scale(-result, fractionDigits, chars, idx);
-                    offset = parseTimezone(chars, idx);
-                }
-                else
-                {
-                    fractionDigits = idx - 19;
-                    assertFractionDigits(chars, fractionDigits, idx);
-                    result = (result << 1) + (result << 3);
-                    result -= c - ZERO;
+                    if (!raw)
+                    {
+                        offset = parseTimezone(chars, idx);
+                    }
                 }
-                idx++;
-            } while (idx < len && !nonDigitFound);
+            }
+            else if (c == ZULU_UPPER || c == ZULU_LOWER)
+            {
+                // Do nothing we are done
+                offset = TimezoneOffset.UTC;
+            }
+            else if (c == PLUS || c == MINUS)
+            {
+                // No fractional seconds
+                offset = parseTimezone(chars, 19);
+            }
+            else
+            {
+                throw raiseUnexpectedCharacter(chars, 19);
+            }
 
-            if (!nonDigitFound)
+            final int second = parsePositiveInt(chars, 17, 19);
+
+            if (!raw)
             {
-                fractionDigits = idx - 20;
-                fractions = scale(-result, fractionDigits, chars, idx);
-                if (!raw)
-                {
-                    offset = parseTimezone(chars, idx);
-                }
+                leapSecondCheck(year, month, day, hour, minute, second, fractions, offset);
+                return OffsetDateTime.of(year, month, day, hour, minute, second, fractions, offset.toZoneOffset());
             }
+            return fractionDigits > 0 ? DateTime.of(year, month, day, hour, minute, second, fractions, offset, fractionDigits) : DateTime.of(year, month, day, hour, minute, second, offset);
         }
-        else if (c == ZULU_UPPER || c == ZULU_LOWER)
-        {
-            // Do nothing we are done
-            offset = TimezoneOffset.UTC;
-        }
-        else if (c == PLUS || c == MINUS)
+        else if (length == 19)
         {
-            // No fractional seconds
-            offset = parseTimezone(chars, 19);
-        }
-        else
-        {
-            raiseDateTimeException(chars, "Unexpected character at position 19", 19);
+            final int seconds = parsePositiveInt(chars, 17, 19);
+            if (raw)
+            {
+                return new DateTime(Field.SECOND, year, month, day, hour, minute, seconds, 0, null, 0);
+            }
+            raiseMissingTimeZone(chars, 19);
         }
 
-        final int second = parsePositiveInt(chars, 17, 19);
-
-        if (!raw)
-        {
-            leapSecondCheck(year, month, day, hour, minute, second, fractions, offset);
-            return OffsetDateTime.of(year, month, day, hour, minute, second, fractions, offset.toZoneOffset());
-        }
-        return fractionDigits > 0 ? DateTime.of(year, month, day, hour, minute, second, fractions, offset, fractionDigits) : DateTime.of(year, month, day, hour, minute, second, offset);
+        throw raiseUnexpectedEndOfText(chars, 16);
     }
 
     private static void assertFractionDigits(String chars, int fractionDigits, int idx)
@@ -428,11 +414,6 @@ private static void leapSecondCheck(int year, int month, int day, int hour, int
         }
     }
 
-    private static void raiseDateTimeException(String chars, String message, int index)
-    {
-        throw new DateTimeParseException(message + ": " + chars, chars, index);
-    }
-
     @Override
     public String formatUtc(OffsetDateTime date, int fractionDigits)
     {
@@ -462,7 +443,7 @@ private String doFormat(OffsetDateTime date, ZoneOffset adjustTo, Field lastIncl
         }
         final TimezoneOffset tz = TimezoneOffset.of(adjustTo);
 
-        final char[] buffer = new char[31];
+        final char[] buffer = new char[26 + fractionDigits];
 
         if (handleDatePart(lastIncluded, buffer, adjusted.getYear(), 0, 4, Field.YEAR))
         {
diff --git a/src/main/java/com/ethlo/time/internal/LimitedCharArrayIntegerUtil.java b/src/main/java/com/ethlo/time/internal/LimitedCharArrayIntegerUtil.java
index fee1e37..e884d99 100644
--- a/src/main/java/com/ethlo/time/internal/LimitedCharArrayIntegerUtil.java
+++ b/src/main/java/com/ethlo/time/internal/LimitedCharArrayIntegerUtil.java
@@ -20,8 +20,6 @@
  * #L%
  */
 
-import java.time.DateTimeException;
-import java.time.format.DateTimeParseException;
 import java.util.Arrays;
 
 public final class LimitedCharArrayIntegerUtil
@@ -53,7 +51,7 @@ public static int parsePositiveInt(final String strNum, int startInclusive, int
     {
         if (endExclusive > strNum.length())
         {
-            throw new DateTimeParseException("Unexpected end of expression at position " + strNum.length() + ": '" + strNum + "'", strNum, startInclusive);
+            ErrorUtil.raiseUnexpectedEndOfText(strNum, startInclusive);
         }
 
         int result = 0;
@@ -62,7 +60,7 @@ public static int parsePositiveInt(final String strNum, int startInclusive, int
             final char c = strNum.charAt(i);
             if (c < ZERO || c > DIGIT_9)
             {
-                throw new DateTimeParseException("Character " + c + " is not a digit", strNum, i);
+                ErrorUtil.raiseUnexpectedCharacter(strNum, i);
             }
             result = (result << 1) + (result << 3);
             result -= c - ZERO;
diff --git a/src/test/java/com/ethlo/time/ExternalParameterizedTest.java b/src/test/java/com/ethlo/time/ExternalParameterizedTest.java
index 87077be..7fbf64c 100644
--- a/src/test/java/com/ethlo/time/ExternalParameterizedTest.java
+++ b/src/test/java/com/ethlo/time/ExternalParameterizedTest.java
@@ -25,6 +25,7 @@
 import java.io.IOException;
 import java.time.DateTimeException;
 import java.time.Instant;
+import java.time.OffsetDateTime;
 import java.time.format.DateTimeParseException;
 import java.time.temporal.TemporalAccessor;
 import java.util.List;
@@ -59,14 +60,14 @@ void testAll(TestParam param)
             }
 
             // Compare to Java's parser result
-            final Instant expected = Instant.parse(param.getInput());
+            final Instant expected = getExpected(param);
             if (result instanceof DateTime)
             {
-                assertThat(((DateTime) result).toInstant()).isEqualTo(expected);
+                assertEqualInstant(((DateTime) result).toInstant(), expected);
             }
             else
             {
-                assertThat(Instant.from(result)).isEqualTo(expected);
+                assertEqualInstant(((OffsetDateTime) result).toInstant(), expected);
             }
         }
         catch (DateTimeException exc)
@@ -91,6 +92,35 @@ void testAll(TestParam param)
 
     }
 
+    private void assertEqualInstant(Instant result, Instant expected)
+    {
+        assertThat(result)
+                .overridingErrorMessage("Expected %s (%s), was %s (%s)", expected, asTs(expected), result, asTs(result))
+                .isEqualTo(expected);
+    }
+
+    private String asTs(Instant instant)
+    {
+        return instant.getEpochSecond() + "," + instant.getNano();
+    }
+
+    private Instant getExpected(TestParam testParam)
+    {
+        if (testParam.getExpected() != null)
+        {
+            return testParam.getExpected();
+        }
+
+        try
+        {
+            return Instant.parse(testParam.getInput());
+        }
+        catch (DateTimeException exc)
+        {
+            throw new IllegalArgumentException("Cannot parse using Instant: " + testParam.getInput() + ": " + exc.getMessage(), exc);
+        }
+    }
+
     public static List<TestParam> fromFile() throws IOException
     {
         final List<TestParam> result = new ObjectMapper()
diff --git a/src/test/java/com/ethlo/time/FieldTest.java b/src/test/java/com/ethlo/time/FieldTest.java
index 9e98464..5ff8cf6 100644
--- a/src/test/java/com/ethlo/time/FieldTest.java
+++ b/src/test/java/com/ethlo/time/FieldTest.java
@@ -26,7 +26,9 @@
 import java.time.OffsetDateTime;
 import java.time.Year;
 import java.time.YearMonth;
+import java.time.temporal.ChronoField;
 import java.time.temporal.Temporal;
+import java.time.temporal.UnsupportedTemporalTypeException;
 
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Tag;
@@ -36,7 +38,7 @@
 public class FieldTest
 {
     @Test
-    public void testGetKnownFields()
+    void testGetKnownFields()
     {
         assertThat(Field.valueOf(Year.class)).isEqualTo(Field.YEAR);
         assertThat(Field.valueOf(YearMonth.class)).isEqualTo(Field.MONTH);
@@ -45,8 +47,14 @@ public void testGetKnownFields()
     }
 
     @Test
-    public void testGetUnknown()
+    void testGetUnknown()
     {
         Assertions.assertThrows(IllegalArgumentException.class, () -> Field.valueOf(Temporal.class));
     }
+
+    @Test
+    void testUnknownField()
+    {
+        Assertions.assertThrows(UnsupportedTemporalTypeException.class, () -> Field.of(ChronoField.NANO_OF_DAY));
+    }
 }
diff --git a/src/test/java/com/ethlo/time/FormatterTest.java b/src/test/java/com/ethlo/time/FormatterTest.java
index fefb96a..2ca4045 100644
--- a/src/test/java/com/ethlo/time/FormatterTest.java
+++ b/src/test/java/com/ethlo/time/FormatterTest.java
@@ -1,5 +1,25 @@
 package com.ethlo.time;
 
+/*-
+ * #%L
+ * Internet Time Utility
+ * %%
+ * Copyright (C) 2017 - 2024 Morten Haraldsen (ethlo)
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * #L%
+ */
+
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 
@@ -11,11 +31,37 @@
 public class FormatterTest
 {
     @Test
-    void testFormat3()
+    void testFormatSpecifiedResolution()
     {
         final String s = "2017-02-21T10:00:00.000+12:00";
         final OffsetDateTime date = ITU.parseDateTime(s);
-        assertThat(ITU.formatUtcMilli(date)).isEqualTo("2017-02-20T22:00:00.000Z");
+        assertThat(ITU.format(date, 9)).isEqualTo("2017-02-21T10:00:00.000000000+12:00");
+    }
+
+    @Test
+    void testFormatYear()
+    {
+        assertThat(DateTime.ofYear(1234).toString()).isEqualTo("1234");
+    }
+
+    @Test
+    void testFormatYearMonth()
+    {
+        assertThat(DateTime.ofYearMonth(1234, 12).toString()).isEqualTo("1234-12");
+    }
+
+    @Test
+    void testFormatHigherGranularityThanAvailable()
+    {
+        final DateTimeException exc = assertThrows(DateTimeException.class, () -> DateTime.ofYear(1234).toString(Field.DAY));
+        assertThat(exc).hasMessage("Requested granularity was DAY, but contains only granularity YEAR");
+    }
+
+    @Test
+    void testFormatWithFractionDigits()
+    {
+        final DateTimeException exc = assertThrows(DateTimeException.class, () -> DateTime.ofYear(1234).toString(Field.DAY));
+        assertThat(exc).hasMessage("Requested granularity was DAY, but contains only granularity YEAR");
     }
 
     @Test
diff --git a/src/test/java/com/ethlo/time/ITUTest.java b/src/test/java/com/ethlo/time/ITUTest.java
index 4555487..8b543f0 100644
--- a/src/test/java/com/ethlo/time/ITUTest.java
+++ b/src/test/java/com/ethlo/time/ITUTest.java
@@ -299,7 +299,7 @@ public void handle(final Year year)
                 assertThat(year).isEqualTo(Year.parse(input));
             }
         }));
-        assertThat(exc).hasMessage("Expected character [T, t,  ] at position 11 '2017-03-05G'");
+        assertThat(exc).hasMessage("Expected character [T, t,  ] at position 11: 2017-03-05G");
     }
 
     @Test
diff --git a/src/test/java/com/ethlo/time/TemporalAccessorTest.java b/src/test/java/com/ethlo/time/TemporalAccessorTest.java
index a50bccd..1c430b2 100644
--- a/src/test/java/com/ethlo/time/TemporalAccessorTest.java
+++ b/src/test/java/com/ethlo/time/TemporalAccessorTest.java
@@ -1,5 +1,25 @@
 package com.ethlo.time;
 
+/*-
+ * #%L
+ * Internet Time Utility
+ * %%
+ * Copyright (C) 2017 - 2024 Morten Haraldsen (ethlo)
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * #L%
+ */
+
 import static org.assertj.core.api.Assertions.assertThat;
 
 import java.time.temporal.ChronoField;
diff --git a/src/test/java/com/ethlo/time/TestParam.java b/src/test/java/com/ethlo/time/TestParam.java
index f73e928..4f5a88a 100644
--- a/src/test/java/com/ethlo/time/TestParam.java
+++ b/src/test/java/com/ethlo/time/TestParam.java
@@ -20,7 +20,10 @@
  * #L%
  */
 
+import static org.assertj.core.api.Assertions.assertThat;
+
 import java.beans.ConstructorProperties;
+import java.time.Instant;
 
 public class TestParam
 {
@@ -28,18 +31,32 @@ public class TestParam
     private final boolean lenient;
     private final String error;
     private final int errorIndex;
+    private final Instant expected;
     private final String note;
 
-    @ConstructorProperties(value = {"input", "lenient", "error", "error_index", "note"})
-    public TestParam(String input, boolean lenient, String error, Integer errorIndex, String note)
+    @ConstructorProperties(value = {"input", "lenient", "error", "error_index", "expected", "note"})
+    public TestParam(String input, boolean lenient, String error, Integer errorIndex, String expected, String note)
     {
         this.input = input;
         this.lenient = lenient;
         this.error = error;
         this.errorIndex = errorIndex != null ? errorIndex : -1;
+        this.expected = parseExpected(expected);
         this.note = note;
     }
 
+    private Instant parseExpected(String expected)
+    {
+        if (expected == null)
+        {
+            return null;
+        }
+
+        final String[] parts = expected.split(",");
+        assertThat(parts.length).isEqualTo(2);
+        return Instant.ofEpochSecond(Long.parseLong(parts[0]), Long.parseLong(parts[1]));
+    }
+
     public String getInput()
     {
         return input;
@@ -66,6 +83,7 @@ public String toString()
         return "TestParam{" +
                 "input='" + input + '\'' +
                 ", lenient=" + lenient +
+                ", expected=" + expected + '\'' +
                 ", error='" + error + '\'' +
                 ", errorOffset=" + errorIndex + '\'' +
                 ", note=" + note +
@@ -76,4 +94,9 @@ public String getNote()
     {
         return note;
     }
+
+    public Instant getExpected()
+    {
+        return expected;
+    }
 }
diff --git a/src/test/java/com/ethlo/time/fuzzer/ParseDateTimeFuzzTest.java b/src/test/java/com/ethlo/time/fuzzer/ParseDateTimeFuzzTest.java
index 9cdc19c..832feb7 100644
--- a/src/test/java/com/ethlo/time/fuzzer/ParseDateTimeFuzzTest.java
+++ b/src/test/java/com/ethlo/time/fuzzer/ParseDateTimeFuzzTest.java
@@ -20,6 +20,7 @@
  * #L%
  */
 
+/*
 import java.time.DateTimeException;
 
 import com.code_intelligence.jazzer.api.FuzzedDataProvider;
@@ -40,3 +41,4 @@ void parse(FuzzedDataProvider data)
         }
     }
 }
+*/
\ No newline at end of file
diff --git a/src/test/java/com/ethlo/time/fuzzer/ParseLenientFuzzTest.java b/src/test/java/com/ethlo/time/fuzzer/ParseLenientFuzzTest.java
index 18fcb90..16d4629 100644
--- a/src/test/java/com/ethlo/time/fuzzer/ParseLenientFuzzTest.java
+++ b/src/test/java/com/ethlo/time/fuzzer/ParseLenientFuzzTest.java
@@ -22,6 +22,7 @@
 
 import java.time.DateTimeException;
 
+/*
 import com.code_intelligence.jazzer.api.FuzzedDataProvider;
 import com.ethlo.time.DateTime;
 import com.ethlo.time.ITU;
@@ -49,3 +50,4 @@ void parse(FuzzedDataProvider data)
         }
     }
 }
+*/
\ No newline at end of file
diff --git a/src/test/resources/test-data.json b/src/test/resources/test-data.json
index 8d7bd80..92f77d6 100644
--- a/src/test/resources/test-data.json
+++ b/src/test/resources/test-data.json
@@ -18,10 +18,6 @@
  * #L%
  */
 [
-    {
-        "input": "2020-22-12T12:11.56+04:30",
-        "error": "Unexpected character at position 16: ."
-    },
     {
         "input": "2017-02-21T15:27:39Z"
     },
@@ -35,51 +31,71 @@
         "input": "2017-02-21T15:27:39.123456789Z"
     },
     {
-        "input": "2017-02-21T15:27:39+00:00"
+        "input": "2017-02-21T15:27:39+00:00",
+        "expected": "1487690859,0"
+    },
+    {
+        "input": "2017-02-21T15:27:39.123+00:00",
+        "expected": "1487690859,123000000"
     },
     {
-        "input": "2017-02-21T15:27:39.123+00:00"
+        "input": "2017-02-21T15:27:39.123456+00:00",
+        "expected": "1487690859,123456000"
     },
     {
-        "input": "2017-02-21T15:27:39.123456+00:00"
+        "input": "2017-02-21T15:27:39.123456789+00:00",
+        "expected": "1487690859,123456789"
     },
     {
-        "input": "2017-02-21T15:27:39.123456789+00:00"
+        "input": "2017-02-21T15:27:39.1+00:00",
+        "expected": "1487690859,100000000"
     },
     {
-        "input": "2017-02-21T15:27:39.1+00:00"
+        "input": "2017-02-21T15:27:39.12+00:00",
+        "expected": "1487690859,120000000"
     },
     {
-        "input": "2017-02-21T15:27:39.12+00:00"
+        "input": "2017-02-21T15:27:39.123+00:00",
+        "expected": "1487690859,123000000"
     },
     {
-        "input": "2017-02-21T15:27:39.123+00:00"
+        "input": "2017-02-21T15:27:39.1234+00:00",
+        "expected": "1487690859,123400000"
     },
     {
-        "input": "2017-02-21T15:27:39.1234+00:00"
+        "input": "2017-02-21T15:27:39.12345+00:00",
+        "expected": "1487690859,123450000"
     },
     {
-        "input": "2017-02-21T15:27:39.12345+00:00"
+        "input": "2017-02-21T15:27:39.123456+00:00",
+        "expected": "1487690859,123456000"
     },
     {
-        "input": "2017-02-21T15:27:39.123456+00:00"
+        "input": "2017-02-21T15:27:39.1234567+00:00",
+        "expected": "1487690859,123456700"
     },
     {
-        "input": "2017-02-21T15:27:39.1234567+00:00"
+        "input": "2017-02-21T15:27:39.12345678+00:00",
+        "expected": "1487690859,123456780"
     },
     {
-        "input": "2017-02-21T15:27:39.12345678+00:00"
+        "input": "2017-02-21T15:27:39.123456789+00:00",
+        "expected": "1487690859,123456789"
     },
     {
-        "input": "2017-02-21T15:27:39.123456789+00:00"
+        "input": "2020-22-12T12:11.56+04:30",
+        "error": "Unexpected character . at position 17: 2020-22-12T12:11.56+04:30",
+        "error_index": 16
     },
     {
         "input": "2017-02-21T15",
-        "error": "Unexpected end of input: 2017-02-21T15"
+        "error": "Unexpected end of input: 2017-02-21T15",
+        "error_index": 13
     },
     {
         "input": "2017-02-21T15Z",
-        "error": "Expected character : at position 14 '2017-02-21T15Z'"
+        "error": "Expected character : at position 14: 2017-02-21T15Z",
+        "error_index": 13
     },
     {
         "input": "2017-02-21T15:27",
@@ -90,59 +106,69 @@
         "error": "No SECOND field found"
     },
     {
-        "input": "2017-02-21T15:27:19~10:00",
-        "error": "Unexpected character at position 19: 2017-02-21T15:27:19~10:00"
+        "input": "2017-02-21T15:27:22~10:00",
+        "error": "Unexpected character ~ at position 20: 2017-02-21T15:27:22~10:00",
+        "error_index": 19
     },
     {
         "input": "2017-02-21T15:27:39.+00:00",
-        "error": "Must have at least 1 fraction digit"
+        "error": "Must have at least 1 fraction digit: 2017-02-21T15:27:39.+00:00",
+        "error_index": 20
     },
     {
         "input": "2017-02-21T15:27:39",
-        "error": "No timezone information: 2017-02-21T15:27:39"
+        "error": "No timezone information: 2017-02-21T15:27:39",
+        "error_index": 19
     },
     {
         "input": "2017-02-21T15:27:39.123",
-        "error": "No timezone information: 2017-02-21T15:27:39.123"
+        "error": "No timezone information: 2017-02-21T15:27:39.123",
+        "error_index": 23
     },
     {
         "input": "2017-02-21T15:27:39.123456",
-        "error": "No timezone information: 2017-02-21T15:27:39.123456"
+        "error": "No timezone information: 2017-02-21T15:27:39.123456",
+        "error_index": 26
     },
     {
         "input": "2017-02-21T15:27:39.123456789",
-        "error": "No timezone information: 2017-02-21T15:27:39.123456789"
+        "error": "No timezone information: 2017-02-21T15:27:39.123456789",
+        "error_index": 29
     },
     {
         "input": "2017-02-21T15:27:39+0000",
-        "error": "Invalid timezone offset: 2017-02-21T15:27:39+0000"
+        "error": "Invalid timezone offset: 2017-02-21T15:27:39+0000",
+        "error_index": 19
     },
     {
         "input": "2017-02-21T15:27:39.123+0000",
-        "error": "Invalid timezone offset: 2017-02-21T15:27:39.123+0000"
+        "error": "Invalid timezone offset: 2017-02-21T15:27:39.123+0000",
+        "error_index": 23
     },
     {
         "input": "201702-21T15:27:39.123456+0000",
-        "error": "Expected character - at position 5 '201702-21T15:27:39.123456+0000'",
+        "error": "Expected character - at position 5: 201702-21T15:27:39.123456+0000",
         "error_index": 4
     },
     {
         "input": "20170221T15:27:39.123456789+0000",
-        "error": "Expected character - at position 5 '20170221T15:27:39.123456789+0000'",
+        "error": "Expected character - at position 5: 20170221T15:27:39.123456789+0000",
         "error_index": 4
     },
     {
         "input": "2017-12-21T12:20:45.987",
-        "error": "No timezone information: 2017-12-21T12:20:45.987"
+        "error": "No timezone information: 2017-12-21T12:20:45.987",
+        "error_index": 23
     },
     {
         "input": "2017-12-21T12:20:45.9b7Z",
-        "error": "Invalid character starting at position 21: 2017-12-21T12:20:45.9b7Z",
+        "error": "Unexpected character b at position 22: 2017-12-21T12:20:45.9b7Z",
         "error_index": 21
     },
     {
         "input": "2017-02-21T15:27:39.0000000",
-        "error": "No timezone information: 2017-02-21T15:27:39.0000000"
+        "error": "No timezone information: 2017-02-21T15:27:39.0000000",
+        "error_index": 27
     },
     {
         "input": "2017-02-21T15:27:39.000+30:00",
@@ -150,7 +176,8 @@
     },
     {
         "input": "2017-02-21T15:00:00.1234567891Z",
-        "error": "Too many fraction digits: 2017-02-21T15:00:00.1234567891Z"
+        "error": "Too many fraction digits: 2017-02-21T15:00:00.1234567891Z",
+        "error_index": 29
     },
     {
         "input": "2017-13-21T15:00:00Z",
@@ -179,32 +206,30 @@
     },
     {
         "input": "1994 11-05T08:15:30-05:00",
-        "error": "Expected character - at position 5 '1994 11-05T08:15:30-05:00'",
+        "error": "Expected character - at position 5: 1994 11-05T08:15:30-05:00",
         "error_index": 4,
         "note": "Invalid separator between year and month"
     },
     {
         "input": "199g-11-05T08:15:30-05:00",
-        "error": "Character g is not a digit",
+        "error": "Unexpected character g at position 4: 199g-11-05T08:15:30-05:00",
+        "error_index": 3,
         "note": "Non-digit in year"
     },
     {
         "input": "1994-11-05X08:15:30-05:00",
-        "error": "Expected character [T, t,  ] at position 11 '1994-11-05X08:15:30-05:00'",
+        "error": "Expected character [T, t,  ] at position 11: 1994-11-05X08:15:30-05:00",
+        "error_index": 10,
         "note": "invalid date/time separator"
     },
     {
         "input": "1994-11-05t08:15:30z",
         "note": "Lowercase 'z' as UTC timezone"
     },
-    {
-        "input": "1994-11-05 08:15:30Z",
-        "error": "Text '1994-11-05 08:15:30Z' could not be parsed at index 10",
-        "note": "Space as date/time separator"
-    },
     {
         "input": "2017-02-21T15:27:39+0000",
         "error": "Invalid timezone offset: 2017-02-21T15:27:39+0000",
+        "error_index": 19,
         "note": "Military format offset"
     },
     {
@@ -213,16 +238,34 @@
     },
     {
         "input": "",
-        "error": "Unexpected end of expression at position 0: ''"
+        "error_index": 0,
+        "error": "Unexpected end of input: "
     },
     {
         "input": "2017-02-21T15:00:00.123ZGGG",
-        "error": "Trailing junk data after position 24: 2017-02-21T15:00:00.123ZGGG"
+        "error": "Trailing junk data after position 25: 2017-02-21T15:00:00.123ZGGG",
+        "error_index": 24
     },
-    /** LENIENT **/
     {
         "input": "2020-12-31T22:22:2",
         "error": "Unexpected end of input: 2020-12-31T22:22:2",
+        "error_index": 16,
+        "lenient": true
+    },
+    {
+        "input": "2020-12-31T22:22:",
+        "error": "Unexpected end of input: 2020-12-31T22:22:",
+        "error_index": 16,
+        "lenient": true
+    },
+    {
+        "input": "2020-12-31T22:56",
+        "expected": "1609455360,0",
+        "lenient": true
+    },
+    {
+        "input": "2020-12-31",
+        "expected": "1609372800,0",
         "lenient": true
     }
 ]