TimestampUtils.java
package com.fasterxml.jackson.dataformat.ion.jsr310;
import java.math.BigDecimal;
import java.time.Instant;
import java.time.ZoneOffset;
import com.amazon.ion.Timestamp;
final class TimestampUtils {
private static final BigDecimal ONE_THOUSAND = new BigDecimal("1000");
private static final BigDecimal ONE_MILLION = new BigDecimal("1000000");
private static final BigDecimal ONE_BILLION = new BigDecimal("1000000000");
private TimestampUtils() {}
static Timestamp toTimestamp(Instant instant, ZoneOffset offset) {
final Integer offsetMinutes = offset == null ? null
: secondsToMinutes(offset.getTotalSeconds());
return Timestamp.forMillis(getFractionalMillis(instant), offsetMinutes);
}
static Instant toInstant(Timestamp timestamp) {
final BigDecimal decSeconds = timestamp.getDecimalMillis().divide(ONE_THOUSAND);
final long epocSeconds = decSeconds.longValue();
final long nanoAdjustment = decSeconds.subtract(BigDecimal.valueOf(epocSeconds))
.multiply(ONE_BILLION)
.longValue();
return Instant.ofEpochSecond(epocSeconds, nanoAdjustment);
}
static BigDecimal getFractionalSeconds(Instant instant) {
final BigDecimal epochSeconds = BigDecimal.valueOf(instant.getEpochSecond());
final BigDecimal nanos = BigDecimal.valueOf(instant.getNano());
return epochSeconds.add(nanos.divide(ONE_BILLION));
}
static BigDecimal getFractionalMillis(Instant instant) {
final BigDecimal epochSeconds = BigDecimal.valueOf(instant.getEpochSecond());
final BigDecimal nanos = BigDecimal.valueOf(instant.getNano());
return epochSeconds.multiply(ONE_THOUSAND)
.add(nanos.divide(ONE_MILLION));
}
//From https://github.com/FasterXML/jackson-modules-java8
static Instant fromFractionalSeconds(BigDecimal seconds) {
// Complexity is here to workaround unbounded latency in some BigDecimal operations.
// https://github.com/FasterXML/jackson-databind/issues/2141
long secondsOnly;
int nanosOnly;
BigDecimal nanoseconds = seconds.scaleByPowerOfTen(9);
if (nanoseconds.precision() - nanoseconds.scale() <= 0) {
// There are no non-zero digits to the left of the decimal point.
// This protects against very negative exponents.
secondsOnly = nanosOnly = 0;
}
else if (seconds.scale() < -63) {
// There would be no low-order bits once we chop to a long.
// This protects against very positive exponents.
secondsOnly = nanosOnly = 0;
}
else {
// Now we know that seconds has reasonable scale, we can safely chop it apart.
secondsOnly = seconds.longValue();
nanosOnly = nanoseconds.subtract(new BigDecimal(secondsOnly).scaleByPowerOfTen(9)).intValue();
if (secondsOnly < 0 && secondsOnly > Instant.MIN.getEpochSecond()) {
// Issue #69 and Issue #120: avoid sending a negative adjustment to the Instant constructor, we want this as the actual nanos
nanosOnly = Math.abs(nanosOnly);
}
}
return Instant.ofEpochSecond(secondsOnly, nanosOnly) ;
}
private static int secondsToMinutes(int seconds) {
return Math.floorDiv(seconds, 60);
}
}