summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/iter.rs367
-rw-r--r--src/iterinfo.rs4
-rw-r--r--src/poslist.rs24
-rw-r--r--src/yearinfo.rs16
4 files changed, 389 insertions, 22 deletions
diff --git a/src/iter.rs b/src/iter.rs
index 8b13789..4ab9a69 100644
--- a/src/iter.rs
+++ b/src/iter.rs
@@ -1 +1,368 @@
+use crate::datetime::*;
+use crate::iterinfo::*;
+use crate::poslist::*;
+use crate::yearinfo::*;
+use chrono::prelude::*;
+use chrono::Duration;
+pub enum QueryMethodTypes {
+ ALL,
+ BETWEEN,
+ BEFORE,
+ AFTER,
+}
+
+pub struct IterArgs {
+ inc: bool,
+ before: DateTime<Utc>,
+ after: DateTime<Utc>,
+ dt: DateTime<Utc>,
+ _value: Option<Vec<DateTime<Utc>>>,
+}
+
+pub struct IterResult {
+ pub method: QueryMethodTypes,
+ pub args: IterArgs,
+ pub min_date: Option<DateTime<Utc>>,
+ pub max_date: Option<DateTime<Utc>>,
+ pub _result: Vec<DateTime<Utc>>,
+ pub total: usize,
+}
+
+impl IterResult {
+ pub fn new(method: QueryMethodTypes, args: IterArgs) -> Self {
+ let (max_date, min_date) = match method {
+ QueryMethodTypes::BETWEEN if args.inc => (Some(args.before), Some(args.after)),
+ QueryMethodTypes::BETWEEN => (
+ Some(args.before - Duration::milliseconds(1)),
+ Some(args.after + Duration::milliseconds(1)),
+ ),
+ QueryMethodTypes::BEFORE if args.inc => (Some(args.dt), None),
+ QueryMethodTypes::BEFORE => (Some(args.dt - Duration::milliseconds(1)), None),
+ QueryMethodTypes::AFTER if args.inc => (None, Some(args.dt)),
+ QueryMethodTypes::AFTER => (None, Some(args.dt + Duration::milliseconds(1))),
+ _ => (None, None),
+ };
+
+ Self {
+ method,
+ args,
+ min_date,
+ max_date,
+ total: 0,
+ _result: vec![],
+ }
+ }
+
+ pub fn accept(&mut self, date: DateTime<Utc>) -> bool {
+ self.total += 1;
+ let too_early = self.min_date.is_some() && date < self.min_date.unwrap();
+ let too_late = self.max_date.is_some() && date > self.max_date.unwrap();
+
+ match self.method {
+ QueryMethodTypes::BETWEEN if too_early => true,
+ QueryMethodTypes::BETWEEN if too_late => false,
+ QueryMethodTypes::BEFORE if too_late => false,
+ QueryMethodTypes::AFTER if too_early => true,
+ QueryMethodTypes::AFTER => {
+ self.add(date);
+ return false;
+ }
+ _ => self.add(date),
+ }
+ }
+
+ pub fn add(&mut self, date: DateTime<Utc>) -> bool {
+ self._result.push(date);
+ return true;
+ }
+
+ pub fn get_value(&self) -> Option<Vec<DateTime<Utc>>> {
+ match self.method {
+ QueryMethodTypes::ALL => None,
+ QueryMethodTypes::BETWEEN => Some(self._result.clone()),
+ QueryMethodTypes::BEFORE => None,
+ QueryMethodTypes::AFTER => None,
+ }
+ }
+}
+
+pub fn iter(
+ iter_result: &mut IterResult,
+ options: &mut ParsedOptions,
+) -> Option<Vec<DateTime<Utc>>> {
+ if (options.count.is_some() && options.count.unwrap() == 0) || options.interval == 0 {
+ return iter_result.get_value();
+ }
+
+ let mut counter_date = options.dtstart.clone();
+ let mut ii = IterInfo::new(options);
+ ii.rebuild(counter_date.year() as isize, counter_date.month() as usize);
+
+ let mut timeset = make_timeset(&ii, &counter_date, options);
+
+ loop {
+ let (mut dayset, start, end) = ii.getdayset(
+ &options.freq,
+ counter_date.year() as isize,
+ counter_date.month() as usize,
+ counter_date.day() as usize,
+ );
+ let mut dayset = dayset
+ .into_iter()
+ .map(|s| Some(s as isize))
+ .collect::<Vec<Option<isize>>>();
+
+ let filtered = remove_filtered_days(&mut dayset, start, end, &ii, options);
+
+ if not_empty(&options.bysetpos) {
+ let poslist = build_poslist(&options.bysetpos, &timeset, start, end, &ii, &dayset);
+
+ for j in 0..poslist.len() {
+ let res = poslist[j];
+ if options.until.is_some() && res > options.until.unwrap() {
+ return iter_result.get_value();
+ }
+
+ if res >= options.dtstart {
+ //let rezoned_date = rezone_if_needed(&res, &options);
+ let rezoned_date = res.clone();
+ if !iter_result.accept(rezoned_date) {
+ return iter_result.get_value();
+ }
+
+ if options.count.is_some() {
+ //options.count.unwrap() += 1;
+ //options.count = Some(options.count.unwrap() - 1);
+ if options.count.unwrap() == 0 {
+ return iter_result.get_value();
+ }
+ }
+ }
+ }
+ } else {
+ for j in start..end {
+ let current_day = dayset[j];
+ if current_day.is_none() {
+ continue;
+ }
+ let current_day = current_day.unwrap();
+
+ let date = from_ordinal(ii.yearordinal().unwrap() + current_day);
+ for k in 0..timeset.len() {
+ let res = Utc.ymd(date.year(), date.month(), date.day()).and_hms(
+ timeset[k].hour as u32,
+ timeset[k].minute as u32,
+ timeset[k].second as u32,
+ );
+ if options.until.is_some() && res > options.until.unwrap() {
+ return iter_result.get_value();
+ }
+ if res >= options.dtstart {
+ //let rezoned_date = rezone_if_needed(&res, &options);
+ let rezoned_date = res.clone();
+ if iter_result.accept(rezoned_date) {
+ return iter_result.get_value();
+ }
+ if options.count.is_some() {
+ //options.count.unwrap() += 1;
+ //options.count = Some(options.count.unwrap() - 1);
+ if options.count.unwrap() == 0 {
+ return iter_result.get_value();
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if options.interval == 0 {
+ return iter_result.get_value();
+ }
+
+ // Handle frequency and interval
+ increment_counter_date(&mut counter_date, options, filtered);
+
+ if counter_date.year() > 9999 {
+ return iter_result.get_value();
+ }
+
+ if options.freq == Frequenzy::HOURLY
+ || options.freq == Frequenzy::MINUTELY
+ || options.freq == Frequenzy::SECONDLY
+ {
+ timeset = ii.gettimeset(
+ &options.freq,
+ counter_date.hour() as usize,
+ counter_date.minute() as usize,
+ counter_date.second() as usize,
+ counter_date.timestamp_subsec_millis() as usize,
+ );
+ }
+
+ ii.rebuild(counter_date.year() as isize, counter_date.month() as usize);
+ }
+}
+
+pub fn increment_counter_date(
+ counter_date: &mut DateTime<Utc>,
+ options: &ParsedOptions,
+ filtered: bool,
+) {
+ match options.freq {
+ Frequenzy::YEARLY => {
+ counter_date.with_year(counter_date.year() + options.interval as i32);
+ }
+ Frequenzy::MONTHLY => {
+ let mut new_month = counter_date.month() + options.interval as u32;
+ if new_month > 12 {
+ let mut year_div = new_month / 12;
+ let mut new_month = new_month % 12;
+ if new_month == 0 {
+ new_month = 12;
+ year_div -= 1;
+ }
+ let new_year = counter_date.year() + year_div as i32;
+ counter_date
+ .with_month(new_month)
+ .unwrap()
+ .with_year(new_year)
+ .unwrap();
+ } else {
+ counter_date.with_month(new_month);
+ }
+ counter_date.with_year(counter_date.year() + options.interval as i32);
+ }
+ _ => (),
+ };
+}
+
+pub fn includes<T>(v: &Vec<T>, el: &T) -> bool
+where
+ T: PartialEq,
+{
+ v.iter().any(|ve| ve == el)
+}
+
+pub fn not_empty<T>(v: &Vec<T>) -> bool {
+ return v.len() > 0;
+}
+
+pub fn is_filtered(ii: &IterInfo, current_day: usize, options: &ParsedOptions) -> bool {
+ return (not_empty(&options.bymonth)
+ && !includes(&options.bymonth, &ii.mmask().unwrap()[current_day]))
+ || (not_empty(&options.byweekno) && (ii.wnomask().unwrap()[current_day]) == 0)
+ || (not_empty(&options.byweekday)
+ && !includes(&options.byweekday, &ii.wdaymask().unwrap()[current_day]))
+ || (not_empty(ii.nwdaymask().unwrap()) && (ii.nwdaymask().unwrap()[current_day]) == 0)
+ || ((not_empty(&options.bymonthday) || not_empty(&options.bynmonthday))
+ && !includes(&options.bymonthday, &ii.mdaymask().unwrap()[current_day])
+ && !includes(&options.bynmonthday, &ii.nmdaymask().unwrap()[current_day]))
+ || (not_empty(&options.byyearday)
+ && ((current_day < ii.yearlen().unwrap()
+ && !includes(&options.byyearday, &(current_day + 1))
+ && !includes(
+ &options.byyearday.iter().map(|v| *v as isize).collect(),
+ &(-(ii.yearlen().unwrap() as isize) + current_day as isize),
+ ))
+ || (current_day >= ii.yearlen().unwrap()
+ && !includes(
+ &options.byyearday,
+ &(current_day + 1 - ii.yearlen().unwrap()),
+ )
+ && !includes(
+ &options.byyearday.iter().map(|v| *v as isize).collect(),
+ &(-(ii.nextyearlen().unwrap() as isize) + current_day as isize
+ - ii.yearlen().unwrap() as isize),
+ ))));
+}
+
+pub fn remove_filtered_days(
+ dayset: &mut Vec<Option<isize>>,
+ start: usize,
+ end: usize,
+ ii: &IterInfo,
+ options: &ParsedOptions,
+) -> bool {
+ let mut filtered = false;
+
+ for daycounter in start..end {
+ let current_day = dayset[daycounter];
+ if current_day.is_none() {
+ continue;
+ }
+
+ filtered = is_filtered(ii, current_day.unwrap() as usize, options);
+ if filtered {
+ dayset[daycounter] = None;
+ }
+ }
+ filtered
+}
+
+pub fn build_timeset(options: &ParsedOptions) -> Vec<Time> {
+ let millisecond_mod = (options.dtstart.timestamp_millis() & 1000) as usize;
+
+ if !(options.freq == Frequenzy::DAILY
+ || options.freq == Frequenzy::MONTHLY
+ || options.freq == Frequenzy::WEEKLY
+ || options.freq == Frequenzy::YEARLY)
+ {
+ return vec![];
+ }
+
+ let mut timeset = vec![];
+ for hour in &options.byhour {
+ for minute in &options.byminute {
+ for second in &options.bysecond {
+ timeset.push(Time::new(*hour, *minute, *second, millisecond_mod));
+ }
+ }
+ }
+
+ timeset
+}
+
+pub fn make_timeset(
+ ii: &IterInfo,
+ counter_date: &DateTime<Utc>,
+ options: &ParsedOptions,
+) -> Vec<Time> {
+ if options.freq == Frequenzy::DAILY
+ || options.freq == Frequenzy::MONTHLY
+ || options.freq == Frequenzy::WEEKLY
+ || options.freq == Frequenzy::YEARLY
+ {
+ return build_timeset(options);
+ }
+
+ if (options.freq >= Frequenzy::HOURLY
+ && options.byhour.len() > 0
+ && !options
+ .byhour
+ .iter()
+ .any(|&h| h == counter_date.hour() as usize))
+ || (options.freq >= Frequenzy::MINUTELY
+ && options.byminute.len() > 0
+ && !options
+ .byminute
+ .iter()
+ .any(|&m| m == counter_date.minute() as usize))
+ || (options.freq >= Frequenzy::SECONDLY
+ && options.bysecond.len() > 0
+ && !options
+ .bysecond
+ .iter()
+ .any(|&s| s == counter_date.second() as usize))
+ {
+ return vec![];
+ }
+
+ return ii.gettimeset(
+ &options.freq,
+ counter_date.hour() as usize,
+ counter_date.minute() as usize,
+ counter_date.second() as usize,
+ counter_date.timestamp_subsec_millis() as usize,
+ );
+}
diff --git a/src/iterinfo.rs b/src/iterinfo.rs
index 87737b1..bfd1421 100644
--- a/src/iterinfo.rs
+++ b/src/iterinfo.rs
@@ -206,7 +206,7 @@ impl<'a> IterInfo<'a> {
pub fn getdayset(
&self,
- freq: Frequenzy,
+ freq: &Frequenzy,
year: isize,
month: usize,
day: usize,
@@ -222,7 +222,7 @@ impl<'a> IterInfo<'a> {
pub fn gettimeset(
&self,
- freq: Frequenzy,
+ freq: &Frequenzy,
hour: usize,
minute: usize,
second: usize,
diff --git a/src/poslist.rs b/src/poslist.rs
index d25419a..e962e0c 100644
--- a/src/poslist.rs
+++ b/src/poslist.rs
@@ -1,3 +1,4 @@
+use crate::datetime::*;
use crate::iterinfo::*;
use crate::yearinfo::*;
use chrono::prelude::*;
@@ -9,13 +10,13 @@ pub fn from_ordinal(ordinal: isize) -> DateTime<Utc> {
DateTime::from_utc(naive, Utc)
}
-pub fn buildPoslist(
- bysetpost: Vec<isize>,
- timeset: Vec<DateTime<Utc>>,
+pub fn build_poslist(
+ bysetpost: &Vec<usize>,
+ timeset: &Vec<Time>,
start: usize,
end: usize,
- ii: IterInfo,
- dayset: Vec<Option<isize>>,
+ ii: &IterInfo,
+ dayset: &Vec<Option<isize>>,
) -> Vec<DateTime<Utc>> {
let mut poslist: Vec<DateTime<Utc>> = vec![];
@@ -24,10 +25,10 @@ pub fn buildPoslist(
let timepos;
let pos = bysetpost[j];
if pos < 0 {
- daypos = pos / timeset.len() as isize;
+ daypos = pos / timeset.len();
timepos = pymod(pos as isize, timeset.len() as isize);
} else {
- daypos = (pos - 1) / timeset.len() as isize;
+ daypos = (pos - 1) / timeset.len();
timepos = pymod(pos as isize - 1, timeset.len() as isize);
}
@@ -41,19 +42,18 @@ pub fn buildPoslist(
let i;
if daypos < 0 {
- let index = (tmp.len() as isize - daypos) as usize;
+ let index = (tmp.len() - daypos) as usize;
i = &tmp[index];
} else {
i = &tmp[daypos as usize];
}
- let time = timeset[timepos as usize];
let date = from_ordinal(ii.yearordinal().unwrap() + i);
// const res = dateutil.combine(date, time)
let res = Utc.ymd(date.year(), date.month(), date.day()).and_hms(
- time.hour(),
- time.minute(),
- time.second(),
+ timeset[timepos as usize].hour as u32,
+ timeset[timepos as usize].minute as u32,
+ timeset[timepos as usize].second as u32,
);
// XXX: can this ever be in the array?
// - compare the actual date instead?
diff --git a/src/yearinfo.rs b/src/yearinfo.rs
index 0628485..c41f66c 100644
--- a/src/yearinfo.rs
+++ b/src/yearinfo.rs
@@ -16,15 +16,15 @@ pub struct YearInfo {
pub wnomask: Option<Vec<usize>>,
}
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, PartialOrd)]
pub enum Frequenzy {
- YEARLY,
- MONTHLY,
- WEEKLY,
- DAILY,
- HOURLY,
- MINUTELY,
- SECONDLY,
+ YEARLY = 0,
+ MONTHLY = 1,
+ WEEKLY = 2,
+ DAILY = 3,
+ HOURLY = 4,
+ MINUTELY = 5,
+ SECONDLY = 6,
}
#[derive(Debug)]