To represent timestamps and durations, we used to use a mix of various
strategies:
* `f64` representing a number of seconds
* `time::Timespec`
* `protobuf::well_known_type::Timestamp`
A span of time was sometimes represented as
* a start and an end timestamp, or
* a start and a duration
This lead to many little helper functions converting from one type of
time representation to another, which caused clutter.
There were valid reasons for alternating between different
representations. For instance, we sometimes wanted a timestamp that
could be serialized and an `f64` filled that role.
We sometimes wanted a timestamp that was more strongly typed, and a
`time::Timespec` filled that role, despite coming from a deprecated
crate.
In general, we should use `std::time` for time operations, but these
types don't lend themselves to serialization as they explicitely avoid
exposing their internals through serialization or otherwise to avoid
misleading programmers into serializing a timestamp, checking it on a
different machine with a different timezone and ending up with broken
assumptions.
Since we do want to serialize durations (since EPOCH, so a timestamp or
since another duration), create a simple struct called
`concrete_time::Duration` that can seemlessly be converted from and into
a `std::time::Duration` and that can also be serialized.
For convenience, also create a `TimeSpan` that encapsulates the idea of
starting at some point and ending at some other point. Give it
constructors that make sense given the contexts in which we populate
timespans (from protobuf and from measurements).
Also change the ffi boundary to push the float representation of time as
far as possible, to the py_zipkin interface; so the python code can more
conveniently compare timestamps for equality in tests.
Note that brfs was purposefully omitted from the homogeneisation effort
as it only used `time::Timespec` without any conversions and that is
what the `fuse` API expects.