What does it mean for a Span to be negative? This is one thing I really like about Durations, they can't be negative and therefore match physical reality.
negative duration:
duration in the reverse direction to the proceeding time scale
Matching "physical reality" is a non-goal. What's important is modeling the problem domain in a way that makes sense to programmers and helps them avoid mistakes. A negative span doesn't give you any extra expressivity that "subtract a span from a datetime" doesn't already give you. Both are a means to go backwards in time. And they line up with human concepts that talk about the past. So for example, if I say, "I went camping 1 year ago." I am expressing a concept that is modeled by a negative span.
And there are also just practical benefits to allowing a span to be signed. For example:
use jiff::{ToSpan, Unit, Zoned};
fn main() -> anyhow::Result<()> {
let now = Zoned::now().intz("Europe/Kyiv")?;
let next_year = now.checked_add(1.year())?;
let span = now.since((Unit::Month, &next_year))?;
println!("{span}");
Ok(())
}
Has this output:
$ cargo -q r
-P12m
If negative spans weren't supported, what would the behavior of this routine be? It could return an error. Or maybe an out-of-band sign. I'm not sure. But this seems like the most sensible thing.
And of course, Temporal has negative durations too. This design was copied from them.
Upon thinking about it a little more, I actually have a stronger opinion that it's probably not ideal to try to assign direction to durations themselves, and even then making them signed wouldn't be the best way. A duration is a scalar length measurement in the time axis. Those things are always positive, at least in our universe. I don't think we gain much by pretending otherwise, and I think we lose clarity.
Expressing a before/after relationship requires that we establish what is the anchor point. Is it the present time experienced in my reference frame? Is it unix epoch? Using a negative number to denote a disembodied "duration before" leaves me guessing about the anchor. In the case when we want to express the timestamp "3 days before/after time t0" I think it's probably best to say something like:
This isn't a criticism of your library, it looks awesome and I'll definitely use it. I am fairly surprised that negative duration definition made it into the standard though.
There are `checked_add` and `checked_sub`. But that shifts the "direction" of the span to the operation, which is a static property of your program, instead of being part of the value itself, which is a dynamic property of your program. I think this results in more annoying code where you just wind up carrying a sign around anyway.
There are also negative years, even though that doesn't really correspond to anything "real" either.
Thanks for the explanation. I agree signed spans make it easier to express concepts like "1 year ago" vs "1 year from now". And clearly if the concept of a negative duration has made it into the standard then it makes sense to support it. But I do wonder if there's some value still in being precise, if I think I've measured a negative duration--e.g I look at my watch and write down t0, wait a bit, look at my watch again and write down t1 and find t0 > t1--that's something surprising that probably warrants further investigation. The explanation likely isn't "well time just went backwards for a bit there" :P. This happens frequently in computers, though, so maybe making the programmer handle an error each time is excessive.
Yeah it's hard for me to get a sense of where that would really matter in practice, or even when it would be correct to do so. You could a `assert!(!span.is_negative());`. Although, you have to be careful, because system time can change arbitrarily.
Your watch example is actually an important use case that specifically isn't served by Jiff. You should be using monotonic time (in Rust, that's `std::time::Instant`) for things like that. In that case, you really do get a guarantee that the duration between two instants (one in the past and one in the future) is non-negative. And if it weren't, then that would be worthy of an assert. But you get no such guarantees with system time.