1

My Rust application stores timestamps in UTC, but needs to output in the local timezone. The following code shows is trivial to do this:

use chrono::{DateTime, Local, Utc};

fn main() {
    let utc = Utc::now();
    utc_to_local(utc);
}

fn utc_to_local(utc: DateTime<Utc>) {
    let local = DateTime::<Local>::from(utc);
    println!("{}", utc.to_string());
    println!("{}", local.to_string());
}

The output is as follows:

2021-08-26 14:55:31.590057252 UTC
2021-08-26 15:55:31.590057252 +01:00

However, I am not comfortable relying on environment settings like the local timezone in unit tests, and would like to test the formatting code (omitted here for simplicity) using a specific timezone or UTC. I am therefore trying to convert utc_to_local() to a generic function:

use chrono::{DateTime, Local, TimeZone, Utc};

fn main() {
    let utc = Utc::now();
    utc_to_local::<Local>(utc);
}

fn utc_to_local<Tz: TimeZone>(utc: DateTime<Utc>) {
    let local = DateTime::<Tz>::from(utc);
    println!("{}", utc.to_string());
    println!("{}", local.to_string());
}

This fails to compile:

error[E0308]: mismatched types
 --> src/main.rs:9:38
  |
8 | fn utc_to_local<Tz: TimeZone>(utc: DateTime<Utc>) {
  |                 -- this type parameter
9 |     let local = DateTime::<Tz>::from(utc);
  |                                      ^^^ expected type parameter `Tz`, found struct `Utc`
  |
  = note: expected struct `DateTime<Tz>`
             found struct `DateTime<Utc>`

Can anyone tell me where I'm going wrong please?

UPDATE

Following advice in the post linked by Svetlin, this works:

use chrono::{DateTime, Local, TimeZone, Utc, Datelike, Timelike};

fn main() {
    let utc = Utc::now();
    utc_to_local(utc, Local);
}

fn utc_to_local<Tz: TimeZone>(utc: DateTime<Utc>, zone: Tz) {
    let local = utc.with_timezone(&zone);
    println!("{:04}-{:02}-{:02} {:02}:{:02}:{:02}", utc.year(), utc.month(), utc.day(), utc.hour(), utc.minute(), utc.second());
    println!("{:04}-{:02}-{:02} {:02}:{:02}:{:02}", local.year(), local.month(), local.day(), local.hour(), local.minute(), local.second());
}

I had to do my own formatting instead of calling to_string(), because I got a compiler error:

error[E0599]: the method `to_string` exists for struct `DateTime<Tz>`, but its trait bounds were not satisfied
  --> src/main.rs:11:26
   |
11 |     println!("{}", local.to_string());
   |                          ^^^^^^^^^ method cannot be called on `DateTime<Tz>` due to unsatisfied trait bounds
   | 
  ::: /home/hwalters/.cargo/registry/src/github.com-1ecc6299db9ec823/chrono-0.4.19/src/datetime.rs:70:1
   |
70 | pub struct DateTime<Tz: TimeZone> {
   | ---------------------------------
   | |
   | doesn't satisfy `DateTime<Tz>: ToString`
   | doesn't satisfy `DateTime<Tz>: std::fmt::Display`
   |
   = note: the following trait bounds were not satisfied:
           `DateTime<Tz>: std::fmt::Display`
           which is required by `DateTime<Tz>: ToString`

But that's ok, I'm doing my own formatting anyway (that's the point of the unit test).

Huw Walters
  • 1,888
  • 20
  • 20

0 Answers0