Skip to content

Commit

Permalink
Improving accuracy. Before, times were only getting millisecond accur…
Browse files Browse the repository at this point in the history
…acy, even when the converted "to" data type could hold more than millisecond accuracy. Now, the nanosecond portion is being factored in, when the converted "to" datatype can hold it.
  • Loading branch information
jdereg committed Feb 17, 2024
1 parent 94982e4 commit ef92119
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,18 @@ static float toFloat(Object from, Converter converter) {
return toLong(from, converter);
}

/**
* @return double number of milliseconds. When integerized, the number returned is always the number of epoch
* milliseconds. If the Instant specified resolution further than milliseconds, the double returned captures
* that as fractional milliseconds.
* Example 1: "2024-02-12T11:38:00.123937482+01:00" (as an Instant) = 1707734280123.937482d
* Example 2: "2024-02-12T11:38:00.1239+01:00" (as an Instant) = 1707734280123.9d
*/
static double toDouble(Object from, Converter converter) {
return toLong(from, converter);
Instant instant = (Instant) from;
long millis = instant.toEpochMilli();
int nanos = instant.getNano();
return millis + (nanos % 1_000_000) / 1_000_000.0d;
}

static AtomicLong toAtomicLong(Object from, Converter converter) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ static long toLong(Object from, Converter converter) {
}

static double toDouble(Object from, Converter converter) {
return toInstant(from, converter).toEpochMilli();
Instant instant = toInstant(from, converter);
return InstantConversions.toDouble(instant, converter);
}

static LocalDateTime toLocalDateTime(Object from, Converter converter) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@ public ZoneId getZoneId() {
// ...
// {source-n, answer-n}

// Useful values for input
long now = System.currentTimeMillis();

/////////////////////////////////////////////////////////////
// Byte/byte
/////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -777,6 +780,7 @@ public ZoneId getZoneId() {
});
TEST_DB.put(pair(Date.class, Long.class), new Object[][]{
{new Date(Long.MIN_VALUE), Long.MIN_VALUE},
{new Date(now), now},
{new Date(Integer.MIN_VALUE), (long) Integer.MIN_VALUE},
{new Date(0), 0L},
{new Date(Integer.MAX_VALUE), (long) Integer.MAX_VALUE},
Expand All @@ -785,18 +789,22 @@ public ZoneId getZoneId() {
TEST_DB.put(pair(java.sql.Date.class, Long.class), new Object[][]{
{new java.sql.Date(Long.MIN_VALUE), Long.MIN_VALUE},
{new java.sql.Date(Integer.MIN_VALUE), (long) Integer.MIN_VALUE},
{new java.sql.Date(now), now},
{new java.sql.Date(0), 0L},
{new java.sql.Date(Integer.MAX_VALUE), (long) Integer.MAX_VALUE},
{new java.sql.Date(Long.MAX_VALUE), Long.MAX_VALUE},
});
TEST_DB.put(pair(Timestamp.class, Long.class), new Object[][]{
{new Timestamp(Long.MIN_VALUE), Long.MIN_VALUE},
{new Timestamp(Integer.MIN_VALUE), (long) Integer.MIN_VALUE},
{new Timestamp(now), now},
{new Timestamp(0), 0L},
{new Timestamp(Integer.MAX_VALUE), (long) Integer.MAX_VALUE},
{new Timestamp(Long.MAX_VALUE), Long.MAX_VALUE},
});
TEST_DB.put(pair(Instant.class, Long.class), new Object[][]{
{ZonedDateTime.parse("2024-02-12T11:38:00.123456789+01:00").toInstant(), 1707734280123L}, // maintains millis (best long can do)
{ZonedDateTime.parse("2024-02-12T11:38:00.123999+01:00").toInstant(), 1707734280123L}, // maintains millis (best long can do)
{ZonedDateTime.parse("2024-02-12T11:38:00+01:00").toInstant(), 1707734280000L},
});
TEST_DB.put(pair(LocalDate.class, Long.class), new Object[][]{
Expand All @@ -812,6 +820,16 @@ public ZoneId getZoneId() {
zdt = zdt.withZoneSameInstant(TOKYO_Z);
return zdt.toLocalDateTime();
}, 1707734280000L}, // Epoch millis in Tokyo timezone
{(Supplier<LocalDateTime>) () -> {
ZonedDateTime zdt = ZonedDateTime.parse("2024-02-12T11:38:00.123+01:00"); // maintains millis (best long can do)
zdt = zdt.withZoneSameInstant(TOKYO_Z);
return zdt.toLocalDateTime();
}, 1707734280123L}, // Epoch millis in Tokyo timezone
{(Supplier<LocalDateTime>) () -> {
ZonedDateTime zdt = ZonedDateTime.parse("2024-02-12T11:38:00.12399+01:00"); // maintains millis (best long can do)
zdt = zdt.withZoneSameInstant(TOKYO_Z);
return zdt.toLocalDateTime();
}, 1707734280123L}, // Epoch millis in Tokyo timezone
});
TEST_DB.put(pair(ZonedDateTime.class, Long.class), new Object[][]{
{ZonedDateTime.parse("2024-02-12T11:38:00+01:00"), 1707734280000L},
Expand All @@ -823,10 +841,19 @@ public ZoneId getZoneId() {
cal.setTimeZone(TOKYO_TZ);
cal.set(2024, Calendar.FEBRUARY, 12, 11, 38, 0);
return cal;
}, 1707705480000L}
}, 1707705480000L},
{(Supplier<Calendar>) () -> {
Calendar cal = Calendar.getInstance();
cal.clear();
cal.setTimeZone(TOKYO_TZ);
cal.setTimeInMillis(now); // Calendar maintains time to millisecond resolution
return cal;
}, now}
});
TEST_DB.put(pair(OffsetDateTime.class, Long.class), new Object[][]{
{OffsetDateTime.parse("2024-02-12T11:38:00+01:00"), 1707734280000L},
{OffsetDateTime.parse("2024-02-12T11:38:00.123+01:00"), 1707734280123L}, // maintains millis (best long can do)
{OffsetDateTime.parse("2024-02-12T11:38:00.12399+01:00"), 1707734280123L}, // maintains millis (best long can do)
});
TEST_DB.put(pair(Year.class, Long.class), new Object[][]{
{Year.of(2024), 2024L},
Expand Down Expand Up @@ -1049,6 +1076,10 @@ public ZoneId getZoneId() {
});
TEST_DB.put(pair(Instant.class, Double.class), new Object[][]{
{ZonedDateTime.parse("2024-02-12T11:38:00+01:00").toInstant(), 1707734280000d},
{ZonedDateTime.parse("2024-02-12T11:38:00.123+01:00").toInstant(), 1707734280123d},
{ZonedDateTime.parse("2024-02-12T11:38:00.1234+01:00").toInstant(), 1707734280123.4d}, // fractional milliseconds (nano support)
{ZonedDateTime.parse("2024-02-12T11:38:00.1239+01:00").toInstant(), 1707734280123.9d},
{ZonedDateTime.parse("2024-02-12T11:38:00.123937482+01:00").toInstant(), 1707734280123.937482d}, // nano = one-millionth of a milli
});
TEST_DB.put(pair(LocalDate.class, Double.class), new Object[][]{
{(Supplier<LocalDate>) () -> {
Expand All @@ -1063,10 +1094,26 @@ public ZoneId getZoneId() {
zdt = zdt.withZoneSameInstant(TOKYO_Z);
return zdt.toLocalDateTime();
}, 1.70773428E12}, // Epoch millis in Tokyo timezone
{(Supplier<LocalDateTime>) () -> {
ZonedDateTime zdt = ZonedDateTime.parse("2024-02-12T11:38:00.123+01:00");
zdt = zdt.withZoneSameInstant(TOKYO_Z);
return zdt.toLocalDateTime();
}, 1.707734280123E12}, // Epoch millis in Tokyo timezone
{(Supplier<LocalDateTime>) () -> {
ZonedDateTime zdt = ZonedDateTime.parse("2024-02-12T11:38:00.1239+01:00");
zdt = zdt.withZoneSameInstant(TOKYO_Z);
return zdt.toLocalDateTime();
}, 1.7077342801239E12}, // Epoch millis in Tokyo timezone
{(Supplier<LocalDateTime>) () -> {
ZonedDateTime zdt = ZonedDateTime.parse("2024-02-12T11:38:00.123937482+01:00");
zdt = zdt.withZoneSameInstant(TOKYO_Z);
return zdt.toLocalDateTime();
}, 1707734280123.937482d}, // Epoch millis in Tokyo timezone
});
TEST_DB.put(pair(ZonedDateTime.class, Double.class), new Object[][]{
{ZonedDateTime.parse("2024-02-12T11:38:00+01:00"), 1707734280000d},
});
// Left off here (need to fix ZoneDateTime and Timestamp)
TEST_DB.put(pair(Date.class, Double.class), new Object[][]{
{new Date(Long.MIN_VALUE), (double) Long.MIN_VALUE, true},
{new Date(Integer.MIN_VALUE), (double) Integer.MIN_VALUE, true},
Expand Down Expand Up @@ -1131,7 +1178,14 @@ public ZoneId getZoneId() {
cal.setTimeZone(TOKYO_TZ);
cal.set(2024, Calendar.FEBRUARY, 12, 11, 38, 0);
return cal;
}, 1707705480000d}
}, 1707705480000d},
{(Supplier<Calendar>) () -> {
Calendar cal = Calendar.getInstance();
cal.clear();
cal.setTimeZone(TOKYO_TZ);
cal.setTimeInMillis(now); // Calendar maintains time to millisecond resolution
return cal;
}, (double)now}
});
TEST_DB.put(pair(Number.class, Double.class), new Object[][]{
{2.5f, 2.5d}
Expand Down Expand Up @@ -1424,7 +1478,6 @@ public ZoneId getZoneId() {
/////////////////////////////////////////////////////////////
// BigInteger
/////////////////////////////////////////////////////////////
long now = System.currentTimeMillis();
TEST_DB.put(pair(Void.class, BigInteger.class), new Object[][]{
{ null, null },
});
Expand Down Expand Up @@ -1498,18 +1551,42 @@ public ZoneId getZoneId() {
{ new AtomicInteger(Integer.MIN_VALUE), BigInteger.valueOf(Integer.MIN_VALUE) },
{ new AtomicInteger(Integer.MAX_VALUE), BigInteger.valueOf(Integer.MAX_VALUE) },
});
// Left off here
TEST_DB.put(pair(AtomicLong.class, BigInteger.class), new Object[][]{
{new AtomicLong(0), BigInteger.ZERO},
{ new AtomicLong(-1), BigInteger.valueOf(-1) },
{ new AtomicLong(0), BigInteger.ZERO },
{ new AtomicLong(Long.MIN_VALUE), BigInteger.valueOf(Long.MIN_VALUE) },
{ new AtomicLong(Long.MAX_VALUE), BigInteger.valueOf(Long.MAX_VALUE) },
});
TEST_DB.put(pair(Date.class, BigInteger.class), new Object[][]{
{new Date(now), BigInteger.valueOf(now)},
{ new Date(0), BigInteger.valueOf(0), true },
{ new Date(now), BigInteger.valueOf(now), true },
{ new Date(Long.MIN_VALUE), BigInteger.valueOf(Long.MIN_VALUE), true },
{ new Date(Long.MAX_VALUE), BigInteger.valueOf(Long.MAX_VALUE), true },
});
TEST_DB.put(pair(java.sql.Date.class, BigInteger.class), new Object[][]{
{new java.sql.Date(now), BigInteger.valueOf(now)},
{ new java.sql.Date(0), BigInteger.valueOf(0), true },
{ new java.sql.Date(now), BigInteger.valueOf(now), true },
{ new java.sql.Date(Long.MIN_VALUE), BigInteger.valueOf(Long.MIN_VALUE), true },
{ new java.sql.Date(Long.MAX_VALUE), BigInteger.valueOf(Long.MAX_VALUE), true },
});
TEST_DB.put(pair(Timestamp.class, BigInteger.class), new Object[][]{
{new Timestamp(now), BigInteger.valueOf(now)},
{ new Timestamp(0), BigInteger.valueOf(0), true },
{ new Timestamp(now), BigInteger.valueOf(now), true },
// { (Supplier<Timestamp>) () -> {
// Timestamp ts = new Timestamp(now);
// ts.setNanos(1);
// return ts;
// }, (Supplier<BigInteger>) () -> {
// Timestamp ts = new Timestamp(now);
// long milliseconds = ts.getTime();
// int nanoseconds = ts.getNanos();
// BigInteger nanos = BigInteger.valueOf(milliseconds).multiply(BigInteger.valueOf(1000000))
// .add(BigInteger.valueOf(nanoseconds));
// return nanos;
// }
// },
{ new Timestamp(Long.MIN_VALUE), BigInteger.valueOf(Long.MIN_VALUE), true },
{ new Timestamp(Long.MAX_VALUE), BigInteger.valueOf(Long.MAX_VALUE), true },
});
TEST_DB.put(pair(Instant.class, BigInteger.class), new Object[][]{
{Instant.ofEpochMilli(now), BigInteger.valueOf(now)},
Expand Down

0 comments on commit ef92119

Please sign in to comment.