【问题标题】:Calculate the duration between now and the next midnight using Chrono使用 Chrono 计算从现在到下一个午夜之间的持续时间
【发布时间】:2018-05-22 08:12:43
【问题描述】:

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

我有这样的功能:

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

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

【问题讨论】:

    标签: rust rust-chrono


    【解决方案1】:

    翻遍了文档,终于找到了缺失的链接: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!,因此必须小心指定正确的时间。

    【讨论】:

    【解决方案2】:

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

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

    但我不确定它是否更好。

    【讨论】:

    • 有没有办法在一次通话中设置小时/分钟/秒/纳秒?会有很大帮助。
    • @MatthieuM。不幸的是,似乎没有办法用更少的样板来做到这一点:docs.rs/chrono/0.4.0/chrono/trait.Timelike.html
    • 也许提取 NaiveDate 并从中重建一个 NaiveDateTime 会更简单,然后从这个新的 NaiveDateTime 和时区构建一个新的日期?
    • @MatthieuM。即使这似乎也很困难。我认为 crate 缺少一些功能:我按照您的建议写了一些东西,但是代码的可读性较差。拥有impl From&lt;Date&gt; for DateTime 的 IMO 会很棒,甚至是 DateTime::new(date: Date, time: Time)
    • 说实话,我的主要目标是减少unwrap的数量,所以从这个意义上说这是一个净赢。
    【解决方案3】:

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

    tm_utcoff: i32

    标识用于计算此细分时间值的时区,包括夏令时的任何调整。这是 UTC 以东的秒数。例如,对于美国太平洋夏令时间,该值为 -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,
        )
    }
    

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

    【讨论】:

    • 我可能会使用一些别名来提高可读性,比如let seconds_in_a_day = 24 * 3600
    猜你喜欢
    • 1970-01-01
    • 2021-12-30
    • 2020-07-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多