diff options
author | Fredrik Meringdal <fmeringdal@hotmail.com> | 2020-10-25 23:00:50 +0100 |
---|---|---|
committer | Fredrik Meringdal <fmeringdal@hotmail.com> | 2020-10-25 23:00:50 +0100 |
commit | dc44e5f2312bbb8ac411b9dc0b3b52eb3b351b6c (patch) | |
tree | ee75b9aeac7c4b18d21b5dd0cb37e9c2098cfc54 /src/iter/yearinfo.rs | |
parent | 55db5800701e9965b19ede01266442b11956b54b (diff) | |
download | rust_rrule-dc44e5f2312bbb8ac411b9dc0b3b52eb3b351b6c.zip |
restructure files
Diffstat (limited to 'src/iter/yearinfo.rs')
-rw-r--r-- | src/iter/yearinfo.rs | 217 |
1 files changed, 217 insertions, 0 deletions
diff --git a/src/iter/yearinfo.rs b/src/iter/yearinfo.rs new file mode 100644 index 0000000..8a944f7 --- /dev/null +++ b/src/iter/yearinfo.rs @@ -0,0 +1,217 @@ +use crate::masks::MASKS; +use crate::options::*; +use chrono::prelude::*; +use crate::datetime::to_ordinal; + + +#[derive(Debug)] +pub struct YearInfo { + pub yearlen: usize, + pub nextyearlen: usize, + pub yearordinal: isize, + pub yearweekday: usize, + pub mmask: Vec<usize>, + pub mrange: Vec<usize>, + pub mdaymask: Vec<isize>, + pub nmdaymask: Vec<isize>, + pub wdaymask: Vec<usize>, + pub wnomask: Option<Vec<usize>>, +} + +fn is_leap_year(year: i32) -> bool { + year % 4 == 0 && (year % 100 != 0 || year % 400 == 0) +} + +fn get_year_len(year: i32) -> usize { + if is_leap_year(year) { + return 366; + } + 365 +} + +pub fn get_weekday_val(wk: &Weekday) -> usize { + match wk { + Weekday::Mon => 0, + Weekday::Tue => 1, + Weekday::Wed => 2, + Weekday::Thu => 3, + Weekday::Fri => 4, + Weekday::Sat => 5, + Weekday::Sun => 6, + } +} + +pub struct BaseMasks { + mmask: Vec<usize>, + mdaymask: Vec<isize>, + nmdaymask: Vec<isize>, + wdaymask: Vec<usize>, + mrange: Vec<usize>, +} + +fn base_year_masks(year: i32) -> BaseMasks { + let masks = MASKS.clone(); + let firstyday = Utc.ymd(year, 1, 1).and_hms_milli(0, 0, 0, 0); + let yearlen = get_year_len(year); + let wday = get_weekday_val(&firstyday.weekday()) as usize; + + if yearlen == 365 { + return BaseMasks { + mmask: masks.m365, + mdaymask: masks.mday365, + nmdaymask: masks.nmday365, + mrange: masks.m365range, + wdaymask: Vec::from(&masks.wday[wday..]), + }; + } + + BaseMasks { + mmask: masks.m366, + mdaymask: masks.mday366, + nmdaymask: masks.nmday366, + mrange: masks.m366range, + wdaymask: Vec::from(&masks.wday[wday..]), + } +} + +pub fn pymod(a: isize, b: isize) -> isize { + let r = a % b; + // If r and b differ in sign, add b to wrap the result to the correct sign. + if (r > 0 && b < 0) || (r < 0 && b > 0) { + return r + b; + } + r +} + +pub fn rebuild_year(year: i32, options: &ParsedOptions) -> YearInfo { + let firstyday = Utc.ymd(year, 1, 1).and_hms_milli(0, 0, 0, 0); + + let yearlen = get_year_len(year); + let nextyearlen = get_year_len(year + 1); + let yearordinal = to_ordinal(&firstyday); + let yearweekday = get_weekday_val(&firstyday.weekday()); + + let base_masks = base_year_masks(year); + + let mut result = YearInfo { + yearlen, + nextyearlen, + yearordinal, + yearweekday, + wnomask: None, + mmask: base_masks.mmask, + mdaymask: base_masks.mdaymask, + nmdaymask: base_masks.nmdaymask, + mrange: base_masks.mrange, + wdaymask: base_masks.wdaymask, + }; + + if options.byweekno.is_empty() { + return result; + } + + let mut wnomask = vec![0; yearlen + 7]; + let wyearlen; + let mut no1wkst = pymod((7 - yearweekday + options.wkst) as isize, 7); + let firstwkst = no1wkst; + if no1wkst >= 4 { + no1wkst = 0; + // Number of days in the year, plus the days we got + // from last year. + wyearlen = result.yearlen as isize + pymod(yearweekday as isize - options.wkst as isize, 7); + } else { + // Number of days in the year, minus the days we + // left in last year. + wyearlen = yearlen as isize - no1wkst; + } + + let div = (wyearlen as f32 / 7.).floor() as isize; + let year_mod = pymod(wyearlen, 7); + //const numweeks = Math.floor(div + mod / 4) + let numweeks = div + (year_mod / 4); + + for j in 0..options.byweekno.len() { + let mut n = options.byweekno[j]; + if n < 0 { + n += (numweeks + 1) as isize; + } + if !(n > 0 && n <= numweeks) { + continue; + } + let mut i; + if n > 1 { + i = no1wkst + (n - 1) * 7; + if no1wkst != firstwkst { + i -= 7 - firstwkst; + } + } else { + i = no1wkst; + } + + for _ in 0..7 { + wnomask[i as usize] = 1; + i += 1; + if result.wdaymask[i as usize] as usize == options.wkst { + break; + } + } + } + + if options.byweekno.iter().any(|&wkno| wkno == 1) { + // Check week number 1 of next year as well + // orig-TODO : Check -numweeks for next year. + let mut i = no1wkst + numweeks * 7; + if no1wkst != firstwkst { + i -= 7 - firstwkst; + } + if i < yearlen as isize { + // If week starts in next year, we + // don't care about it. + for _ in 0..7 { + wnomask[i as usize] = 1; + i += 1; + if result.wdaymask[i as usize] as usize == options.wkst { + break; + } + } + } + } + + if no1wkst > 0 { + // Check last week number of last year as + // well. If no1wkst is 0, either the year + // started on week start, or week number 1 + // got days from last year, so there are no + // days from last year's last week number in + // this year. + let lnumweeks; + if !options.byweekno.iter().any(|&weekno| weekno == -1) { + let lyearweekday = get_weekday_val(&Utc.ymd(year - 1, 1, 1).weekday()); + + let lno1wkst = pymod((7 - lyearweekday + options.wkst) as isize, 7); + + let lyearlen = get_year_len(year - 1); + let weekst; + if lno1wkst >= 4 { + //lno1wkst = 0; + weekst = lyearlen as isize + pymod((lyearweekday - options.wkst) as isize, 7); + } else { + weekst = yearlen as isize - no1wkst; + } + + lnumweeks = 52 + (pymod(weekst, 7) / 4) as isize; + } else { + lnumweeks = -1 as isize; + } + + if options.byweekno.iter().any(|&weekno| weekno == lnumweeks) { + for i in 0..no1wkst { + wnomask[i as usize] = 1; + } + } + } + + result.wnomask = Some(wnomask); + + result +} |