From 39545dbea9b40fbc55a58df8f4ceecd06150ce49 Mon Sep 17 00:00:00 2001 From: james-rms Date: Wed, 8 Mar 2023 09:47:41 +1100 Subject: [PATCH] CLI: info: handle durations > 2**63 (#844) * CLI: info: handle durations > 2**63 * make a function * correct comment --- go/cli/mcap/cmd/info.go | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/go/cli/mcap/cmd/info.go b/go/cli/mcap/cmd/info.go index 7807cbefa6..d5e57ad5ca 100644 --- a/go/cli/mcap/cmd/info.go +++ b/go/cli/mcap/cmd/info.go @@ -5,6 +5,7 @@ import ( "context" "fmt" "io" + "math" "os" "sort" "time" @@ -19,9 +20,8 @@ var ( ) func decimalTime(t time.Time) string { - unix := t.UnixNano() - seconds := unix / 1e9 - nanoseconds := unix % 1e9 + seconds := t.Unix() + nanoseconds := t.Nanosecond() return fmt.Sprintf("%d.%09d", seconds, nanoseconds) } @@ -35,6 +35,19 @@ func humanBytes(numBytes uint64) string { return fmt.Sprintf("%.2f %s", displayedValue, prefixes[prefixIndex]) } +func getDurationNs(start uint64, end uint64) float64 { + // subtracts start from end, returning the result as a 64-bit float. + // float64 can represent the entire range of possible durations (-2**64, 2**64), + // albeit with some loss of precision. + diff := end - start + signMultiplier := 1.0 + if start > end { + diff = start - end + signMultiplier = -1.0 + } + return float64(diff) * signMultiplier +} + func printInfo(w io.Writer, info *mcap.Info) error { buf := &bytes.Buffer{} fmt.Fprintf(buf, "library: %s\n", info.Header.Library) @@ -45,16 +58,23 @@ func printInfo(w io.Writer, info *mcap.Info) error { fmt.Fprintf(buf, "messages: %d\n", info.Statistics.MessageCount) start = info.Statistics.MessageStartTime end = info.Statistics.MessageEndTime + durationNs := getDurationNs(start, end) + durationInSeconds = durationNs / 1e9 starttime := time.Unix(int64(start/1e9), int64(start%1e9)) endtime := time.Unix(int64(end/1e9), int64(end%1e9)) - fmt.Fprintf(buf, "duration: %s\n", endtime.Sub(starttime)) - durationInSeconds = endtime.Sub(starttime).Seconds() + if math.Abs(durationNs) > math.MaxInt64 { + // time.Duration is an int64 nanosecond count under the hood, but end and start can + // be further apart than that. + fmt.Fprintf(buf, "duration: %.3fs\n", durationInSeconds) + } else { + fmt.Fprintf(buf, "duration: %s\n", endtime.Sub(starttime)) + } if starttime.After(LongAgo) { fmt.Fprintf(buf, "start: %s (%s)\n", starttime.Format(time.RFC3339Nano), decimalTime(starttime)) fmt.Fprintf(buf, "end: %s (%s)\n", endtime.Format(time.RFC3339Nano), decimalTime(endtime)) } else { - fmt.Fprintf(buf, "start: %.3f\n", float64(starttime.UnixNano())/1e9) - fmt.Fprintf(buf, "end: %.3f\n", float64(endtime.UnixNano())/1e9) + fmt.Fprintf(buf, "start: %s\n", decimalTime(starttime)) + fmt.Fprintf(buf, "end: %s\n", decimalTime(endtime)) } } if len(info.ChunkIndexes) > 0 {