-1

I have two DateTime objects of different type which I would like to be able to subtract, or otherwise find the Duration difference between.

Here is some example code:

// First step: Want to be able to construct DateTimes for a set of different
// timezones.
//
// To do this, we first create a Utc now object, and convert it to different
// timezones, as required. For example here, we convert to London.
let utc_now = Utc::now();
let naive_utc_datetime = utc_now.naive_local();
    // Since this time is in Utc, `naive_local` should return the same as
    // `naive_utc` ?

// Create London time from a chrono_tz Timezone
let london_now = chrono_tz::Europe::London.from_utc_datetime(&naive_utc_datetime);
println!("london_now: {}", london_now);
    // london_now: 2023-08-31 10:07:43.421198168 BST

let difference_from_utc = london_now - utc_now;
println!("difference_from_utc: {}", difference_from_utc);
    // does not compile

The final line does not compile, this is why:

cannot subtract `DateTime<Utc>` from `DateTime<Tz>`
the trait `Sub<DateTime<Utc>>` is not implemented for `DateTime<Tz>`
the following other types implement trait `Sub<Rhs>`:
  <DateTime<Tz> as Sub<Days>>
  <DateTime<Tz> as Sub<FixedOffset>>
  <DateTime<Tz> as Sub<Months>>
  <DateTime<Tz> as Sub<chrono::Duration>>
  <DateTime<Tz> as Sub>

The question is, how can we obtain the Duration (or otherwise) difference between the time in London and the Utc time. Since it is currently British Summer Time, I would expect to see a difference of exactly 1 hour on todays date. (2023-08-31)


Related: The following question explains how to subtract two DateTime::<T> objects assuming they have the same type T.

This will work if both datetimes are DateTime::<Utc> but not otherwise.

Chayim Friedman
  • 47,971
  • 5
  • 48
  • 77
FreelanceConsultant
  • 13,167
  • 27
  • 115
  • 225
  • "*the trait `Sub>` is not implemented for `DateTime`*" - ignoring the technical details, this does not make much sense to me from a theoretical perspective. UTC is not a time zone, however, durations between UTC datetime and timezone-aware datetime should be unambiguous, assuming the appropriate time zone rules are applied. – FObersteiner Sep 01 '23 at 06:08

2 Answers2

1

You can convert the datetimes to NaiveDateTime:

let difference_from_utc = london_now.naive_local() - utc_now.naive_local();

For UTC, it is faster to use naive_utc():

let difference_from_utc = london_now.naive_local() - utc_now.naive_utc();
Chayim Friedman
  • 47,971
  • 5
  • 48
  • 77
  • 2
    @FreelanceConsultant I didn't ask for your upvote. I posted it here for you and for posterity. And for the record, I was not the downvoter in this case, and [you should not assume you know who is the downvoter](https://meta.stackoverflow.com/questions/388686/why-shouldnt-i-assume-i-know-who-downvoted-my-post). – Chayim Friedman Aug 31 '23 at 10:07
  • I do not think the answer is good, because it required converting to naive forms. – FreelanceConsultant Aug 31 '23 at 10:29
  • 2
    I don't think this is a problem, especially given that we calculate-and-throw-away it, but of course you're free to think otherwise. Nevertheless, it's still better than your answer, that converts the `DateTime` to a type it clearly _is not_. – Chayim Friedman Aug 31 '23 at 10:33
  • I would **guess** although I don't know if this is the case, that it **might** be possible to convert a `DateTime` to `DateTime` which **maybe** could be subtracted from `london_now`. I would suggest this is the "real" solution but I have not yet figured out how to do that. I agree, converting to `Utc` is not **ideal** but it is better than throwing away the timezone information. – FreelanceConsultant Aug 31 '23 at 12:04
  • @FreelanceConsultant This won't help; as you've noticed in your answer, subtracting `DateTime` ignores the time zone and only compares the UTC time. – Chayim Friedman Aug 31 '23 at 12:07
  • Fair enough. This is a good point. – FreelanceConsultant Aug 31 '23 at 12:10
-1

One way is to convert the current London Datetime, which is some kind of DateTime<FixedOffset> type into a DateTime<Utc> object.

println!("london_now.naive_local(): {}", london_now.naive_local());
    // 2023-08-31 10:07:43.421198168

// force it into a type which can be subtracted
// this is perhaps a misnomer, because this time IS NOT a utc time
let london_now_utc = Utc.from_local_datetime(&london_now.naive_local()).unwrap();

let difference_from_utc = london_now_utc - utc_now;
println!("difference_from_utc: {}", difference_from_utc); // PT3600S

However, this example only works for subtracting two Utc times. If we wanted to subtract two DateTime objects for a London and Chicago time, this method would suggest both have to be converted to UTC first, which seems inefficient.


I thought it may be possible to subtract two DateTime<FixedOffset> types, but this does not produce the expected result.

For example:

let london_now = chrono_tz::Europe::London.from_utc_datetime(&naive_utc_datetime);
println!("london_now: {}", london_now);
    // london_now: 2023-08-31 10:21:36.642965010 BST

let chicago_now = chrono_tz::America::Chicago.from_utc_datetime(&naive_utc_datetime);
println!("chicago_now: {}", chicago_now);
    // chicago_now: 2023-08-31 04:21:36.642965010 CDT

println!("difference Chicago - London: {}", chicago_now - london_now);

I can sort of imagine why the difference is zero. Both "times" are in different "timezones". When we compute the difference between them we find that although the displayed time is very different, the difference in time is still zero.

FreelanceConsultant
  • 13,167
  • 27
  • 115
  • 225