Rust + chronoで指定期間の全日付を取得する
2020-11-10
- プログラミング
小ネタ。
最近、Rustの勉強として小さいツールを書いている。そこで出くわしたものをイディオムとしてメモしておく。
記事を書いていたら日付の和・差のtrait実装まで調べることになったのでそれも書く。
やりたいこと
ある日付(start_date
)からある日付(end_date
)の間にある日付をすべて取得したい。
日時を扱うときはChronoというcrateがデファクトで使われるらしいのでこれを使う。
環境
- Rust
1.47.0 - chrono
0.4.19
コード
2020/11/01 から 2020/11/10 までの全日付を取得する。
Cargo.toml
dependenciesのところに追記。
[dependencies]
chrono = "0.4.19"
src/main.rs
iter_daysを使う。
これを使うと、指定した日からの日付イテレータが返る。それをtake_whileで打ち切ればいい。
今回の目的には超便利。
use chrono::prelude::*;
use chrono::Duration;
fn main() {
let start_date = NaiveDate::from_ymd(2020, 11, 1);
let end_date = NaiveDate::from_ymd(2020, 11, 10);
let dates: Vec<NaiveDate> = start_date.iter_days().take_while(|x| x <= &end_date).collect();
println!("{:?}", dates);
// => [2020-11-01, 2020-11-02, 2020-11-03, 2020-11-04, 2020-11-05, 2020-11-06, 2020-11-07, 2020-11-08, 2020-11-09, 2020-11-10]
}
別の方法
end_date
から start_date
を引いた差(duration
)を取って、それをnum_daysで日数に換算。
あとは日数をrangeにして、 map
の中で start_date
に加えていくという方法。
最初はこの方法を考えていた。
日付の差を取るのはsigned_duration_sinceを使えばよさそう。
単純に end_date - start_date
でも同じ。
use chrono::prelude::*;
use chrono::Duration;
fn main() {
let start_date = NaiveDate::from_ymd(2020, 11, 1);
let end_date = NaiveDate::from_ymd(2020, 11, 10);
let duration = end_date.signed_duration_since(start_date);// end_date - start_date でも同じ
let dates: Vec<NaiveDate> = (0..=duration.num_days()).map(|x| start_date + Duration::days(x)).collect();
println!("{:?}", dates);
// => [2020-11-01, 2020-11-02, 2020-11-03, 2020-11-04, 2020-11-05, 2020-11-06, 2020-11-07, 2020-11-08, 2020-11-09, 2020-11-10]
}
なお日付の和は 日付 + Duration
でやった。メソッドとしてはchecked_add_signedに対応しているが、
差のときと違って単純に置きかえはできない。
つまり
map(|x| start_date + Duration::days(x))
の部分を
map(|x| start_date.checked_add_signed(Duration::days(x)))
とはできない。なぜなら checked_add_signed
はOption
map(|x| start_date.checked_add_signed(Duration::days(x)).expect("failed"))
としてOptionを外せば通る。
日付で +
や -
を使ったときにどのメソッドが使われるのかはtrait実装を見ればいいようだ。
たとえば +
はAdd traitの実装で、ここを見れば checked_add_signed
に対応することがわかる。