Skip to content

Commit

Permalink
Store the number of parsed fraction digits
Browse files Browse the repository at this point in the history
  • Loading branch information
ethlo committed Mar 10, 2022
1 parent ccd4c0d commit 7d922bb
Show file tree
Hide file tree
Showing 16 changed files with 96 additions and 76 deletions.
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.ethlo.time</groupId>
<artifactId>itu</artifactId>
<version>1.6.2-SNAPSHOT</version>
<version>1.7.0</version>
<name>Internet Time Utility</name>
<description>Extremely fast date/time parser and formatter - RFC 3339 (ISO 8601 profile) and W3C format
</description>
Expand Down
37 changes: 25 additions & 12 deletions src/main/java/com/ethlo/time/DateTime.java
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,9 @@ public class DateTime
private final int second;
private final int nano;
private final TimezoneOffset offset;
private final int fractionDigits;

public DateTime(final Field field, final int year, final int month, final int day, final int hour, final int minute, final int second, final int nano, final TimezoneOffset offset)
public DateTime(final Field field, final int year, final int month, final int day, final int hour, final int minute, final int second, final int nano, final TimezoneOffset offset, final int fractionDigits)
{
this.field = field;
this.year = year;
Expand All @@ -62,54 +63,55 @@ public DateTime(final Field field, final int year, final int month, final int da
this.second = assertSize(second, 0, 60, Field.SECOND);
this.nano = assertSize(nano, 0, 999_999_999, Field.NANO);
this.offset = offset;
this.fractionDigits = fractionDigits;
}

/**
* Create a new instance with second granularity from the input parameters
*/
public static DateTime of(int year, int month, int day, int hour, int minute, int second, TimezoneOffset offset)
{
return new DateTime(Field.SECOND, year, month, day, hour, minute, second, 0, offset);
return new DateTime(Field.SECOND, year, month, day, hour, minute, second, 0, offset, 0);
}

/**
* Create a new instance with nanosecond granularity from the input parameters
*/
public static DateTime of(int year, int month, int day, int hour, int minute, int second, int nanos, TimezoneOffset offset)
public static DateTime of(int year, int month, int day, int hour, int minute, int second, int nanos, TimezoneOffset offset, final int fractionDigits)
{
return new DateTime(Field.NANO, year, month, day, hour, minute, second, nanos, offset);
return new DateTime(Field.NANO, year, month, day, hour, minute, second, nanos, offset, fractionDigits);
}

/**
* Create a new instance with year granularity from the input parameters
*/
public static DateTime ofYear(int year)
{
return new DateTime(Field.YEAR, year, 0, 0, 0, 0, 0, 0, null);
return new DateTime(Field.YEAR, year, 0, 0, 0, 0, 0, 0, null, 0);
}

/**
* Create a new instance with year-month granularity from the input parameters
*/
public static DateTime ofYearMonth(int years, int months)
{
return new DateTime(Field.MONTH, years, months, 0, 0, 0, 0, 0, null);
return new DateTime(Field.MONTH, years, months, 0, 0, 0, 0, 0, null, 0);
}

/**
* Create a new instance with day granularity from the input parameters
*/
public static DateTime ofDate(int years, int months, int days)
{
return new DateTime(Field.DAY, years, months, days, 0, 0, 0, 0, null);
return new DateTime(Field.DAY, years, months, days, 0, 0, 0, 0, null, 0);
}

/**
* Create a new instance with minute granularity from the input parameters
*/
public static DateTime of(int years, int months, int days, int hours, int minute, TimezoneOffset offset)
{
return new DateTime(Field.MINUTE, years, months, days, hours, minute, 0, 0, offset);
return new DateTime(Field.MINUTE, years, months, days, hours, minute, 0, 0, offset, 0);
}

/**
Expand All @@ -120,7 +122,7 @@ public static DateTime of(int years, int months, int days, int hours, int minute
*/
public static DateTime of(OffsetDateTime dateTime)
{
return DateTime.of(dateTime.getYear(), dateTime.getMonthValue(), dateTime.getDayOfMonth(), dateTime.getHour(), dateTime.getMinute(), dateTime.getSecond(), dateTime.getNano(), TimezoneOffset.of(dateTime.getOffset()));
return DateTime.of(dateTime.getYear(), dateTime.getMonthValue(), dateTime.getDayOfMonth(), dateTime.getHour(), dateTime.getMinute(), dateTime.getSecond(), dateTime.getNano(), TimezoneOffset.of(dateTime.getOffset()), 9);
}

private int assertSize(int value, int min, int max, Field field)
Expand Down Expand Up @@ -367,14 +369,24 @@ private String toString(final DateTime date, final Field lastIncluded, final int
}

/**
* Formats this date-time as a date/date-time with the same fields as was parsed and no fractions in the second.
* Return the number of significant fraction digits in the second.
*
* @return The number of significant fraction digits
*/
public int getFractionDigits()
{
return fractionDigits;
}

/**
* Formats this date-time as a date/date-time with the same fields as was parsed
*
* @return The formatted date/date-time string
*/
@Override
public String toString()
{
return toString(field);
return fractionDigits > 0 ? toString(fractionDigits) : toString(field);
}

/**
Expand All @@ -399,6 +411,7 @@ public boolean equals(final Object o)
&& minute == dateTime.minute
&& second == dateTime.second
&& nano == dateTime.nano
&& fractionDigits == dateTime.fractionDigits
&& field == dateTime.field
&& Objects.equals(offset, dateTime.offset);
}
Expand All @@ -409,6 +422,6 @@ public boolean equals(final Object o)
@Override
public int hashCode()
{
return Objects.hash(field.ordinal(), year, month, day, hour, minute, second, nano, offset);
return Objects.hash(field.ordinal(), year, month, day, hour, minute, second, nano, offset, fractionDigits);
}
}
12 changes: 8 additions & 4 deletions src/main/java/com/ethlo/time/ITU.java
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,9 @@ public static String formatUtc(OffsetDateTime offsetDateTime, int fractionDigits

/**
* Format the input as an ISO format string, limited to the granularity of the specified field, in the UTC timezone.
*
* @param offsetDateTime The date-time to format
* @param lastIncluded The last included field
* @param lastIncluded The last included field
* @return The formatted string
*/
public static String formatUtc(OffsetDateTime offsetDateTime, Field lastIncluded)
Expand Down Expand Up @@ -174,7 +175,8 @@ public static String formatUtcNano(final OffsetDateTime offsetDateTime)

/**
* Parse the input, and use callbacks for the type of date/date-time it contains. This allows you to handle different granularity inputs with ease!
* @param text The text to parse as a date/date-time
*
* @param text The text to parse as a date/date-time
* @param temporalConsumer The consumer of the found date/date-time
*/
public static void parse(final String text, final TemporalConsumer temporalConsumer)
Expand Down Expand Up @@ -207,7 +209,8 @@ else if (dateTime.includesGranularity(Field.MONTH))

/**
* Parse the input, and use callbacks for the type of date/date-time it contains. This allows you to handle different granularity inputs with ease!
* @param text The text to parse as a date/date-time
*
* @param text The text to parse as a date/date-time
* @param temporalHandler The handler of the found date/date-time
*/

Expand Down Expand Up @@ -241,7 +244,8 @@ else if (dateTime.includesGranularity(Field.MONTH))

/**
* Check if the input is valid for one of the specified types
* @param text The input to check
*
* @param text The input to check
* @param types The types that are considered valid
* @return True if valid, otherwise false
*/
Expand Down
1 change: 1 addition & 0 deletions src/main/java/com/ethlo/time/TemporalHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@

/**
* Handler for flexibly dealing with different granularity date/date-times
*
* @param <T> The return type of the functions
*/
public interface TemporalHandler<T>
Expand Down
6 changes: 6 additions & 0 deletions src/main/java/com/ethlo/time/TimezoneOffset.java
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@ public ZoneOffset toZoneOffset()
return ZoneOffset.ofHoursMinutes(hours, minutes);
}

/**
* @hidden
*/
@Override
public boolean equals(final Object o)
{
Expand All @@ -101,6 +104,9 @@ public boolean equals(final Object o)
return hours == that.hours && minutes == that.minutes;
}

/**
* @hidden
*/
@Override
public int hashCode()
{
Expand Down
73 changes: 36 additions & 37 deletions src/main/java/com/ethlo/time/internal/EthloITU.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,12 @@

public class EthloITU extends AbstractRfc3339 implements W3cDateTimeUtil
{
private static final EthloITU instance = new EthloITU();

private static final char PLUS = '+';
private static final char MINUS = '-';
public static final char DATE_SEPARATOR = '-';
public static final char TIME_SEPARATOR = ':';
public static final char SEPARATOR_UPPER = 'T';
private static final EthloITU instance = new EthloITU();
private static final char PLUS = '+';
private static final char MINUS = '-';
private static final char SEPARATOR_LOWER = 't';
private static final char SEPARATOR_SPACE = ' ';
private static final char FRACTION_SEPARATOR = '.';
Expand All @@ -64,6 +63,33 @@ public static EthloITU getInstance()
return instance;
}

public static String finish(char[] buf, int length, final TimezoneOffset tz)
{
int tzLen = 0;
if (tz != null)
{
tzLen = writeTz(buf, length, tz);
}
return new String(buf, 0, length + tzLen);
}

private static int writeTz(char[] buf, int start, TimezoneOffset tz)
{
if (tz.equals(TimezoneOffset.UTC))
{
buf[start] = ZULU_UPPER;
return 1;
}
else
{
buf[start] = tz.getTotalSeconds() < 0 ? MINUS : PLUS;
LimitedCharArrayIntegerUtil.toString(Math.abs(tz.getHours()), buf, start + 1, 2);
buf[start + 3] = TIME_SEPARATOR;
LimitedCharArrayIntegerUtil.toString(Math.abs(tz.getMinutes()), buf, start + 4, 2);
return 6;
}
}

private int getHour(final char[] chars)
{
return parsePositiveInt(chars, 11, 13);
Expand Down Expand Up @@ -260,33 +286,6 @@ private boolean handleDatePart(final Field lastIncluded, final char[] buffer, fi
return lastIncluded == field;
}

public static String finish(char[] buf, int length, final TimezoneOffset tz)
{
int tzLen = 0;
if (tz != null)
{
tzLen = writeTz(buf, length, tz);
}
return new String(buf, 0, length + tzLen);
}

private static int writeTz(char[] buf, int start, TimezoneOffset tz)
{
if (tz.equals(TimezoneOffset.UTC))
{
buf[start] = ZULU_UPPER;
return 1;
}
else
{
buf[start] = tz.getTotalSeconds() < 0 ? MINUS : PLUS;
LimitedCharArrayIntegerUtil.toString(Math.abs(tz.getHours()), buf, start + 1, 2);
buf[start + 3] = TIME_SEPARATOR;
LimitedCharArrayIntegerUtil.toString(Math.abs(tz.getMinutes()), buf, start + 4, 2);
return 6;
}
}

private void addFractions(char[] buf, int fractionDigits, int nano)
{
final double d = widths[fractionDigits - 1];
Expand Down Expand Up @@ -402,12 +401,12 @@ private DateTime handleSeconds(int year, int month, int day, int hour, int minut
if (remaining == 0)
{
final int seconds = getSeconds(chars);
return leapSecondCheck(year, month, day, hour, minute, seconds, 0, null, false);
return leapSecondCheck(year, month, day, hour, minute, seconds, 0, null, 0);
}

TimezoneOffset offset = null;
int fractions = 0;
boolean hasFractions = false;
int fractionDigits = 0;
final char c = chars[19];
if (remaining == 1 && (c == ZULU_UPPER || c == ZULU_LOWER))
{
Expand All @@ -424,7 +423,7 @@ else if (remaining >= 1 && c == FRACTION_SEPARATOR)
// We have an end of fractions
final int len = idx - 20;
fractions = getFractions(chars, idx, len);
hasFractions = true;
fractionDigits = len;
offset = parseTimezone(chars, idx);
}
else
Expand All @@ -442,10 +441,10 @@ else if (remaining >= 1 && (c == PLUS || c == MINUS))
raiseDateTimeException(chars, "Unexpected character at position 19");
}

return leapSecondCheck(year, month, day, hour, minute, getSeconds(chars), fractions, offset, hasFractions);
return leapSecondCheck(year, month, day, hour, minute, getSeconds(chars), fractions, offset, fractionDigits);
}

private DateTime leapSecondCheck(int year, int month, int day, int hour, int minute, int second, int nanos, TimezoneOffset offset, final boolean hasFractions)
private DateTime leapSecondCheck(int year, int month, int day, int hour, int minute, int second, int nanos, TimezoneOffset offset, final int fractionDigits)
{
if (second == LEAP_SECOND_SECONDS)
{
Expand All @@ -466,7 +465,7 @@ private DateTime leapSecondCheck(int year, int month, int day, int hour, int min
}
}
}
return hasFractions ? DateTime.of(year, month, day, hour, minute, second, nanos, offset) : DateTime.of(year, month, day, hour, minute, second, offset);
return fractionDigits > 0 ? DateTime.of(year, month, day, hour, minute, second, nanos, offset, fractionDigits) : DateTime.of(year, month, day, hour, minute, second, offset);
}

private void raiseDateTimeException(char[] chars, String message)
Expand Down
3 changes: 2 additions & 1 deletion src/test/java/com/ethlo/time/AbstractTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,10 @@
* #L%
*/

import org.junit.jupiter.api.BeforeEach;

import com.ethlo.time.internal.Rfc3339Formatter;
import com.ethlo.time.internal.Rfc3339Parser;
import org.junit.jupiter.api.BeforeEach;

public abstract class AbstractTest
{
Expand Down
3 changes: 2 additions & 1 deletion src/test/java/com/ethlo/time/CharArrayUtilTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,10 @@

import java.util.Arrays;

import com.ethlo.time.internal.LimitedCharArrayIntegerUtil;
import org.junit.jupiter.api.Test;

import com.ethlo.time.internal.LimitedCharArrayIntegerUtil;

public class CharArrayUtilTest
{
@Test
Expand Down
11 changes: 2 additions & 9 deletions src/test/java/com/ethlo/time/DateTimeTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,11 @@
* #L%
*/

import org.junit.jupiter.api.Assertions;
import static org.assertj.core.api.Assertions.assertThat;

import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;

import java.time.LocalDate;
import java.time.OffsetDateTime;
import java.time.Year;
import java.time.YearMonth;
import java.time.temporal.Temporal;

import static org.assertj.core.api.Assertions.assertThat;

@Tag("CorrectnessTest")
public class DateTimeTest
{
Expand Down
3 changes: 2 additions & 1 deletion src/test/java/com/ethlo/time/FormatterBenchmarkTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,12 @@
import java.time.OffsetDateTime;
import java.util.concurrent.TimeUnit;

import com.ethlo.time.internal.Rfc3339Formatter;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.infra.Blackhole;

import com.ethlo.time.internal.Rfc3339Formatter;

@OutputTimeUnit(TimeUnit.NANOSECONDS)
public abstract class FormatterBenchmarkTest
{
Expand Down
Loading

0 comments on commit 7d922bb

Please sign in to comment.