Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -321,31 +321,25 @@ public static Timestamp toTimestamp(BinaryString input, int precision, TimeZone
return DateTimeUtils.parseTimestampData(input.toString(), precision, timeZone);
}

private static final long[] POW10 = {1L, 10L, 100L, 1_000L, 10_000L, 100_000L, 1_000_000L};

// Helper method to convert epoch to Timestamp with the provided precision.
private static Timestamp fromMillisToTimestamp(long epoch, int precision) {
// Calculate milliseconds and nanoseconds from epoch based on precision
if (precision < 0 || precision > 9) {
throw new RuntimeException("Unsupported precision: " + precision);
}

// epoch counts units of 10^-precision seconds, so one unit is 10^(3 - precision)
// milliseconds: seconds at precision 0, millis at 3, micros at 6, nanos at 9.
long millis;
int nanosOfMillis;

switch (precision) {
case 0: // seconds
millis = epoch * 1000;
nanosOfMillis = 0;
break;
case 3: // milliseconds
millis = epoch;
nanosOfMillis = 0;
break;
case 6: // microseconds
millis = epoch / 1000;
nanosOfMillis = (int) ((epoch % 1000) * 1000);
break;
case 9: // nanoseconds
millis = epoch / 1_000_000;
nanosOfMillis = (int) (epoch % 1_000_000);
break;
default:
throw new RuntimeException("Unsupported precision: " + precision);
if (precision > 3) {
long divisor = POW10[precision - 3];
millis = epoch / divisor;
nanosOfMillis = (int) ((epoch % divisor) * 1_000_000L / divisor);
} else {
millis = epoch * POW10[3 - precision];
nanosOfMillis = 0;
}

// If nanoseconds is negative, remove a millisecond
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,19 @@ class BinaryStringUtilsTest {
// One second and one nanosecond before epoch in nanoseconds
// The negative nanosecond gets flipped and the milliseconds decremented
"-1000000001, 9, -1001, 999999",
"-86400123456, 6, -86400124, 544000"
"-86400123456, 6, -86400124, 544000",
// Intermediate precisions scale the unit by ten per step from the anchors.
"36000000, 4, 3600000, 0", // one hour in 0.1 ms units
"360000000, 5, 3600000, 0", // one hour in 0.01 ms units
"36000000000, 7, 3600000, 0", // one hour in 100 ns units
"360000000000, 8, 3600000, 0", // one hour in 10 ns units
"36000, 1, 3600000, 0", // one hour in 0.1 s units
"360000, 2, 3600000, 0", // one hour in 0.01 s units
// A remainder below one millisecond becomes nanos-of-millisecond
"17000000001, 5, 170000000, 10000", // one 0.01 ms unit past the millisecond
"170000000012, 8, 1700000, 120", // twelve 10 ns units past the millisecond
// Negative epoch: the nanos-of-millisecond offset stays positive
"-1700000001, 7, -170001, 999900"
})
void testToTimestamp(String input, int precision, long expectedMillis, int expectedNanos) {
BinaryString binaryInput = BinaryString.fromString(input);
Expand All @@ -63,7 +75,7 @@ void testToTimestamp(String input, int precision, long expectedMillis, int expec
}

@ParameterizedTest
@ValueSource(ints = {1, 2, 4, 5, 7, 8, 10, -1})
@ValueSource(ints = {10, -1})
void testInvalidPrecisions(int precision) {
BinaryString input = BinaryString.fromString("1609459200");

Expand Down
Loading