Skip to content

Commit

Permalink
Truncate to millisecond precision.
Browse files Browse the repository at this point in the history
  • Loading branch information
chronos-tachyon committed Dec 6, 2023
1 parent 77ba646 commit bc7442f
Showing 1 changed file with 39 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,37 @@
public class ProtobufTimeUtils {

private static final int NANOS_PER_SECOND = 1000000000;
private static final int NANOS_PER_MILLI = 1000000;

/**
* Converts a Protobuf Duration to a Java Duration with millisecond precision. Null inputs are
* treated as zero.
*/
@Nonnull
public static Duration toJavaDuration(com.google.protobuf.Duration d) {
// TODO we should refactor an implicit conversion of empty values into ZERO and rename the
// current method into toJavaDurationSafe, toJavaDurationOrDefault or something like that
public static Duration toJavaDuration(@Nullable com.google.protobuf.Duration d) {
if (Objects.isNull(d)) {
return Duration.ZERO;
}
return truncateToMillis(toJavaDurationExact(d));
}

/**
* Converts a Java Duration to a Protobuf Duration with millisecond precision. Null inputs are
* treated as zero.
*/
@Nonnull
public static com.google.protobuf.Duration toProtoDuration(@Nullable Duration d) {
if (Objects.isNull(d)) {
return Durations.ZERO;
}
return toProtoDurationExact(truncateToMillis(d));
}

/**
* Converts a Protobuf Duration to a Java Duration with nanosecond precision.
*/
@Nonnull
public static Duration toJavaDurationExact(@Nonnull com.google.protobuf.Duration d) {
// See the comment in toProtoDuration for details about how Java Duration and Protobuf Duration
// have almost-but-not-quite identical representations.
//
Expand All @@ -50,14 +72,11 @@ public static Duration toJavaDuration(com.google.protobuf.Duration d) {
return Duration.ofSeconds(d.getSeconds(), d.getNanos());
}

/**
* Converts a Java Duration to a Protobuf Duration with nanosecond precision.
*/
@Nonnull
public static com.google.protobuf.Duration toProtoDuration(Duration d) {
// TODO we should refactor an implicit conversion of empty values into ZERO and rename the
// current method into toJavaDurationSafe, toJavaDurationOrDefault or something like that
if (Objects.isNull(d)) {
return Durations.ZERO;
}

public static com.google.protobuf.Duration toProtoDurationExact(@Nonnull Duration d) {
// Java Duration and Protobuf Duration are *almost* identical in representation: both use a
// 96-bit value divided between a 64-bit (long) seconds count and a 32-bit (int) nanoseconds
// count. However, they represent negative durations slightly differently:
Expand Down Expand Up @@ -116,4 +135,14 @@ public static com.uber.m3.util.Duration toM3DurationSinceNow(Timestamp t) {

return Timestamp.newBuilder().setSeconds(t.getEpochSecond()).setNanos(t.getNano()).build();
}

@Nonnull
private static Duration truncateToMillis(@Nonnull Duration exact) {
// In JDK 9+, this would just be a call to Duration.truncatedTo(ChronoUnit.MILLIS).
// Alas, we must remain compatible with JDK 8.
final long s = exact.getSeconds();
final int ns = exact.getNano();
final int ms = ns / NANOS_PER_MILLI;
return Duration.ofSeconds(s).plusMillis(ms);
}
}

0 comments on commit bc7442f

Please sign in to comment.