Skip to content

Commit

Permalink
Making sure that times that handle nanos, support the nanos on double…
Browse files Browse the repository at this point in the history
… and BigDecimal
  • Loading branch information
jdereg committed Feb 18, 2024
1 parent ef92119 commit d8ce0ac
Show file tree
Hide file tree
Showing 9 changed files with 282 additions and 110 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package com.cedarsoftware.util.convert;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.Timestamp;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZonedDateTime;
import java.util.UUID;

/**
* @author John DeRegnaucourt ([email protected])
* <br>
* Copyright (c) Cedar Software LLC
* <br><br>
* 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
* <br><br>
* <a href="http://www.apache.org/licenses/LICENSE-2.0">License</a>
* <br><br>
* 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.
*/
final class BigDecimalConversions {
static Instant toInstant(Object from, Converter converter) {
BigDecimal time = (BigDecimal) from;
long seconds = time.longValue() / 1000;
int nanos = time.remainder(BigDecimal.valueOf(1000)).multiply(BigDecimal.valueOf(1_000_000)).intValue();
return Instant.ofEpochSecond(seconds, nanos);
}

static LocalDateTime toLocalDateTime(Object from, Converter converter) {
return toZonedDateTime(from, converter).toLocalDateTime();
}

static ZonedDateTime toZonedDateTime(Object from, Converter converter) {
return toInstant(from, converter).atZone(converter.getOptions().getZoneId());
}

static Timestamp toTimestamp(Object from, Converter converter) {
return Timestamp.from(toInstant(from, converter));
}

static BigInteger toBigInteger(Object from, Converter converter) {
return ((BigDecimal)from).toBigInteger();
}

static String toString(Object from, Converter converter) {
return ((BigDecimal) from).stripTrailingZeros().toPlainString();
}

static UUID toUUID(Object from, Converter converter) {
BigInteger bigInt = ((BigDecimal) from).toBigInteger();
return BigIntegerConversions.toUUID(bigInt, converter);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package com.cedarsoftware.util.convert;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.UUID;

/**
* @author John DeRegnaucourt ([email protected])
* <br>
* Copyright (c) Cedar Software LLC
* <br><br>
* 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
* <br><br>
* <a href="http://www.apache.org/licenses/LICENSE-2.0">License</a>
* <br><br>
* 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.
*/
final class BigIntegerConversions {
static BigDecimal toBigDecimal(Object from, Converter converter) {
return new BigDecimal((BigInteger)from);
}

static UUID toUUID(Object from, Converter converter) {
BigInteger bigInteger = (BigInteger) from;
if (bigInteger.signum() < 0) {
throw new IllegalArgumentException("Cannot convert a negative number [" + bigInteger + "] to a UUID");
}
StringBuilder hex = new StringBuilder(bigInteger.toString(16));

// Pad the string to 32 characters with leading zeros (if necessary)
while (hex.length() < 32) {
hex.insert(0, "0");
}

// Split into two 64-bit parts
String highBitsHex = hex.substring(0, 16);
String lowBitsHex = hex.substring(16, 32);

// Combine and format into standard UUID format
String uuidString = highBitsHex.substring(0, 8) + "-" +
highBitsHex.substring(8, 12) + "-" +
highBitsHex.substring(12, 16) + "-" +
lowBitsHex.substring(0, 4) + "-" +
lowBitsHex.substring(4, 16);

// Create UUID from string
return UUID.fromString(uuidString);
}
}
30 changes: 15 additions & 15 deletions src/main/java/com/cedarsoftware/util/convert/Converter.java
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ private static void buildFactoryConversions() {
CONVERSION_DB.put(pair(ZonedDateTime.class, Double.class), ZonedDateTimeConversions::toDouble);
CONVERSION_DB.put(pair(Date.class, Double.class), DateConversions::toDouble);
CONVERSION_DB.put(pair(java.sql.Date.class, Double.class), DateConversions::toDouble);
CONVERSION_DB.put(pair(Timestamp.class, Double.class), DateConversions::toDouble);
CONVERSION_DB.put(pair(Timestamp.class, Double.class), TimestampConversions::toDouble);
CONVERSION_DB.put(pair(AtomicBoolean.class, Double.class), AtomicBooleanConversions::toDouble);
CONVERSION_DB.put(pair(AtomicInteger.class, Double.class), NumberConversions::toDouble);
CONVERSION_DB.put(pair(AtomicLong.class, Double.class), NumberConversions::toDouble);
Expand Down Expand Up @@ -293,7 +293,7 @@ private static void buildFactoryConversions() {
CONVERSION_DB.put(pair(Boolean.class, BigInteger.class), BooleanConversions::toBigInteger);
CONVERSION_DB.put(pair(Character.class, BigInteger.class), CharacterConversions::toBigInteger);
CONVERSION_DB.put(pair(BigInteger.class, BigInteger.class), Converter::identity);
CONVERSION_DB.put(pair(BigDecimal.class, BigInteger.class), NumberConversions::bigDecimalToBigInteger);
CONVERSION_DB.put(pair(BigDecimal.class, BigInteger.class), BigDecimalConversions::toBigInteger);
CONVERSION_DB.put(pair(AtomicBoolean.class, BigInteger.class), AtomicBooleanConversions::toBigInteger);
CONVERSION_DB.put(pair(AtomicInteger.class, BigInteger.class), NumberConversions::integerTypeToBigInteger);
CONVERSION_DB.put(pair(AtomicLong.class, BigInteger.class), NumberConversions::integerTypeToBigInteger);
Expand Down Expand Up @@ -323,13 +323,13 @@ private static void buildFactoryConversions() {
CONVERSION_DB.put(pair(Boolean.class, BigDecimal.class), BooleanConversions::toBigDecimal);
CONVERSION_DB.put(pair(Character.class, BigDecimal.class), CharacterConversions::toBigDecimal);
CONVERSION_DB.put(pair(BigDecimal.class, BigDecimal.class), Converter::identity);
CONVERSION_DB.put(pair(BigInteger.class, BigDecimal.class), NumberConversions::bigIntegerToBigDecimal);
CONVERSION_DB.put(pair(BigInteger.class, BigDecimal.class), BigIntegerConversions::toBigDecimal);
CONVERSION_DB.put(pair(AtomicBoolean.class, BigDecimal.class), AtomicBooleanConversions::toBigDecimal);
CONVERSION_DB.put(pair(AtomicInteger.class, BigDecimal.class), NumberConversions::integerTypeToBigDecimal);
CONVERSION_DB.put(pair(AtomicLong.class, BigDecimal.class), NumberConversions::integerTypeToBigDecimal);
CONVERSION_DB.put(pair(Date.class, BigDecimal.class), DateConversions::toBigDecimal);
CONVERSION_DB.put(pair(java.sql.Date.class, BigDecimal.class), DateConversions::toBigDecimal);
CONVERSION_DB.put(pair(Timestamp.class, BigDecimal.class), DateConversions::toBigDecimal);
CONVERSION_DB.put(pair(Timestamp.class, BigDecimal.class), TimestampConversions::toBigDecimal);
CONVERSION_DB.put(pair(Instant.class, BigDecimal.class), InstantConversions::toBigDecimal);
CONVERSION_DB.put(pair(LocalDate.class, BigDecimal.class), LocalDateConversions::toBigDecimal);
CONVERSION_DB.put(pair(LocalDateTime.class, BigDecimal.class), LocalDateTimeConversions::toBigDecimal);
Expand Down Expand Up @@ -466,9 +466,9 @@ private static void buildFactoryConversions() {
CONVERSION_DB.put(pair(Short.class, Timestamp.class), UNSUPPORTED);
CONVERSION_DB.put(pair(Integer.class, Timestamp.class), UNSUPPORTED);
CONVERSION_DB.put(pair(Long.class, Timestamp.class), NumberConversions::toTimestamp);
CONVERSION_DB.put(pair(Double.class, Timestamp.class), NumberConversions::toTimestamp);
CONVERSION_DB.put(pair(Double.class, Timestamp.class), DoubleConversions::toTimestamp);
CONVERSION_DB.put(pair(BigInteger.class, Timestamp.class), NumberConversions::toTimestamp);
CONVERSION_DB.put(pair(BigDecimal.class, Timestamp.class), NumberConversions::toTimestamp);
CONVERSION_DB.put(pair(BigDecimal.class, Timestamp.class), BigDecimalConversions::toTimestamp);
CONVERSION_DB.put(pair(AtomicInteger.class, Timestamp.class), UNSUPPORTED);
CONVERSION_DB.put(pair(AtomicLong.class, Timestamp.class), NumberConversions::toTimestamp);
CONVERSION_DB.put(pair(Timestamp.class, Timestamp.class), DateConversions::toTimestamp);
Expand Down Expand Up @@ -538,9 +538,9 @@ private static void buildFactoryConversions() {
CONVERSION_DB.put(pair(Short.class, LocalDateTime.class), UNSUPPORTED);
CONVERSION_DB.put(pair(Integer.class, LocalDateTime.class), UNSUPPORTED);
CONVERSION_DB.put(pair(Long.class, LocalDateTime.class), NumberConversions::toLocalDateTime);
CONVERSION_DB.put(pair(Double.class, LocalDateTime.class), NumberConversions::toLocalDateTime);
CONVERSION_DB.put(pair(Double.class, LocalDateTime.class), DoubleConversions::toLocalDateTime);
CONVERSION_DB.put(pair(BigInteger.class, LocalDateTime.class), NumberConversions::toLocalDateTime);
CONVERSION_DB.put(pair(BigDecimal.class, LocalDateTime.class), NumberConversions::toLocalDateTime);
CONVERSION_DB.put(pair(BigDecimal.class, LocalDateTime.class), BigDecimalConversions::toLocalDateTime);
CONVERSION_DB.put(pair(AtomicInteger.class, LocalDateTime.class), UNSUPPORTED);
CONVERSION_DB.put(pair(AtomicLong.class, LocalDateTime.class), NumberConversions::toLocalDateTime);
CONVERSION_DB.put(pair(java.sql.Date.class, LocalDateTime.class), DateConversions::toLocalDateTime);
Expand Down Expand Up @@ -587,9 +587,9 @@ private static void buildFactoryConversions() {
CONVERSION_DB.put(pair(Short.class, ZonedDateTime.class), UNSUPPORTED);
CONVERSION_DB.put(pair(Integer.class, ZonedDateTime.class), UNSUPPORTED);
CONVERSION_DB.put(pair(Long.class, ZonedDateTime.class), NumberConversions::toZonedDateTime);
CONVERSION_DB.put(pair(Double.class, ZonedDateTime.class), NumberConversions::toZonedDateTime);
CONVERSION_DB.put(pair(Double.class, ZonedDateTime.class), DoubleConversions::toZonedDateTime);
CONVERSION_DB.put(pair(BigInteger.class, ZonedDateTime.class), NumberConversions::toZonedDateTime);
CONVERSION_DB.put(pair(BigDecimal.class, ZonedDateTime.class), NumberConversions::toZonedDateTime);
CONVERSION_DB.put(pair(BigDecimal.class, ZonedDateTime.class), BigDecimalConversions::toZonedDateTime);
CONVERSION_DB.put(pair(AtomicInteger.class, ZonedDateTime.class), UNSUPPORTED);
CONVERSION_DB.put(pair(AtomicLong.class, ZonedDateTime.class), NumberConversions::toZonedDateTime);
CONVERSION_DB.put(pair(java.sql.Date.class, ZonedDateTime.class), DateConversions::toZonedDateTime);
Expand Down Expand Up @@ -622,8 +622,8 @@ private static void buildFactoryConversions() {
CONVERSION_DB.put(pair(Void.class, UUID.class), VoidConversions::toNull);
CONVERSION_DB.put(pair(UUID.class, UUID.class), Converter::identity);
CONVERSION_DB.put(pair(String.class, UUID.class), StringConversions::toUUID);
CONVERSION_DB.put(pair(BigInteger.class, UUID.class), NumberConversions::bigIntegerToUUID);
CONVERSION_DB.put(pair(BigDecimal.class, UUID.class), NumberConversions::bigDecimalToUUID);
CONVERSION_DB.put(pair(BigInteger.class, UUID.class), BigIntegerConversions::toUUID);
CONVERSION_DB.put(pair(BigDecimal.class, UUID.class), BigDecimalConversions::toUUID);
CONVERSION_DB.put(pair(Map.class, UUID.class), MapConversions::toUUID);

// Class conversions supported
Expand All @@ -649,7 +649,7 @@ private static void buildFactoryConversions() {
CONVERSION_DB.put(pair(Boolean.class, String.class), StringConversions::toString);
CONVERSION_DB.put(pair(Character.class, String.class), CharacterConversions::toString);
CONVERSION_DB.put(pair(BigInteger.class, String.class), StringConversions::toString);
CONVERSION_DB.put(pair(BigDecimal.class, String.class), NumberConversions::bigDecimalToString);
CONVERSION_DB.put(pair(BigDecimal.class, String.class), BigDecimalConversions::toString);
CONVERSION_DB.put(pair(AtomicBoolean.class, String.class), StringConversions::toString);
CONVERSION_DB.put(pair(AtomicInteger.class, String.class), StringConversions::toString);
CONVERSION_DB.put(pair(AtomicLong.class, String.class), StringConversions::toString);
Expand Down Expand Up @@ -728,9 +728,9 @@ private static void buildFactoryConversions() {
CONVERSION_DB.put(pair(Short.class, Instant.class), UNSUPPORTED);
CONVERSION_DB.put(pair(Integer.class, Instant.class), UNSUPPORTED);
CONVERSION_DB.put(pair(Long.class, Instant.class), NumberConversions::toInstant);
CONVERSION_DB.put(pair(Double.class, Instant.class), NumberConversions::toInstant);
CONVERSION_DB.put(pair(Double.class, Instant.class), DoubleConversions::toInstant);
CONVERSION_DB.put(pair(BigInteger.class, Instant.class), NumberConversions::toInstant);
CONVERSION_DB.put(pair(BigDecimal.class, Instant.class), NumberConversions::toInstant);
CONVERSION_DB.put(pair(BigDecimal.class, Instant.class), BigDecimalConversions::toInstant);
CONVERSION_DB.put(pair(AtomicInteger.class, Instant.class), UNSUPPORTED);
CONVERSION_DB.put(pair(AtomicLong.class, Instant.class), NumberConversions::toInstant);
CONVERSION_DB.put(pair(java.sql.Date.class, Instant.class), DateConversions::toInstant);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package com.cedarsoftware.util.convert;

import java.sql.Timestamp;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZonedDateTime;

/**
* @author John DeRegnaucourt ([email protected])
* <br>
* Copyright (c) Cedar Software LLC
* <br><br>
* 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
* <br><br>
* <a href="http://www.apache.org/licenses/LICENSE-2.0">License</a>
* <br><br>
* 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.
*/
final class DoubleConversions {
private DoubleConversions() { }

static Instant toInstant(Object from, Converter converter) {
double d = (Double) from;
long seconds = (long) d / 1000;
int nanoAdjustment = (int) ((d - seconds * 1000) * 1_000_000);
return Instant.ofEpochSecond(seconds, nanoAdjustment);
}

static LocalDateTime toLocalDateTime(Object from, Converter converter) {
return toZonedDateTime(from, converter).toLocalDateTime();
}

static ZonedDateTime toZonedDateTime(Object from, Converter converter) {
return toInstant(from, converter).atZone(converter.getOptions().getZoneId());
}

static Timestamp toTimestamp(Object from, Converter converter) {
double milliseconds = (Double) from;
long millisPart = (long) milliseconds;
int nanosPart = (int) ((milliseconds - millisPart) * 1_000_000);
Timestamp timestamp = new Timestamp(millisPart);
timestamp.setNanos(timestamp.getNanos() + nanosPart);
return timestamp;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,7 @@ static ZonedDateTime toZonedDateTime(Object from, Converter converter) {
static long toLong(Object from, Converter converter) {
return ((Instant) from).toEpochMilli();
}

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
Expand All @@ -66,9 +62,9 @@ static float toFloat(Object from, Converter converter) {
*/
static double toDouble(Object from, Converter converter) {
Instant instant = (Instant) from;
long millis = instant.toEpochMilli();
int nanos = instant.getNano();
return millis + (nanos % 1_000_000) / 1_000_000.0d;
long seconds = instant.getEpochSecond();
int nanoAdjustment = instant.getNano();
return (double) seconds * 1000 + (double) nanoAdjustment / 1_000_000;
}

static AtomicLong toAtomicLong(Object from, Converter converter) {
Expand Down Expand Up @@ -96,7 +92,10 @@ static BigInteger toBigInteger(Object from, Converter converter) {
}

static BigDecimal toBigDecimal(Object from, Converter converter) {
return BigDecimal.valueOf(toLong(from, converter));
Instant instant = (Instant) from;
long seconds = instant.getEpochSecond();
int nanos = instant.getNano();
return BigDecimal.valueOf(seconds * 1000).add(BigDecimal.valueOf(nanos, 6));
}

static LocalDateTime toLocalDateTime(Object from, Converter converter) {
Expand Down
Loading

0 comments on commit d8ce0ac

Please sign in to comment.