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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#![deny(warnings)]
pub type DateTime = chrono::NaiveDateTime;
pub type Date = chrono::NaiveDate;
pub type Duration = chrono::Duration;
use std::str::FromStr;
#[derive(Debug,PartialEq,Eq,PartialOrd,Ord,Clone,Copy)]
pub enum Grain {
Second,
Minute,
Hour,
Day,
Week,
Month,
Quarter,
Half,
Year,
Lustrum,
Decade,
Century,
Millenium,
}
impl FromStr for Grain {
type Err = String;
fn from_str(s: &str) -> Result<Grain, String> {
match s.to_lowercase().as_ref() {
"second" | "seconds" => Ok(Grain::Second),
"minute" | "minutes" => Ok(Grain::Minute),
"hour" | "hours" => Ok(Grain::Hour),
"day" | "days" => Ok(Grain::Day),
"week" | "weeks" => Ok(Grain::Week),
"month" | "months" => Ok(Grain::Month),
"quarter" | "quarters" => Ok(Grain::Quarter),
"half" | "halfs" => Ok(Grain::Half),
"year" | "years" => Ok(Grain::Year),
"lustrum" | "lustrums" => Ok(Grain::Lustrum),
"decade" | "decades" => Ok(Grain::Decade),
"century" | "centuries" => Ok(Grain::Century),
"millenium" | "millenia" | "milleniums" => Ok(Grain::Millenium),
_ => Err(format!("Can't build Grain from {}", s))
}
}
}
#[derive(Debug,PartialEq,Eq,Clone,Copy)]
pub enum Season {
Spring,
Summer,
Autumn,
Winter,
}
impl FromStr for Season {
type Err = String;
fn from_str(s: &str) -> Result<Season, String> {
match s.to_lowercase().as_ref() {
"spring" | "springs" => Ok(Season::Spring),
"summer" | "summers" => Ok(Season::Summer),
"autumn" | "autumns" => Ok(Season::Autumn),
"winter" | "winters" => Ok(Season::Winter),
_ => Err(format!("Can't build Season from {}", s))
}
}
}
#[derive(Clone,Debug,PartialEq)]
pub struct Range {
pub start: DateTime,
pub end: DateTime,
pub grain: Grain,
}
impl Range {
pub fn intersect(&self, other: &Range) -> Option<Range> {
use std::cmp;
if self.start < other.end && self.end > other.start {
return Some(Range{
start: cmp::max(self.start, other.start),
end: cmp::min(self.end, other.end),
grain: cmp::min(self.grain, other.grain)
});
}
None
}
pub fn len(&self) -> Duration {
self.end.signed_duration_since(self.start)
}
}
pub trait TimeSequence {
fn _future_raw(&self, t0: &DateTime) -> Box<dyn Iterator<Item=Range> + '_>;
fn _past_raw(&self, t0: &DateTime) -> Box<dyn Iterator<Item=Range> + '_>;
fn future(&self, t0: &DateTime) -> Box<dyn Iterator<Item=Range> + '_> {
let t0 = *t0;
Box::new(self._future_raw(&t0)
.skip_while(move |range| range.end <= t0))
}
fn past(&self, t0: &DateTime) -> Box<dyn Iterator<Item=Range> + '_> {
let t0 = *t0;
Box::new(self._past_raw(&t0)
.skip_while(move |range| range.end > t0))
}
}