使用 Chrono 计算现在和下一个午夜之间的持续时间

Calculate the duration between now and the next midnight using Chrono

获取现在和下一个午夜之间的持续时间的惯用方法是什么?

我有这样的功能:

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??
}

它应该 Duration 1 小时,因为下一个午夜是 2017 年 12 月 9 日星期六 00:00:00 GMT-0300 (-03)

只需减去两个日期:午夜和现在:

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())
}

应 Matthieu 的要求,您可以这样写:

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()
}

但是不知道是不是更好

一种方法是计算到下一个午夜的秒数,请记住 time::Tm 同时考虑夏令时和时区:

tm_utcoff: i32

Identifies the time zone that was used to compute this broken-down time value, including any adjustment for Daylight Saving Time. This is the number of seconds east of UTC. For example, for U.S. Pacific Daylight Time, the value is -7*60*60 = -25200.

extern crate time;
use std::time::Duration;

fn duration_until_next_midnight() -> Duration {
    let tnow = time::now();

    Duration::new(
        (86400 - tnow.to_timespec().sec % 86400 - 
        i64::from(tnow.tm_utcoff)) as u64,
        0,
    )
}

如果你想要纳秒精度,你必须做更多的数学运算......

在搜索文档后,我终于找到了丢失的 link:Date::and_hms

所以,实际上,这很简单:

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);
}

想法很简单:

  • 增加DateTime到明天,
  • 提取保留时区的Date部分,
  • 通过用 and_hms.
  • 指定“00:00:00”Time 来重建一个新的 DateTime

and_hms中有一个panic!,所以要注意指定正确的时间。