【问题标题】:Loop over date range循环日期范围
【发布时间】:2018-10-10 20:55:50
【问题描述】:

在 Python3 中,我可以像这样循环一系列日期

import datetime

dt0 = datetime.datetime(2017, 1, 1, 0, 0, 0)
dt1 = datetime.datetime(2017, 1, 5, 0, 0, 0)
dt = dt0
while dt <= dt1:
    print(dt.strftime("%Y-%m-%d %H:%M:%S"))
    dt += datetime.timedelta(days=1)

在 Rust 中是否有类似的方法来循环日期? 我知道我可以在几个月内编写一个嵌套循环,然后是一个月中的几天。像这样:

let days = [1, 2, 3, 4, 5, 6, 7,
            8, 9, 10, 11, 12, 13, 14, 
            15, 16, 17, 18, 19, 20, 21,
            22, 23, 24, 25, 26, 27, 28, 29, 30, 31];
let months = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
let months_30_days = [4, 6, 9, 11];

for month in months.iter() {
    for day in days.iter() {
        if month == &2 {
            if is_leap_year(year) {
                if day > &29 {
                    continue;
                }
            } else if day > &28 {
                continue;
            }
        } else if months_30_days.contains(&month) && day > &30 {
            continue;
        }

        print!("{:04}-{:02}-{:02} ", year, month, day);
    }
}

fn is_leap_year(year: i32) -> bool {
    if year % 100 == 0 {
        return year % 400 == 0;
    } else {
        return year % 4 == 0;
    }
}

有没有更质朴的方式来做到这一点?

【问题讨论】:

  • 如果您的代码工作但您希望对其进行改进,那么对于Code Review.SE 来说这是一个更好的问题。
  • 你似乎错过了外年循环。
  • 这是一个sn-p。年份较早在 main 函数中声明。但是您是对的,如果日期范围包括几年,则可以将年份循环添加为外部循环。

标签: loops date rust


【解决方案1】:

您可以为此使用 chrono crate:

extern crate chrono; // 0.4.6

use chrono::{Duration, TimeZone, Utc};

fn main() {
    let dt0 = Utc.ymd(2017, 1, 1);
    let dt1 = Utc.ymd(2017, 1, 5);

    let mut dt = dt0;
    while dt <= dt1 {
        println!("{:?}", dt);
        dt = dt + Duration::days(1);
    }
}

这也可以包装成一个迭代器:

extern crate chrono; // 0.4.6

use chrono::{Date, Duration, TimeZone, Utc};
use std::mem;

struct DateRange(Date<Utc>, Date<Utc>);

impl Iterator for DateRange {
    type Item = Date<Utc>;
    fn next(&mut self) -> Option<Self::Item> {
        if self.0 <= self.1 {
            let next = self.0 + Duration::days(1);
            Some(mem::replace(&mut self.0, next))
        } else {
            None
        }
    }
}

fn main() {
    let dt0 = Utc.ymd(2017, 1, 1);
    let dt1 = Utc.ymd(2017, 1, 5);

    for dt in DateRange(dt0, dt1) {
        println!("{:?}", dt);
    }
}

【讨论】:

  • mstlr 这很好用。我不知道如何在日期时间中添加一天。我仍然看不到“.expect”的作用,但没有它就无法运行。
  • @joeschmoe2 expectunwrap 具有完全相同的行为,除了它还允许您在出现恐慌时指定自定义消息。这是必要的,因为checked_add 返回一个Option&lt;UTC&gt;,但该值被分配给dt,这是一个普通的UTC
【解决方案2】:

可能有一个 crate 已经提供了这样的功能,但是如果你想自己实现它,你可以引入一个新的数据类型并实现 Iterator - 这将是 Rust-y 的方式它。

struct MyDate {
    year: usize, // or allow negatives for B.C.
    month: u8, // or a dedicated Month type limited to 12
    day: u8  // or a dedicated Day type limited to 31
}

impl Iterator for Date {
    type Item = Date;

    fn next(&mut self) -> Option<Date> {
        // conditions for incrementing day, month and year
    }
}

然后您就可以使用next() 在循环中递增它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-12-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-19
    • 2011-05-19
    • 1970-01-01
    • 2013-03-20
    相关资源
    最近更新 更多