Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Calculate the duration between now and the next midnight using Chrono

What is the idiomatic way to get the duration between now and the next midnight?

I have a function like this:

extern crate chrono;

use chrono::prelude::*;
use time;

fn duration_until_next_midnight() -> time::Duration {
    let now = Local::now(); // Fri Dec 08 2017 23:00:00 GMT-0300 (-03)
    // ... how to continue??
}

It should make a Duration with 1 hour, since the next midnight is Sat Dec 09 2017 00:00:00 GMT-0300 (-03)

like image 351
cspinetta Avatar asked Dec 08 '17 05:12

cspinetta


2 Answers

After scouring the docs, I finally found the missing link: Date::and_hms.

So, actually, it's as easy as:

fn main() {
    let now = Local::now();

    let tomorrow_midnight = (now + Duration::days(1)).date().and_hms(0, 0, 0);

    let duration = tomorrow_midnight.signed_duration_since(now).to_std().unwrap();

    println!("Duration between {:?} and {:?}: {:?}", now, tomorrow_midnight, duration);
}

The idea is simple:

  • increase the DateTime to tomorrow,
  • extract the Date part, which keeps the timezone,
  • reconstructs a new DateTime by specifying a "00:00:00" Time with and_hms.

There's a panic! in and_hms, so one has to be careful to specify a correct time.

like image 156
Matthieu M. Avatar answered Sep 21 '22 00:09

Matthieu M.


Just subtract the two dates: midnight and now:

extern crate chrono;
use chrono::prelude::*;
use std::time;

fn duration_until_next_midnight() -> time::Duration {
    let now = Local::now();
    // change to next day and reset hour to 00:00
    let midnight = (now + chrono::Duration::days(1))
        .with_hour(0).unwrap()
        .with_minute(0).unwrap()
        .with_second(0).unwrap()
        .with_nanosecond(0).unwrap();

    println!("Duration between {:?} and {:?}:", now, midnight);
    midnight.signed_duration_since(now).to_std().unwrap()
}

fn main() {
    println!("{:?}", duration_until_next_midnight())
}

As requested by Matthieu, you can write something like:

fn duration_until_next_midnight() -> Duration {
    let now = Local::now();
    // get the NaiveDate of tomorrow
    let midnight_naivedate = (now + chrono::Duration::days(1)).naive_utc().date();
    // create a NaiveDateTime from it
    let midnight_naivedatetime = NaiveDateTime::new(midnight_naivedate, NaiveTime::from_hms(0, 0, 0));
    // get the local DateTime of midnight
    let midnight: DateTime<Local> = DateTime::from_utc(midnight_naivedatetime, *now.offset());

    println!("Duration between {:?} and {:?}:", now, midnight);
    midnight.signed_duration_since(now).to_std().unwrap()
}

But I am not sure if it is better.

like image 33
Boiethios Avatar answered Sep 21 '22 00:09

Boiethios